Skip to content

Commit

Permalink
add a very basic console-only example of how to read add/remove entit…
Browse files Browse the repository at this point in the history
…y events. fixes #39
  • Loading branch information
mreinstein committed Feb 9, 2024
1 parent 97d878f commit b8bca6a
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
examples
devtools-extension
test
.github
119 changes: 119 additions & 0 deletions examples/events/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import ECS from 'ecs'


const WIDGET_QUERY = [ 'widget' ]

const constants = {
FIXED_STEP_MS: 16, // fixed steps run @ 62.5fps (16ms per frame)
}

const Global = {
world: undefined, // ECS instance

// timekeeping (in milliseconds)
lastFrameTime: 0, // time the last frame ran
accumulator: 0, // accumulate time to run ticks at a fixed rate

tick: 0, // total number of frames elapsed
}


async function main () {
// init
Global.world = ECS.createWorld()

// add all of the game's systems
ECS.addSystem(Global.world, widgetSpawnerSystem)
ECS.addSystem(Global.world, scoreSystem)

// start the simulation loop
simLoop()
}


function simLoop () {
const world = Global.world
const { FIXED_STEP_MS } = constants

const newTime = performance.now()
const frameTime = newTime - Global.lastFrameTime
Global.lastFrameTime = newTime

Global.accumulator += frameTime

// reset accumulator when > 2 seconds of time has elapsed since last step
// e.g., when the game window is restored after being hidden for a while
if (Global.accumulator > 2000)
Global.accumulator = 0

// run the game's physics and logic in fixed timesteps (great for physics stability and network determinism)
while (Global.accumulator >= FIXED_STEP_MS) {
Global.accumulator -= FIXED_STEP_MS

ECS.fixedUpdate(world, FIXED_STEP_MS)

ECS.cleanup(world)

Global.tick++
}

//requestAnimationFrame(simLoop)
setTimeout(simLoop, 1000 / 60)
}


main()



function createWidgetEntity (world) {
const w = ECS.createEntity(world)
ECS.addComponentToEntity(world, w, 'widget', {
frameTTL: 60, // after 60 frames this widget should be removed
})
}

// spawns new widgets entities

function widgetSpawnerSystem (world) {

const onFixedUpdate = function (dt) {
// spawn 1 widget per 60 ticks
if (Global.tick % 60 === 0)
createWidgetEntity(world, Global.tick)

// remove any widgets that have expired
for (const e of ECS.getEntities(world, WIDGET_QUERY)) {
if (e.widget.frameTTL === 0)
ECS.removeEntity(world, e)
else
e.widget.frameTTL--
}
}

return { onFixedUpdate }
}


// imagine a system that calculates score based on how many widgets were added/removed on a given frame
function scoreSystem (world) {

const result = {
count: 0,
entries: new Array(100),
}

const onFixedUpdate = function (dt) {
ECS.getEntities(world, WIDGET_QUERY, 'added', result)
if (result.count)
console.log('widgets added:', result.count)

ECS.getEntities(world, WIDGET_QUERY, 'removed', result)
if (result.count)
console.log('widgets removed:', result.count)

}

return { onFixedUpdate }
}

62 changes: 62 additions & 0 deletions examples/events/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title class="titleText"> ECS example - event handling </title>
<meta name="description" content="ECS example - event handling" />
<meta name="author" content="Michael Reinstein" />
<meta name="viewport" content="width=device-width" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />

<style>
* {
font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light',
'Helvetica Neue', Helvetica, Arial, 'Lucida Grande',
sans-serif;
font-weight: 300;
}

body {
background-color: #666;
padding: 0;
margin: 0;
transition: opacity 0.27s;
}

body, canvas, img {
image-rendering: pixelated;
}

canvas {
background-color: #333;
border: none;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: pixelated;
}

canvas::-webkit-scrollbar {
display: none;
}

</style>
</head>
<body>

<canvas> </canvas>

<script type="importmap">
{
"imports": {
"ecs": "../../ecs.js",
"remove-array-items": "https://cdn.skypack.dev/pin/[email protected]/mode=imports,min/optimized/remove-array-items.js"
}
}
</script>

<script type="module" src="./app.js"> </script>
</body>
</html>

0 comments on commit b8bca6a

Please sign in to comment.