From ba44a9a6c8b093bf7f5e1912627197da104f829f Mon Sep 17 00:00:00 2001 From: Phil Norton Date: Fri, 4 Apr 2025 22:32:20 +0100 Subject: [PATCH 1/2] 27: Added delta time to the core four.js file. --- four.js | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/four.js b/four.js index 293ee8c..e80aa8c 100644 --- a/four.js +++ b/four.js @@ -23,6 +23,11 @@ let score = 0; // The canvas context object. let ctx; +// Set up delta times. +let lastUpdate = Date.now(); +const updateLoopsPerSecond = 1000 / 60; +let delta = 0; + // Constants for detecting directions. const KEYPRESS_UP = 'up'; const KEYPRESS_DOWN = 'down'; @@ -153,10 +158,13 @@ function flashGrid(colour) { ctx.beginPath(); ctx.fillStyle = colour; ctx.fillRect(0, 0, canvas.width, canvas.height); - // After 50 milliseconds, clear the screen and re-draw the grid. + // After some milliseconds, clear the screen and re-draw the grid. + clearInterval(gameloopId); setTimeout(() => { cls(); - }, 50); + lastUpdate = Date.now(); + gameloopId = setInterval(gameLoop, updateLoopsPerSecond); + }, 250); } // Handle the canvas click event and pass onto a custom handle function @@ -186,11 +194,16 @@ function canvasClick(event) { return false; } -// Add event listener for `click` events. +// Add event listener for mouse click events. function addClickListener() { canvas.addEventListener('click', canvasClick, false); } +// Remove the event listener for mouse click events. +function removeClickListener() { + canvas.removeEventListener('click', canvasClick, false); +} + // Convert the keypress into directions and pass them upstream. function keyPress(event) { if (typeof userActionKeyPress !== 'function') { @@ -261,14 +274,16 @@ function randomElement() { return grid[randomX][randomY]; } -// Animate the score. +// Internal function used to animate the score. function animateScore() { cls(); if (frameCounter >= frames.length) { + // Finished animating. frames = []; flashGrid('black'); addKeyListener(); + addClickListener(); return; } @@ -289,6 +304,9 @@ function animateScore() { // Display the score in the game grid. function displayScore(passedScore) { removeKeyListener(); + removeClickListener(); + + // Function to find the colomn from the grid. const arrayColumn = (arr, n) => arr.map((x) => x[n]); // Convert score into a string and add start and end buffers. @@ -325,9 +343,14 @@ function displayScore(passedScore) { // The game loop, where we define our custom functions. function gameLoop() { + // Frames having length means that our animation is running. if (frames.length === 0) { - draw(); - update(); + let now = Date.now(); + delta = (now - lastUpdate) / 1000; + lastUpdate = now; + + draw(delta); + update(delta); } drawGrid(); @@ -336,7 +359,7 @@ function gameLoop() { // Initialise the canvas. function initCanvas(id) { canvas = document.getElementById(id); - + canvas.style.cursor = 'crosshair'; canvas.style.background = 'white'; canvas.style.border = '2px solid black'; @@ -358,13 +381,17 @@ function initCanvas(id) { init(); } - gameloopId = setInterval(gameLoop, 100); + gameloopId = setInterval(gameLoop, updateLoopsPerSecond); } // Pause the game loop for a number of seconds and restart it. function wait(seconds) { clearInterval(gameloopId); - gameloopId = setInterval(gameLoop, seconds); + + setTimeout(() => { + lastUpdate = Date.now(); + gameloopId = setInterval(gameLoop, updateLoopsPerSecond); + }, seconds); } // Get the canvas context object of the game grid. Used for testing. From fb7edd55514bbbf264ad3da50c56a9d5b5fc449e Mon Sep 17 00:00:00 2001 From: Phil Norton Date: Fri, 4 Apr 2025 22:34:32 +0100 Subject: [PATCH 2/2] 27: Updated docs and examples with relation to the delta time update. --- docs/demo/fort/fort.js | 42 ++++++++++++++++++++-------- docs/demo/forward/forward.js | 30 ++++++++++++++------ docs/demo/forward/index.html | 2 +- docs/demo/forx/forx.js | 18 ++++++------ docs/demo/fourdelance/fourdelance.js | 26 +++++++++-------- docs/demo/index.html | 2 +- docs/demo/test/test.js | 31 ++++++++++++-------- docs/docs/index.html | 24 ++++++++++++++-- 8 files changed, 120 insertions(+), 55 deletions(-) diff --git a/docs/demo/fort/fort.js b/docs/demo/fort/fort.js index 4c4e00a..cd7d844 100644 --- a/docs/demo/fort/fort.js +++ b/docs/demo/fort/fort.js @@ -3,6 +3,12 @@ let loose = false; let greenSpots = []; let redSpots = []; +const defaultDecayInterval = 60; +let decayInterval = defaultDecayInterval; + +const defaultPlaceInterval = 60; +let placeInterval = defaultDecayInterval; + function placeGreen() { if (greenSpots.length > score) { return; @@ -23,7 +29,7 @@ function placeGreen() { continue placeGreenLoop; } } - const randomHealth = randomRange(15, 50); + const randomHealth = randomRange(1, 15); greencoordinates = { column: random.column, row: random.row, health: randomHealth }; } greenSpots.push(greencoordinates); @@ -49,7 +55,7 @@ function placeRed() { continue placeRedLoop; } } - const randomHealth = randomRange(25, 50); + const randomHealth = randomRange(2, 20); redcoordinates = { column: random.column, row: random.row, health: randomHealth }; } redSpots.push(redcoordinates); @@ -90,7 +96,7 @@ function init() { placeRed(); } -function update() { +function update(delta) { if (loose === true) { // Crashed! // Flush the screen. @@ -103,6 +109,9 @@ function update() { greenSpots = []; redSpots = []; + decayInterval = defaultDecayInterval; + placeInterval = defaultPlaceInterval; + placeGreen(); placeRed(); @@ -111,18 +120,27 @@ function update() { return; } - // Randomly place a counter. - let actions = [ - placeGreen, - placeRed, - ]; - shuffle(actions); - actions[0](); + decayInterval -= (delta * 60); - decreaseHealth(); + if (decayInterval <= 0) { + decreaseHealth(); + decayInterval = Math.max(5, defaultDecayInterval - score); + } + + placeInterval -= (1 + delta); + if (placeInterval <= 0) { + // Randomly place a counter. + let actions = [ + placeGreen, + placeRed, + ]; + shuffle(actions); + actions[0](); + placeInterval = Math.max(5, defaultPlaceInterval - score); + } } -function draw() { +function draw(delta) { cls(); for (let i = 0; i < gridMaxX; i += 1) { for (let j = 0; j < gridMaxY; j += 1) { diff --git a/docs/demo/forward/forward.js b/docs/demo/forward/forward.js index 6c609ef..a431868 100644 --- a/docs/demo/forward/forward.js +++ b/docs/demo/forward/forward.js @@ -1,7 +1,8 @@ // Set up variables for the forward game. let loose = false; let playercoordinates = {}; -let wallTimeout; +const defaultMovementInterval = 60; +let moveInterval = defaultMovementInterval; const shapes = []; shapes[0] = [ @@ -34,7 +35,6 @@ let wall = []; let wallCoordinates; function moveWall() { - wallTimeout = setTimeout(moveWall, Math.max(1000 - (score * 100), 250)); if (wallIsActive) { if (wallCoordinates === -1) { wallIsActive = false; @@ -52,9 +52,6 @@ function moveWall() { function placePlayer() { playercoordinates = { column: 0, row: 2 }; - if (typeof wallTimeout !== 'number') { - wallTimeout = setTimeout(moveWall, 1000); - } } function userActionKeyPress(direction) { @@ -69,6 +66,9 @@ function userActionKeyPress(direction) { playercoordinates.row += 1; } break; + default: + // Do nothing. + break; } } @@ -76,7 +76,7 @@ function init() { placePlayer(); } -function update() { +function update(delta) { if (loose === true) { // Crashed! // Flush the screen. @@ -85,6 +85,12 @@ function update() { displayScore(score); // Reset some variables. score = 0; + moveInterval = defaultMovementInterval; + + wallIsActive = false; + wall = []; + wallCoordinates = 0; + // Set the game up again. placePlayer(); @@ -93,13 +99,21 @@ function update() { return; } + moveInterval -= (delta * 60); + + if (moveInterval <= 0) { + moveWall(); + moveInterval = Math.max(5, defaultMovementInterval - score); + } + + // Check loose state. for (let i = 0; i < gridMaxX; i += 1) { for (let j = 0; j < gridMaxY; j += 1) { const element = grid[i][j]; if (element.column === wallCoordinates) { for (let wallpart = 0; wallpart < wall.length; wallpart += 1) { if (wall[wallpart] === 1 && element.row === wallpart) { - if (element.column === playercoordinates.column + if (element.column === playercoordinates.column && element.row === playercoordinates.row) { loose = true; return; @@ -111,7 +125,7 @@ function update() { } } -function draw() { +function draw(delta) { cls(); for (let i = 0; i < gridMaxX; i += 1) { diff --git a/docs/demo/forward/index.html b/docs/demo/forward/index.html index f79af07..5edc38a 100644 --- a/docs/demo/forward/index.html +++ b/docs/demo/forward/index.html @@ -32,7 +32,7 @@

Four Demo: Forward

-

An implementation of flappy bird. Use the up and down arrows to move your box up and down and avoid the walls.

+

An implementation of flappy bird, without the gravity. Use the up and down arrows to move your box up and down and avoid the walls.