I am building multiplayer real-time space shooter game. At first i created only single player local version of the game to see how things can be done. Game was runing smoothly with stable 60 fps. I was happy with the core and performance so i started porting it for multi player version. As server for the game i use node.js.
I want every player to see the same "state" of game and have the same experience with the game so i decided to only pass player input to the server and let server calculate everything.
The question is, which method should be used for game loop on server side?
Server is calculating enemies position and enemies bullets. I used setInterval method:
setInterval(function() {
for(var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
enemy.move();
enemy.fire();
}
io.emit('enemies', enemies);
}, 1000 / 60)
enemy move function is like this:
this.move = function() {
this.x += (this.movX - this.x) / this.speed;
this.y += (this.movY - this.y) / this.speed;
};
On the client side i run requestAnimationFrame loop:
socket.on('enemies', function(enemies) {
self.enemies = enemies;
});
var run = function() {
for(var i = 0; i < self.enemies.length; i++) {
(function(i) {
var enemy = self.enemies[i];
if(enemy.alive) {
for(var i = 0; i < enemy.primary_bullets_pool.length; i++) {
var bullet = enemy.primary_bullets_pool[i];
if(bullet.alive) {
self.context.fillStyle = 'red';
self.context.fillRect(bullet.x, bullet.y, bullet.w, bullet.h);
}
}
self.context.drawImage(self.images[enemy.model], enemy.x, enemy.y, enemy.w, enemy.h);
}
}(i));
}
window.requestAnimationFrame(run);
};
Now the user experience is very bad. Enemies are "jumping" on the screen instead of move smoothly. I experimented with timing for interval. If put 10 ms instead of 1000 / 60 - it is going a little bit better but jittering still is visible. What is the right way to make it happen so every player can see enemies in the same position at any given time and move is done smoothly?
As it stands, it looks like you're updating enemy positions every "tick"- which, as you've noticed, will appear jittery if the server can't update their positions quickly enough.
Ideally, you don't want your server to have to emit position events for all enemies to all players constantly just to achieve smooth movement. That's a lot of overhead for something that ought to be handled entirely on the client.
What I advise is not updating an enemy's position on the client every "tick," but accepting a set of coordinates the enemy should be moving toward whenever an enemy begins moving (or begins moving in a different direction) and then animating that. This will get you the smoother experience you want.
Some of the answers on this question from the GameDev Stack Exchange ought to point you in the right direction for implementing a "move toward" function.
Related
I am trying to make a robot that can perform certain animations when keys are pressed.
When I press the "J" key I would like the robot to jump up and down.
I am using Three.js and Tween.js to accomplish this. So far I have a scene made with light and a camera. I am creating the different parts of the robot through functions. I have an example of one of these functions below.
function createHead() {
const head = new THREE.Mesh( new THREE.BoxGeometry(30, 30, 30),
new THREE.MeshLambertMaterial({ color: 0x669999 }));
head.position.y = 30;
head.position.z = -250;
head.rotation.y = 5;
scene.add(head);
var jumpTween = new TWEEN.Tween(head.position).to({y: head.position.y+20}, 1000).repeat(1).yoyo(true).start();
}
Here is my function for updating
function update (event) {
if (String.fromCharCode(event.keyCode) == "J" || isJumping)
{
isJumping = true;
TWEEN.update();
}
// Draw!
renderer.render(scene, camera);
// Schedule the next frame.
requestAnimationFrame(update);
}
When I press "J" my robot jumps once and only once. I cannot press "J" again to get the robot to perform another jump. I was hoping there would be away to just simply "call" a tween on command and have it play on command. However, it seems like TWEEN.update() is the only function that actually runs the tween and in this case, it only runs once. I have been reading the documentation for Tween.js but I am not finding anything helpful.
Edit: I have also tried adding this to my tween.
.onComplete(() => {isJumping = false})
so that it would set isJumping back to false when the animation completes but this did not work.
Thanks for the help.
I am experimenting with creating games using Three.js and I would like to ask if there is a way to animate a GLFT model but instead of having the animation loop I would like to use random intervals. In my case, the game is about taking care of frogs (but I'm cool so I spelled it phrogs) and as an idle animation I want the frogs to croak randomly. Further on in development I also want to add randomly playing animations for movement, eating etc but right now I only need the croaking animation.
Here is the code that loads the model and animates it:
const basePhrog = new GLTFLoader()
var obj
basePhrog.load('assets/models/Phrogs/base phrog/phrog.gltf', function (gltf) {
mixer = new THREE.AnimationMixer(gltf.scene)
obj = gltf.scene
var action = mixer.clipAction(gltf.animations[0])
scene.add(gltf.scene)
action.play()
})
My animate loop looks like this:
function animate () {
requestAnimationFrame(animate)
var delta = clock.getDelta()
if (mixer) mixer.update(delta)
renderer.render(scene, camera)
}
animate()
I hope you can help and thank you for any suggestions!
The glTF file provides an animation (or THREE.AnimationClip in three.js terminology), and the playback of that clip is managed by a THREE.AnimationAction instance. The code in your example will begin playing that animation immediately, and loop it forever, but the AnimationAction does not have to be used that way.
Instead, you could wait and play the action at random intervals:
var action = mixer.clipAction( animation );
action.loop = THREE.LoopOnce;
// Play animation randomly every 1-10s.
setInterval(() => {
action
.reset()
.play();
}, Math.random() * 9000 + 1000);
You can continue to update the AnimationMixer as you are doing now, regardless of whether the animation is playing at any given time.
If you're later trying to play multiple animations on the same object, some of the APIs for transitioning between two animations may be helpful, see the animation / skinning / morph example.
So i'm trying to make my game unload a bunch of un-used resources. It's proving to be a lot more complicated. here's my code:
var meteor = this.physics.add.group();
this.physics.add.collider(meteor, sput, deathControl, null, this);
meteorSpawnFrequency = 500;
setInterval(spawnMeteor, meteorSpawnFrequency);
var meteorCap = 0;
function spawnMeteor() {
//Create Meteors
meteorCap++;
meteors = meteor.create(Math.floor(Math.random() *800) + 1, 30, "meteor");
//Edit Meteors
meteors.depth = -1;
meteors.setVelocityY(500);
meteors.setScale(Math.floor(Math.random() * 2) + 1);
meteors.setCollideWorldBounds(true);
//Destroy meteors after the cap reaches 10
if(meteorCap > 10){
meteors.destroy();
console.log("meteors destroyed");
meteorCap = 0;
}
}
I'm using an interval to spawn the sprites, and all of it works just fine. What I'm trying to do is set a cap that when 100 meteors are present, they'll get destroyed, and the cap gets set back to 0, to repeat this process.
Only problem is it's not working. How do I get this working?
Almost certainly a scope issue and there isn't enough source code shown to determine the root cause. But meteorCap looks dangerous like a local variable, so reading it from spawnMeteor isn't going to work.
Also, don't use setInterval, there is literally a TimerEvents feature built into the Phaser API for exactly this that is game-step safe and manages the scope context for you. Here is one such an example.
I'm creating a PDF output tool using jsPDF but need to add multiple pages, each holding a canvas image of a video frame.
I am stuck on the logic as to the best way to achieve this as I can't reconcile how to queue the operations and wait on events to achieve the best result.
To start I have a video loaded into a video tag and can get or set its seek point simply with:
video.currentTime
I also have an array of video seconds like the following:
var vidSecs = [1,9,13,25,63];
What I need to do is loop through this array, seek in the video to the seconds defined in the array, create a canvas at these seconds and then add each canvas to a PDF page.
I have a create canvas from video frame function as follows:
function capture_frame(video_ctrl, width, height){
if(width == null){
width = video_ctrl.videoWidth;
}
if(height == null){
height = video_ctrl.videoHeight;
}
canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.drawImage(video_ctrl, 0, 0, width, height);
return canvas;
}
This function works fine in conjunction with the following to add an image to the PDF:
function addPdfImage(pdfObj, videoObj){
pdfObj.addPage();
pdfObj.text("Image at time point X:", 10, 20);
var vidImage = capture_frame(videoObj, null, null);
var dataURLWidth = 0;
var dataURLHeight = 0;
if(videoObj.videoWidth > pdfObj.internal.pageSize.width){
dataURLWidth = pdfObj.internal.pageSize.width;
dataURLHeight = (pdfObj.internal.pageSize.width/videoObj.videoWidth) * videoObj.videoHeight;
}else{
dataURLWidth = videoObj.videoWidth;
dataURLHeight = videoObj.videoHeight;
}
pdfObj.addImage(vidImage.toDataURL('image/jpg'), 'JPEG', 10, 50, dataURLWidth, dataURLHeight);
}
My logic confusion is how best to call these bits of code while looping through the vidSecs array as the problem is that setting the video.currentTime needs the loop to wait for the video.onseeked event to fire before code to capture the frame and add it to the PDF can be run.
I've tried the following but only get the last image as the loop has completed before the onseeked event fires and calls the frame capture code.
for(var i = 0; i < vidSecs.length; i++){
video.currentTime = vidSecs[i];
video.onseeked = function() {
addPdfImage(jsPDF_Variable, video);
};
}
Any thoughts much appreciated.
This is not a real answer but a comment, since I develop alike application and got no solution.
I am trying to extract viddeo frames from webcam live video stream and save as canvas/context, updated every 1 - 5 sec.
How to loop HTML5 webcam video + snap photo with delay and photo refresh?
I have created 2 canvases to be populated by setTimeout (5000) event and on test run I don't get 5 sec delay between canvas/contextes, sometimes, 2 5 sec. delayed contextes get populated with image at the same time.
So I am trying to implement
Draw HTML5 Video onto Canvas - Google Chrome Crash, Aw Snap
var toggle = true;
function loop() {
toggle = !toggle;
if (toggle) {
if (!v.paused) requestAnimationFrame(loop);
return;
}
/// draw video frame every 1/30 frame
ctx.drawImage(v, 0, 0);
/// loop if video is playing
if (!v.paused) requestAnimationFrame(loop);
}
to replace setInterval/setTimeout to get video and video frames properly synced
"
Use requestAnimationFrame (rAF) instead. The 20ms makes no sense. Most video runs at 30 FPS in the US (NTSC system) and at 25 FPS in Europe (PAL system). That would be 33.3ms and 40ms respectively.
"
I am afraid HTML5 provided no quality support for synced real time live video processing via canvas/ context, since HTML5 offers no proper timing since was intended to be event/s controlled and not run as real time run app code ( C, C++ ...).
My 100+ queries via search engine resulted in not a single HTML5 app I intend to develop.
What worked for me was Snap Photo from webcam video input, Click button event controlled.
If I am wrong, please correct me.
Two approaches:
create a new video element for every seek event, code provided by Chris West
reuse the video element via async/await, code provided by Adrian Wong
We're developing arcade (a lot of action and speed) browser 2d-game using canvas.
Sometimes our testing players report us that there is a delay: player still moving 5-10 pixels away after keyup.
I've digged this issue, you can see yourself delay http://jsfiddle.net/C4ev3/7/ (try keydown/up any key as fast as you can). My results is from 70 to 120ms. And i think that's a lot. (FYI, our network latency is 10-20ms).
Any ideas how to reduce this delay?
upd i've noticed that on good hardware this delay is under 30-40ms. But i'm testing on core2duo, winxp, chrome 19 - it's not a P4 with IE6 :)
Hi one thing you could do is instead of using an anonymous function try using defined functions,
http://jsfiddle.net/C4ev3/10/ - for me this reported at 50-100 MS
However i would not recommend jQuery for Canvas Applications it's very big for the very little you using, you should try using native Javascript
http://jsfiddle.net/C4ev3/11/ - for me this reported 30-70 MS
Javascript Threading
One thing i noticed in the comments Javascript is not Multi-Threaded Well Urm-Arr,
it sort of is setInterval is Async not Sync, however affecting the window is a single thread E.G if you have a Class that has some number is it using a setInteval will use another thread and not have a problem altering the math however in the Task then requires a Draw on the page it will enter the bottom of the JS handle Que,
Certain parts of Javascript are on a different thread how ever any thing changing the page has to run on the Main Thread same as any Windows application if your thread want to change the Form your have to invoke the main thread to do it for you
however it is not multi-threaded like any thing else you cant just handle or abort at a given Wim like windows,
Other ASync Tasks include AJAX has the option to be both Async and Sync
Updated to show my comment about FPS limiting:
Please bear with me. This is linking to a project that is allready built to show the example:
so my Game is Completely OOP
var elem = document.getElementById('myCanvas');
var context = elem.getContext("2d");
context.fillStyle = '#888';
context.lineWidth = 4;
// Draw some rectangles.
context.fillRect(0, 0, 800, 600);
context.fillStyle = '#f00';
var ball = new Ball();
var leftPadel = new Padel(10, 60, 40, 120);
var rightPadel = new Padel(750, 520, 40, 120);
pong = new Pong();
pong.draw();
setTimeout("ball.move()", pong.redrawTime());
Inside my pong class is where all the main workings of the game goes but here are the FPS bit you need to see
this.fps = 30;
this.maxFPS = 60;
this.redrawTime = function(){
return (1000 / this.fps)
}
this.lastDraw = (new Date)*1 - 1;
Then as you can see my Interval is on ball.move this calls the main pong class again on redraw at the End of the redraw i have the FPS checking and limiting code
this.fps = ((now=new Date) - this.lastDraw);
if(this.fps > this.maxFPS){
this.fps = this.maxFPS;
}
this.lastDraw = (new Date)*1 - 1;
if(this.reporting = true){
console.clear();
console.log("FPS: "+this.fps.toFixed(1))
}
setTimeout("ball.move()", pong.redrawTime());
This then forces you to get the Best Possible FPS without queuing the Main Thread
Try this:
e.stopPropagation()
Stops the bubbling of an event to parent elements, preventing any
parent handlers from being notified of the event.
e.preventDefault()
Prevents the browser from executing the default action. Use the method
isDefaultPrevented to know whether this method was ever called (on
that event object).
My min. results in Google chrome: 7ms