rayjs/examples/ts_game/src/game.ts

135 lines
4.0 KiB
TypeScript
Raw Normal View History

2023-06-06 06:51:42 +00:00
import { withComponent } from "./entity";
import { hasDefault } from "./entity";
2023-05-29 22:03:29 +00:00
import { Behaviour, Entity, EntityOf } from "./entity";
import { forEachReverse } from "./helpers";
2023-05-27 13:03:29 +00:00
import { resourceUnloadAll } from "./resource";
2023-05-30 23:21:20 +00:00
const promiseUpdateList: PromiseContext<any>[] = []
2023-05-29 22:03:29 +00:00
const entitiyList: Entity[] = []
2023-05-27 13:03:29 +00:00
2023-05-27 09:35:08 +00:00
const dispatchPromises = () => {
for (var i = promiseUpdateList.length - 1; i >= 0; i--) {
2023-05-30 23:21:20 +00:00
const p = promiseUpdateList[i]
p.update()
if (p.isFinished) {
2023-05-27 09:35:08 +00:00
promiseUpdateList.splice(i, 1);
}
}
}
2023-05-30 23:21:20 +00:00
class PromiseContext<T> {
private _result: T | null = null;
public get result(): T | null {
return this._result;
}
private _error: any | null = null;
public get error(): any | null {
return this._error;
}
private _isFinished = false;
public get isFinished() {
return this._isFinished;
}
private _isCancellationRequested = false;
public get isCancellationRequested() {
return this._isCancellationRequested;
}
constructor(private readonly resolveFn: (val: T | PromiseLike<T>) => void,
private readonly rejectFn: (err: any) => void,
private readonly updateFn: (p: PromiseContext<T>) => void){}
update(){
if(!this.isFinished){
this.updateFn(this)
2023-05-29 22:03:29 +00:00
}
2023-05-27 09:35:08 +00:00
}
2023-05-30 23:21:20 +00:00
resolve(val: T){
this._result = val
this._isFinished = true
this.resolveFn(val)
}
reject(reason: any){
this._error = reason
this._isFinished = true
this.rejectFn(reason)
}
cancel(){
this._isCancellationRequested = true
}
}
export interface ExtendedPromise<T> extends Promise<T> {
context: PromiseContext<T>
}
export const makeUpdateablePromise = <T>(update: (ctx: PromiseContext<T>) => void) => {
let context: PromiseContext<T>
const promise = <ExtendedPromise<T>>new Promise<T>((resolve, reject) => {
context = new PromiseContext<T>(resolve,reject,update)
});
promise.context = context!
promiseUpdateList.unshift(context!)
2023-05-27 09:35:08 +00:00
return promise
}
2023-05-29 22:03:29 +00:00
export const entityAdd = (entity: Entity) => {
entity.behaviours.forEach(b => b.load ? b.load(entity) : undefined)
2023-05-27 13:03:29 +00:00
entitiyList.push(entity)
2023-05-29 22:03:29 +00:00
traceLog(LOG_INFO, `GAME: [ID ${entity.id}] loaded entity`)
}
export const entityUnload = (entity: Entity) => {
forEachReverse(entity.behaviours, (b, i) => b.unload ? b.unload(entity) : undefined);
traceLog(LOG_INFO, `GAME: [ID ${entity.id}] unloaded entity`)
2023-05-27 13:03:29 +00:00
}
2023-05-27 09:35:08 +00:00
2023-05-29 22:03:29 +00:00
export const entityRemove = (entity: Entity) => {
2023-05-27 13:03:29 +00:00
// TODO: Do this cached
const i = entitiyList.findIndex(x => x.id === entity.id)
if (i !== -1) {
2023-05-29 22:03:29 +00:00
entityUnload(entity)
2023-05-27 13:03:29 +00:00
entitiyList.splice(i, 1)
}
2023-05-27 13:03:29 +00:00
}
2023-06-06 06:51:42 +00:00
interface WindowConfig {
width: number,
height: number,
title: string,
flags: number
}
const withConfig = withComponent<WindowConfig>(x => {
hasDefault(x, 'width', 640)
hasDefault(x, 'height', 480)
hasDefault(x, 'title', "Rayjs")
hasDefault(x, 'flags', 0)
})
export const runGame = (options: Partial<WindowConfig>, startupCallback: (quit: () => void) => void | Promise<void>) => {
const config = withConfig(options)
setConfigFlags(config.flags)
initWindow(config.width,config.height,config.title)
2023-05-27 13:03:29 +00:00
setTargetFPS(60)
2023-05-29 22:03:29 +00:00
let quit = false
let exception: any = null
const p = startupCallback(() => quit = true)
if(p) p.catch(e => { exception = e })
2023-06-06 06:51:42 +00:00
while(!windowShouldClose() && !quit){
2023-05-27 13:03:29 +00:00
dispatchPromises()
2023-05-29 22:03:29 +00:00
if(exception) throw exception
entitiyList.forEach(e => e.behaviours.forEach(b => b.update ? b.update(e) : undefined))
2023-05-27 13:03:29 +00:00
beginDrawing()
clearBackground(BLACK)
2023-05-29 22:03:29 +00:00
drawText("Active promises: "+ promiseUpdateList.length, 10,10, 8, RAYWHITE)
entitiyList.forEach(e => e.behaviours.forEach(b => b.draw ? b.draw(e) : undefined))
2023-05-27 13:03:29 +00:00
endDrawing()
}
2023-05-29 22:03:29 +00:00
entitiyList.forEach(x => entityUnload(x))
entitiyList.splice(0,entitiyList.length)
2023-05-27 13:03:29 +00:00
resourceUnloadAll()
closeWindow()
}