Guide to integrating a deterministic game loop with tick-based mechanics

My current project involves creating a "simple" 3D game using Three.js and incorporating a network framework for multiplayer functionality in the future. After some research, I found that many "action" games utilize a "tick" based game loop to sync clients and servers, allowing for smooth interpolation between ticks.

I have developed a working code for the tick function that handles input, updates, and draws. I want to confirm if my implementation is correct and understand how this "deterministic" loop should function. When I increase the "tick rate," the game speeds up as the update function runs more frequently - is this the expected behavior?

this.loops = 0;
this.tick_rate = 20;
this.skip_ticks = 1000 / this.tick_rate;
this.max_frame_skip = 10;
this.next_game_tick = performance.now();

The above code snippet is part of the Game class constructor.

Game.prototype.run = function () {
    this.handle_input();

    this.loops = 0;

    while (performance.now() > this.next_game_tick && this.loops < this.max_frame_skip){
        this.up_stats.update();
        this.update();
        this.next_game_tick += this.skip_ticks;
        this.loops++;
    }

    this.draw();
    //monitor performance
    this.stats.update();

    //next update
    requestAnimationFrame(this.run.bind(this));
};

For the complete code, visit: https://github.com/derezzedex/first_three_js/blob/master/js/game/main.js

Answer №1

This solution appears quite reasonable to me and I have utilized similar techniques in previous projects.

Managing synchronized simulations is a broad subject, but what you have presented serves as a solid foundation and may suffice depending on the complexity of your game.

edit: Providing more clarification...

Yes, it operates similarly, with the difference being that this.dt remains constant. For example, 1000 / your chosen FPS for the game loop.

If you wish to incorporate smoothing/interpolation between frames, you will need to store the previous state of your object as well. It is advisable to avoid using Euler rotations, as they do not interpolate effectively. This is because an angle of 360 degrees flips back to 0, resulting in peculiar interpolation logic...

Instead, you can record the state before and after the update...

and interpolate the .quaternion instead... linear interpolation works well for slight rotation changes. For larger changes, you can utilize quaternion.slerp() which handles interpolation over greater distances.

Therefore, you have lastTickTime, currentTime, and nextTickTime...

Each frame, you are essentially performing the following:

To achieve interpolation, follow these steps:

var alpha = (currentTime - lastTickTime) / (nextTickTime - lastTickTime);//nextTickTime - lastTickTime = your framerate delta (e.g., for 60fps = 1000/60 = 16.666666666666668)

var recip = 1.0 - alpha;

object.position.x = (object.lastPosition.x * recip) + (object.nextPosition.x * alpha)
object.position.y = (object.lastPosition.y * recip) + (object.nextPosition.y * alpha)
object.position.z = (object.lastPosition.z * recip) + (object.nextPosition.z * alpha)

object.scale.x = (object.lastScale.x * recip) + (object.nextScale.x * alpha)
object.scale.y = (object.lastScale.y * recip) + (object.nextScale.y * alpha)
object.scale.z = (object.lastScale.z * recip) + (object.nextScale.z * alpha)

object.quaternion.x = (object.lastQuaternion.x * recip) + (object.nextQuaternion.x * alpha)
object.quaternion.y = (object.lastQuaternion.y * recip) + (object.nextQuaternion.y * alpha)
object.quaternion.z = (object.lastQuaternion.z * recip) + (object.nextQuaternion.z * alpha)
object.quaternion.w = (object.lastQuaternion.w * recip) + (object.nextQuaternion.w * alpha)

In a proper Three.js application, it is recommended not to directly store lastPosition and nextPosition on the object but rather in object.userData. Nonetheless, it should still function correctly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error: Unable to execute this.context.router.push due to it not being a function

I recently encountered an issue where the browser console displayed the same message as the post title. The problem occurred when trying to navigate to a profile page after clicking a dropdown button. contextTypes: { router: React.PropTypes.func }, _h ...

I encountered an issue with Expo commands where it was throwing an error: "Module not found: 'minizlib'"

Every time I attempt to execute commands like expo init, expo start, or simply expo, it returns the following error message: Error: Cannot find module 'minizlib' Require stack: - /usr/local/lib/node_modules/expo-cli/node_modules/tar/lib/pack.js ...

Does anyone else have trouble with the Smtp settings and connection on Servage.net? It's driving me crazy, I can't figure it out!

Whenever I attempt to connect to send a servage SMTP, it gives me this error message: SMTP connect() failed. I have tried using the following settings: include('res/mailer/class.phpmailer.php'); $mail->SMTPDebug = 2; include('res/mai ...

Fetch information that was transmitted through an ajax post submission

How can I retrieve JSON formatted data sent using an ajax post request if the keys and number of objects are unknown when using $_POST["name"];? I am currently working on a website that functions as a simple online store where customers can choose items m ...

Using jQuery to send a GET request to the current page with specified parameters

Within my application, hosted on a PHP page, I am aiming to trigger a GET request upon selecting an option from a dropdown menu. The URL of the page is: www.mydomain.it/admin/gest-prenotazioni-piazzola.php I intend to utilize jQuery to execute this GET r ...

I am seeking to redirect to a different page within an ejs template by clicking on a link

I am having trouble navigating to the next page using a link and keep getting a 404 error. I recently switched my template from jade to ejs. <html> <body> <div> <ul style="color:white; float: right;" class="nav navbar-nav ...

Is there a delay following the click on the file upload button?

Whenever I attempt to choose a file for upload by clicking on "Select File" (input type=file), there seems to be a lag between the moment I click the button and when the selected file appears next to the button. It almost seems as if the browser is attempt ...

What are the various undisclosed schema types in A-Frame?

I've been exploring different examples of property types in the official documentation and various Github repositories (though now I can't remember which ones). The latter introduced me to unique properties like "min" and "max" for numbers, as we ...

Angular's two-way binding feature allows the use of a variable as a string without directly assigning it to

Sample HTML code: <div tile-component included-svg='::installController.installUpdatesSvg'></div> Install controller: **A scope variable named 'installUpdatesSvg' is defined** this.installUpdateSvg = 'xyzSvg'; ...

Combining multiple JSON objects into a single array in AngularJS

Currently, I am facing a challenge in merging two API calls. The first call involves fetching data by filtering the account_id on the backend, while the second call retrieves data based on the test_id. Let's start with the JSON response for /api/test ...

Change the z-index of divs when clicked

When a button is clicked, I want to iterate through a group of absolutely positioned children divs with varying z-indexes. The goal is for the z-index of the currently visible div to decrease on each click, creating a looping effect where only one div is v ...

What are the best ways to conceptualize the benefits of WebRTC?

I encountered a peculiar issue with the abstraction of the WebRTC offer generation process. It appears that the incoming ice candidates fail to reach the null candidate. While I have been able to generate offers successfully using similar code in the past, ...

Trouble with incrementing JavaScript dictionary values within a nested for loop

I am currently working on analyzing shark attack data with d3.js using a csv file named shark.csv. I have encountered a problem while implementing a nested for-loop in my code. The csv file contains information about shark attacks categorized by continent ...

Creating a stand-alone JavaScript file for generating Bootstrap-vue Toast notifications

After a few days of learning vue.js, I decided to implement a custom toast function based on the official bootstrap-vue documentation: . I successfully created toasts using component instance injection and custom components in Vue. However, my goal now is ...

Ensure the backslashes are removed from the AWS Lambda string API response

I have an AWS Lambda function where I am sending a string as my final response let abc= `"phone_exist":"0","calls":"0","lastaction":"0"` callback(null,abc); Output: "\"phone_exist\":\"0\",\"calls\":\"0\",\"l ...

Having trouble with the npm Twitter API functionality?

I'm attempting to execute a simple stream using an example code snippet. Here is the code I am working with: var twit = require('twitter'); var twitter = new twit({ consumer_key: '[KEY]', consumer_secret: &ap ...

Building a node.is script to validate email addresses

This code snippet is for validating email addresses. I have successfully implemented example 5, where the email length must be over 5 characters to avoid errors and prompt users to re-enter their email address. However, I am unsure how to handle examples ...

Utilizing the power of $.ajax() to parse through an XML document

I have a query about working with a large XML file containing 1000 nodes. Here is the code snippet I am using: $.ajax({ type: "GET", cache: false, url: "someFile.xml", ...

The xslt code is failing to invoke the JavaScript function

I am currently utilizing xslt for the transformation of xml to html. Below is an example of an .xml file. <ImportOrganizationUtility-logging> <log-session module-name="ImportOrganizationUtility" end="17:54:06" start="17 ...

Is it possible to move a directive within a limited parent element?

Is there a way to limit the movement of an angular.js drag directive within the confines of its parent element? You can see the problem I'm facing in this jsbin: http://jsbin.com/maxife/3/edit?html,css,js,output ...