diff --git a/examples/ts_game/resources/anonymous_pro_bold.ttf b/examples/ts_game/resources/anonymous_pro_bold.ttf new file mode 100644 index 0000000..badb0aa Binary files /dev/null and b/examples/ts_game/resources/anonymous_pro_bold.ttf differ diff --git a/examples/ts_game/src/entity.ts b/examples/ts_game/src/entity.ts index fd2c961..b41bb64 100644 --- a/examples/ts_game/src/entity.ts +++ b/examples/ts_game/src/entity.ts @@ -1,19 +1,19 @@ -export interface HasIdentity { +export interface HasIdentity { id: number } export interface Drawable { - draw: (entity: T) => void + draw: (entity: T) => void } export interface Updatable { - update: (entity: T) => void + update: (entity: T) => void } export interface HasResources { - load: (entity: T) => void - unload: (entity: T) => void + load: (entity: T) => void + unload: (entity: T) => void } export interface HasPosition { @@ -24,7 +24,7 @@ export interface HasColor { color: Color } -export type EntityOf = HasIdentity & Partial> & Partial> & Partial> & T +export type EntityOf = HasIdentity & Partial>> & Partial>> & Partial>> & T let ID = 0 export const makeEntity = () => ({ @@ -32,13 +32,16 @@ export const makeEntity = () => ({ }) export const makePosition = (x = 0, y = 0) => ({ - position: new Vector2(x,y) + position: new Vector2(x, y) }) export const makeColorRgb = (r = 255, g = 255, b = 255, a = 255) => ({ - color: new Color(r,g,b,a) + color: new Color(r, g, b, a) }) export const makeColorClone = (c = WHITE) => ({ - color: new Color(c.r,c.g,c.b,c.a) + color: new Color(c.r, c.g, c.b, c.a) }) + + + diff --git a/examples/ts_game/src/game.ts b/examples/ts_game/src/game.ts index 28a9d17..5ffcf81 100644 --- a/examples/ts_game/src/game.ts +++ b/examples/ts_game/src/game.ts @@ -1,4 +1,9 @@ +import { EntityOf } from "./entity"; +import { resourceUnloadAll } from "./resource"; + const promiseUpdateList: (()=>boolean)[] = [] +const entitiyList: EntityOf[] = [] + const dispatchPromises = () => { for (var i = promiseUpdateList.length - 1; i >= 0; i--) { @@ -23,34 +28,37 @@ export const makeUpdateablePromise = (updateFn: () => boolean) => { return promise } +export const entityAdd = (entity: EntityOf) => { + if (entity.load) entity.load(entity) + entitiyList.push(entity) +} -export abstract class Game { - public clearColor = BLACK - private quit = false - - constructor(public readonly width: number, - public readonly height: number, - public readonly title: string){ +export const entityRemove = (entity: EntityOf) => { + // TODO: Do this cached + const i = entitiyList.findIndex(x => x.id === entity.id) + if (i !== -1) { + const e = entitiyList[i] + if (e.unload) e.unload(entity) + entitiyList.splice(i, 1) } +} - public run(){ - initWindow(this.width,this.height,this.title) - setTargetFPS(60) - this.load() - while(!(this.quit = windowShouldClose())){ - dispatchPromises() - this.update() - beginDrawing() - clearBackground(this.clearColor) - this.draw() - endDrawing() +export const runGame = (width: number, height: number, title: string, startupCallback: () => void) => { + initWindow(width, height, title) + setTargetFPS(60) + startupCallback() + while(!windowShouldClose()){ + dispatchPromises() + for (const entity of entitiyList) { + if (entity.update) entity.update(entity) } - this.unload() - closeWindow() + beginDrawing() + clearBackground(BLACK) + for (const entity of entitiyList) { + if (entity.draw) entity.draw(entity) + } + endDrawing() } - - abstract draw(): void; - abstract update(): void; - abstract load(): void; - abstract unload(): void; + resourceUnloadAll() + closeWindow() } \ No newline at end of file diff --git a/examples/ts_game/src/index.ts b/examples/ts_game/src/index.ts index e756342..a39ac53 100644 --- a/examples/ts_game/src/index.ts +++ b/examples/ts_game/src/index.ts @@ -1,47 +1,23 @@ import { fadeIn, fadeOut, wait } from "./animation"; -import { EntityOf } from "./entity"; -import { Game, makeUpdateablePromise } from "./game"; +import { entityAdd, entityRemove, runGame } from "./game"; import { TextEntity, makeTextEntity } from "./text"; -class MyGame extends Game { - entities: EntityOf[] = [] - - draw(): void { - for (const entity of this.entities) { - if(entity.draw) entity.draw(entity) - } - } - update(): void { - for (const entity of this.entities) { - if(entity.update) entity.update(entity) - } - } - load(): void { - } - unload(): void { - } - - addEntity(entity: EntityOf){ - this.entities.push(entity) - } -} - -const game = new MyGame(800,450,"Typescript Game") - -const main = async () => { +runGame(800,400, "Typescript Game", async () => { const text = { ...makeTextEntity("Welcome to rayjs!"), size: 80, - position: new Vector2(100, game.height/2 - 40) + position: new Vector2(100, getScreenHeight()/2 - 40), + font: 'resources/anonymous_pro_bold.ttf' } - game.addEntity(text) - await fadeIn(text, 2) - await wait(2) - await fadeOut(text, 2) - text.position.x += 75 - text.text = "This Summer!" - await fadeIn(text, 2) -} - -main() -game.run() \ No newline at end of file + let quit = false + entityAdd(text) + while(!quit){ + await fadeIn(text, 2) + await wait(2) + await fadeOut(text, 2) + text.text = "This Summer!" + await fadeIn(text, 2) + await fadeOut(text, 3) + entityRemove(text) + } +}) diff --git a/examples/ts_game/src/resource.ts b/examples/ts_game/src/resource.ts new file mode 100644 index 0000000..8a82f81 --- /dev/null +++ b/examples/ts_game/src/resource.ts @@ -0,0 +1,47 @@ +type ResourceType = 'texture' | 'image' | 'shader' | 'font' + +const resourceList = new Map() + +interface Resource { + refcount: number, + id: string, + resource: any + unload: (t: any) => void +} + +function loadResourceFunc(loader: (filename: string) => T, unloader: (resource: T) => void){ + return (filename: string) => { + if(resourceList.has(filename)){ + const res = resourceList.get(filename) + res!.refcount++ + return res?.resource + } else { + traceLog(LOG_INFO, "here") + const resource = loader(filename) + traceLog(LOG_INFO, resource) + resourceList.set(filename, { + refcount: 1, + id: filename, + resource: resource, + unload: unloader + }) + return resource + } + } +} +export const resourceUnload = (id: string) => { + const res = resourceList.get(id) + if(res){ + res.refcount-- + if(res.refcount === 0){ + res.unload(res.resource) + } + } +} +export const resourceUnloadAll = () => { + for (const res of resourceList.entries()) { + res[1].unload(res[1].resource) + } +} +export const textureLoad = loadResourceFunc(loadTexture,unloadTexture) +export const fontLoad = loadResourceFunc(loadFont,unloadFont) \ No newline at end of file diff --git a/examples/ts_game/src/text.ts b/examples/ts_game/src/text.ts index a74ea6c..bc8522d 100644 --- a/examples/ts_game/src/text.ts +++ b/examples/ts_game/src/text.ts @@ -1,34 +1,41 @@ import { EntityOf, HasColor, HasPosition, makeColorRgb, makeEntity, makePosition } from "./entity" +import { fontLoad, resourceUnload } from "./resource" export interface Text extends HasPosition, HasColor { text: string, - font: Font, + font?: string, size: number, spacing: number } export interface TextEntity extends EntityOf { type: "text" + fontResource?: Font } -export const makeText = (text = "", size = 20, font = null, spacing = 1) => ({ +export const makeText = (text = "", size = 20, font: string | null = null, spacing = 1) => ({ ...makePosition(), ...makeColorRgb(), text: text, - font: font === null ? getFontDefault() : loadFont(font), + font: font, size: size, spacing: spacing }) -export const textDraw = (t: Text) => { - return drawTextEx(t.font, t.text, t.position, t.size, t.spacing, t.color); +export const textDrawFn = (t: TextEntity) => drawTextEx(t.fontResource!, t.text, t.position, t.size, t.spacing, t.color); +export const textLoadFn = (t: TextEntity) => { + t.fontResource = (t.font ? fontLoad(t.font) : getFontDefault()) + return } +export const textUnloadFn = (t: TextEntity) => t.font ? resourceUnload(t.font) : undefined export const makeTextEntity = (text: string = "") => ({ ...makeEntity(), ...makeText(text), type: "text", - draw: textDraw, + draw: textDrawFn, + load: textLoadFn, + unload: textUnloadFn })