├── LICENSE ├── README.md └── gameLoop.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alex Bennett // timetocode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Edit: 2018 2 | ============== 3 | JavaScript timers have improved quite a bit since this repo was created in 2014. The following code can test this: 4 | ```js 5 | const hrtimeMs = function() { 6 | let time = process.hrtime() 7 | return time[0] * 1000 + time[1] / 1000000 8 | } 9 | 10 | const TICK_RATE = 20 11 | let tick = 0 12 | let previous = hrtimeMs() 13 | let tickLengthMs = 1000 / TICK_RATE 14 | 15 | const loop = () => { 16 | setTimeout(loop, tickLengthMs) 17 | let now = hrtimeMs() 18 | let delta = (now - previous) / 1000 19 | console.log('delta', delta) 20 | // game.update(delta, tick) // game logic would go here 21 | previous = now 22 | tick++ 23 | } 24 | 25 | loop() // starts the loop 26 | ``` 27 | Delta here is in units of seconds (not milliseconds, like it was in the original). The perfect delta at this TICK_RATE would be 0.050000000000. A delta of 0.051 is off by 1 millisecond. If running this code produces satisfactory accuracy on the target machine, then it may be a superior option to the node-game-loop. 28 | 29 | 30 | node-game-loop (original readme) 31 | ============== 32 | 33 | A game loop in node.js capable of accurate frame rates. 34 | 35 | This is an alternative to setTimeout/setInterval loops which are accurate to within 16 ms. 36 | 37 | This is also an alternative to a pure setImmediate loop which is nice and accurate, but will use 100% CPU (well, 100% of one thread) even while idle. 38 | 39 | -------------------------------------------------------------------------------- /gameLoop.js: -------------------------------------------------------------------------------- 1 | /** 2 | Length of a tick in milliseconds. The denominator is your desired framerate. 3 | e.g. 1000 / 20 = 20 fps, 1000 / 60 = 60 fps 4 | */ 5 | var tickLengthMs = 1000 / 20 6 | 7 | /* gameLoop related variables */ 8 | // timestamp of each loop 9 | var previousTick = Date.now() 10 | // number of times gameLoop gets called 11 | var actualTicks = 0 12 | 13 | var gameLoop = function () { 14 | var now = Date.now() 15 | 16 | actualTicks++ 17 | if (previousTick + tickLengthMs <= now) { 18 | var delta = (now - previousTick) / 1000 19 | previousTick = now 20 | 21 | update(delta) 22 | 23 | console.log('delta', delta, '(target: ' + tickLengthMs +' ms)', 'node ticks', actualTicks) 24 | actualTicks = 0 25 | } 26 | 27 | if (Date.now() - previousTick < tickLengthMs - 16) { 28 | setTimeout(gameLoop) 29 | } else { 30 | setImmediate(gameLoop) 31 | } 32 | } 33 | 34 | 35 | /** 36 | Update is normally where all of the logic would go. In this case we simply call 37 | a function that takes 10 milliseconds to complete thus simulating that our game 38 | had a very busy time. 39 | */ 40 | var update = function(delta) { 41 | aVerySlowFunction(10) 42 | } 43 | 44 | /** 45 | A function that wastes time, and occupies 100% CPU while doing so. 46 | Suggested use: simulating that a complex calculation took time to complete. 47 | */ 48 | var aVerySlowFunction = function(milliseconds) { 49 | // waste time 50 | var start = Date.now() 51 | while (Date.now() < start + milliseconds) { } 52 | } 53 | 54 | // begin the loop ! 55 | gameLoop() 56 | --------------------------------------------------------------------------------