This commit is contained in:
2022-09-08 18:41:47 +02:00
parent 2143f9887e
commit 4bb1f17467
16 changed files with 350 additions and 5281 deletions

View File

@ -45,4 +45,9 @@ export default class Vector2D {
parseFloat(this.y.toFixed(nDecimal))
)
}
public set(x: number, y: number) {
this.x = x
this.y = y
}
}

View File

@ -10,10 +10,21 @@ export interface ComponentState {
isColliding?: string
}
export type StaticComponent<
// eslint-disable-next-line @typescript-eslint/ban-types
T extends {} | void = {} | void
> =
new (params: T | undefined) => Component2D<T>
/**
* 2D Component
*/
export default abstract class Component2D {
export default abstract class Component2D<
// eslint-disable-next-line @typescript-eslint/ban-types
T extends {} | void = {} | void
> {
public params: T = {} as T
/**
* Indicate how the component is rendered
@ -75,6 +86,12 @@ export default abstract class Component2D {
*/
public debug?: boolean
public constructor(it: T | void) {
if (it) {
this.params = it
}
}
/**
* Function run when the component is initialized
*/

View File

@ -1,25 +1,57 @@
import GameEngine from 'GameEngine'
import ComponentDebug from 'GameEngine/2D/Debug/ComponentDebug'
import Vector2D from 'GameEngine/2D/Vector2D'
import Component2D from 'GameEngine/Component2D'
import Renderer from 'GameEngine/Renderer'
import TextRenderer from 'GameEngine/Renderer/TextRenderer'
export default class FPSCounter extends Component2D {
export default class FPSCounter extends Component2D<{textColor?: string, size?: number}> {
public position: Vector2D = new Vector2D(0,0)
public position: Vector2D = new Vector2D(10,8)
public scale: Vector2D = new Vector2D(1, 1)
public origin: Vector2D = new Vector2D(0, 0)
public childs: Array<Component2D> = [new ComponentDebug(this)]
public renderer: TextRenderer = new TextRenderer(this, {text: 'pouet'})
public renderer: TextRenderer = new TextRenderer(this, {text: 'loading...'})
private lastUpdate: number = new Date().getTime()
private length = 1
private previousFrameTimes: Array<number> = []
private lastUpdate = window.performance.now() * 1000
public init() {
const fps = GameEngine.getGameEngine().options?.goalFramerate
if (!fps || fps < 1) {
this.length = 60
} else {
this.length = fps
}
if (this.params.textColor) {
this.renderer.color = this.params.textColor
}
if (this.params.size) {
this.renderer.size = this.params.size
}
}
public update() {
const now = new Date().getTime()
this.renderer.text = (1000 / (now - this.lastUpdate)).toFixed(2)
this.lastUpdate = now
const t = GameEngine.getGameEngine().lastFrame
// if (!t) {return}
// console.log(this.previousFrameTimes, t)
const diff = t - this.lastUpdate
this.lastUpdate = t
this.previousFrameTimes.push(diff)
if (this.previousFrameTimes.length > this.length) {
this.previousFrameTimes.shift()
}
const time = (this.previousFrameTimes.reduce((p, c) => p + c, 0)) / this.previousFrameTimes.length
if (time === 0) {
this.renderer.text = 'a lot'
} else {
this.renderer.text = (1000 / time).toFixed(2)
}
}
}

View File

@ -29,17 +29,14 @@ export default class Scene {
}
public async init() {
this.components.forEach((v) => {
if (v.init) {
v.init()
}
})
for await (const component of this.components) {
await component.init?.()
}
}
public async update() {
for (let index = 0; index < this.components.length; index++) {
const component = this.components[index];
await this.updateComponent(component, index)
await this.updateComponent(this.components[index], index)
}
}
@ -99,8 +96,8 @@ export default class Scene {
if (debug) {
console.log('Processing childs', v)
}
for await (const child of v.childs) {
await this.updateComponent(child)
for (let cIndex = 0; cIndex < v.childs.length; cIndex++) {
await this.updateComponent(v.childs[cIndex], cIndex)
}
}
}

View File

@ -22,8 +22,23 @@ export default class GameEngine {
wasDown: false
}
public currentScene?: Scene
// last frame timestamp
public lastFrame = 0
/**
* last frame execution time in milliseconds
*
* @memberof GameEngine
*/
public frameTime = 0
private isRunning = false
private timer = 16.6
// timer between frames
private timer = 0
public constructor(
id: string,
@ -61,12 +76,8 @@ export default class GameEngine {
ctx.imageSmoothingEnabled = false
this.ctx = ctx
if (options?.goalFramerate) {
if (options.goalFramerate === -1) {
this.timer = 0
} else {
this.timer = 1000 / options.goalFramerate
}
if (options?.goalFramerate && options.goalFramerate >= 0) {
this.timer = 1000 / options.goalFramerate
}
}
@ -80,13 +91,11 @@ export default class GameEngine {
return
}
this.isRunning = true
requestAnimationFrame(() => {
this.update()
})
this.currentScene?.init().then(() => this.update())
document.addEventListener('mousemove', (ev) => {
this.cursor.position = new Vector2D(
ev.clientX / this.caseSize.x - (this.currentScene?.camera?.topLeft?.x ?? 0),
ev.clientY / this.caseSize.y - (this.currentScene?.camera?.topLeft?.y ?? 0)
(ev.clientX + window.scrollX) / this.caseSize.x - (this.currentScene?.camera?.topLeft?.x ?? 0),
(ev.clientY + window.scrollY) / this.caseSize.y - (this.currentScene?.camera?.topLeft?.y ?? 0)
)
if (this.cursor.isDown) {
this.cursor.wasDown = true
@ -109,35 +118,66 @@ export default class GameEngine {
public async setScene(scene: Scene | string) {
console.log('Setting scene', typeof scene === 'string' ? scene : scene.id)
const wasRunning = this.isRunning
if (wasRunning) {
this.isRunning = false
}
await this.currentScene?.destroy()
await this.currentScene?.init()
if (wasRunning) {
this.isRunning = true
}
this.currentScene = typeof scene === 'string' ? Scene.scenes[scene] : scene
this.currentScene.setGameEngine(this)
}
private update() {
const now = new Date().getTime()
if (!this.isRunning) {
return
}
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
if (this.options?.background) {
this.ctx.fillStyle = this.options.background
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
}
this.currentScene?.update()
const diff = new Date().getTime() - now
if (diff > this.timer) {
requestAnimationFrame(() => {
this.update()
})
} else {
setTimeout(() => {
// this.update()
requestAnimationFrame(() => {
this.update()
})
}, this.timer - diff)
}
private async update() {
// console.log('update')
let frameFinished = true
setInterval((it) => {
// get current time
const now = window.performance.now()
// game is not runnig, wait a frame
if (!this.isRunning || !frameFinished) {
// console.log('skip frame')
// setTimeout(() => {
// this.update()
// }, this.timer)
return
}
// game is running too fast, wait until necessary
if (this.lastFrame + this.timer > now ) {
// console.log('skip frame')
// setTimeout(() => {
// this.update()
// }, (this.lastFrame + this.timer) - now)
return
}
// console.log('new frame')
frameFinished = false
// if a background need to be drawn
if (this.options?.background) {
this.ctx.fillStyle = this.options.background
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
} else {
// clear the previous frame
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
}
// update scene
this.currentScene?.update()
// calculate for next frame
this.lastFrame = window.performance.now()
this.frameTime = window.performance.now() - now
frameFinished = true
// this.update()
// requestAnimationFrame(() => {
// })
})
}
}