Skip to content

Commit

Permalink
Merge pull request #19 from ineka-dev/refactor/engine-loop
Browse files Browse the repository at this point in the history
Refactor/engine loop
  • Loading branch information
ColinEspinas authored Aug 29, 2024
2 parents 0011e7b + fd47614 commit 9da26cb
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 113 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-steaks-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ineka/engine": minor
---

Changed engine loop and time management class to improve developer experience.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
],
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "rollup -cw",
"dev": "rollup -w --config rollup.config.ts --configPlugin typescript",
"build": "rollup --config rollup.config.ts --configPlugin typescript --environment NODE_ENV:production",
"docs:generate": "typedoc",
"docs:serve": "serve docs",
Expand Down
34 changes: 20 additions & 14 deletions src/core/Engine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { EngineOptions } from '../options/EngineOptions'
import type { EngineOptions } from '../types/options'
import { EngineError } from '../errors/EngineError'
import type { OuterNode } from './OuterNode'
import type { TreeNode } from './TreeNode'
import { Time } from './Time'
Expand All @@ -12,13 +13,9 @@ export class Engine {
*/
private _options: EngineOptions
/**
* Engine container element.
* Engine DOM container element.
*/
private _container: HTMLElement
/**
* Root node of the engine's graph.
*/
public rootNode: TreeNode
/**
* Engine's attached systems.
*/
Expand All @@ -27,6 +24,10 @@ export class Engine {
* Engine's time utility.
*/
private _time: Time = new Time()
/**
* Root node of the engine's graph.
*/
public rootNode: TreeNode | undefined

/**
* Get engine's options.
Expand Down Expand Up @@ -64,7 +65,7 @@ export class Engine {
framerate: null,
...options,
}
this._container = document.querySelector(this._options.container)
this._container = document.querySelector(this._options.container as string) as HTMLElement
this.init()
}

Expand All @@ -79,7 +80,7 @@ export class Engine {
public run(): void {
// Check if root node exists before loading.
if (!this.rootNode) {
throw new Error('No root node given to engine, cannot run.')
throw new EngineError(this, 'ENGINE:FAILURE', 'No root node given to engine, cannot run.')
}
// Load systems.
this.systems.forEach((system) => {
Expand All @@ -97,21 +98,26 @@ export class Engine {
* to fix the timestep for fixed update loops (useful for physics and user interactions).
*/
protected step(now: number): void {
if (!this.rootNode) {
throw new EngineError(this, 'ENGINE:FAILURE', 'No root node given to engine, cannot run.')
}
// Update delta and last frame time
this.time.updateDelta(now)
this.time.updateLast()
this.time.update(now)
// Fix timestep of fixedStep methods
this.time.fixTimestep(() => {
if (!this.rootNode) {
throw new EngineError(this, 'ENGINE:FAILURE', 'No root node given to engine, cannot run.')
}
this.systems.forEach((system) => {
Promise.resolve().then(() => system.fixedStep())
system.fixedStep()
})
Promise.resolve().then(() => this.rootNode.fixedStep())
this.rootNode.fixedStep()
})
// Do non fixed steps
this.systems.forEach((system) => {
system.step()
system.step(this.time.delta)
})
this.rootNode.step()
this.rootNode.step(this.time.delta)
// Request next step
requestAnimationFrame(this.step.bind(this))
}
Expand Down
42 changes: 23 additions & 19 deletions src/core/InnerNode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EngineError } from '../errors/EngineError'
import type { Engine } from './Engine'
import { TreeNode } from './TreeNode'

Expand All @@ -13,14 +14,14 @@ export class InnerNode extends TreeNode {
/**
* Node's children nodes.
*/
protected children: TreeNode[]
protected _children: TreeNode[]

/**
* Setup children and calls onCreate method.
*/
constructor(parent: TreeNode | Engine) {
super(parent)
this.children = []
this._children = []
this.onCreate()
}

Expand All @@ -31,11 +32,11 @@ export class InnerNode extends TreeNode {
* @sealed
*/
public add(node: TreeNode): number {
this.children.push(node)
this._children.push(node)
// Load the added node if added after loading.
if (this.isLoaded)
if (this._isLoaded)
node.load()
return this.children.length
return this._children.length
}

/**
Expand All @@ -46,7 +47,7 @@ export class InnerNode extends TreeNode {
*/
public remove(node: TreeNode): TreeNode {
let removedNode
this.children = this.children.filter((n: TreeNode) => {
this._children = this._children.filter((n: TreeNode) => {
// Unloads and filters the given node out.
if (n.id === node.id) {
removedNode = n
Expand All @@ -55,6 +56,8 @@ export class InnerNode extends TreeNode {
}
return true
})
if (!removedNode)
throw new EngineError(this._engine, 'NODE:FAILURE', 'The node you tried to remove is not a child of this node.')
return removedNode
}

Expand All @@ -67,10 +70,10 @@ export class InnerNode extends TreeNode {
*/
public load(): void {
this.onLoad()
for (let i = 0, len = this.children.length; i !== len; ++i) {
this.children[i].load()
for (let i = 0, len = this._children.length; i !== len; ++i) {
this._children[i].load()
}
this.isLoaded = true
this._isLoaded = true
}

/**
Expand All @@ -80,10 +83,10 @@ export class InnerNode extends TreeNode {
* Calls the `onStep` method and children's `step` methods.
* @sealed
*/
public step(): void {
this.onStep()
for (let i = 0, len = this.children.length; i !== len; ++i) {
this.children[i].step()
public step(delta: number): void {
this.onStep(delta)
for (let i = 0, len = this._children.length; i !== len; ++i) {
this._children[i].step(delta)
}
}

Expand All @@ -96,8 +99,8 @@ export class InnerNode extends TreeNode {
*/
public fixedStep(): void {
this.onFixedStep()
for (let i = 0, len = this.children.length; i !== len; ++i) {
this.children[i].fixedStep()
for (let i = 0, len = this._children.length; i !== len; ++i) {
this._children[i].fixedStep()
}
}

Expand All @@ -110,10 +113,10 @@ export class InnerNode extends TreeNode {
*/
public unload(): void {
this.onUnload()
for (let i = 0, len = this.children.length; i !== len; ++i) {
this.children[i].unload()
for (let i = 0, len = this._children.length; i !== len; ++i) {
this._children[i].unload()
}
this.isLoaded = false
this._isLoaded = false
}

/**
Expand All @@ -138,7 +141,8 @@ export class InnerNode extends TreeNode {
* this function is to be implemented when needed.
* @virtual
*/
protected onStep(): void { }
// eslint-disable-next-line unused-imports/no-unused-vars
protected onStep(delta: number): void { }

/**
* Called by the parent node at each fixed step of the loop,
Expand Down
16 changes: 9 additions & 7 deletions src/core/OuterNode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EngineError } from '../errors/EngineError'
import type { Engine } from './Engine'
import { TreeNode } from './TreeNode'

Expand All @@ -21,7 +22,7 @@ export class OuterNode extends TreeNode {
* @sealed
*/
public add(): number {
throw new Error('You tried to add a child to an outer node. Outer nodes cannot have children.')
throw new EngineError(this._engine, 'NODE:FAILURE', 'You tried to add a child to an outer node. Outer nodes cannot have children.')
}

/**
Expand All @@ -30,7 +31,7 @@ export class OuterNode extends TreeNode {
* @sealed
*/
public remove(): TreeNode {
throw new Error('You tried to remove a child to an outer node. Outer nodes cannot have children.')
throw new EngineError(this._engine, 'NODE:FAILURE', 'You tried to remove a child to an outer node. Outer nodes cannot have children.')
}

/**
Expand All @@ -42,7 +43,7 @@ export class OuterNode extends TreeNode {
*/
public load(): void {
this.onLoad()
this.isLoaded = true
this._isLoaded = true
}

/**
Expand All @@ -52,8 +53,8 @@ export class OuterNode extends TreeNode {
* Calls the `onStep` method.
* @sealed
*/
public step(): void {
this.onStep()
public step(delta: number): void {
this.onStep(delta)
}

/**
Expand All @@ -76,7 +77,7 @@ export class OuterNode extends TreeNode {
*/
public unload(): void {
this.onUnload()
this.isLoaded = false
this._isLoaded = false
}

/**
Expand All @@ -101,7 +102,8 @@ export class OuterNode extends TreeNode {
* this method is to be implemented when needed.
* @virtual
*/
protected onStep(): void { }
// eslint-disable-next-line unused-imports/no-unused-vars
protected onStep(delta: number): void { }

/**
* Called by the parent node at each fixed step of the loop,
Expand Down
Loading

0 comments on commit 9da26cb

Please sign in to comment.