RaphaelJS - Simultaneous Animation - javascript

I have pong balls that are being generated very consistently, but the
rates change dynamically. So in a given second, there could be 1 pong
ball that's being drawn and translating across the screen (constantly
from left to right), or 50.
I have a pong paddle that responds based on the generation of these
balls, and it's supposed to "catch" every one of the balls that's
being sent towards its destination. The x coordinate is always the
same, because the pong paddle never moves, but the y coordinate is
randomly generated.
Here's an extremely similar (if not identical) example of what I'm
doing: http://www.youtube.com/watch?v=HeWfkPeDQbY
I have a lot of this code already written, but I'm afraid my design
for catching the balls is incorrect/inefficient. It works, but the
paddle very easily becomes out of sync with the balls that are being
thrown towards it.
The way I'm currently doing this is by putting each ball object into a
global array, and the paddle pops the next ball off of this queue and
uses basic arithmetic to calculate the speed at which it needs to
translate to the y coordinate of the next ball.
Is there a more efficient way of doing this?

I'll assume the issue is that the motion of each ball (and the paddle) is controlled by a separate timer. Since there are no guarantees about the exactness of js timers, there are really no guarantees about how many, many timers will interact.
Two broad approaches to correct the problem are:
Instead of using raphaeljs animation primitives, implement a synchronous animation yourself with setTimer, updating the position of each ball (and the paddle) in sync. Then any timer-stutters apply consistently across all elements in your universe.
Use feedback to course-correct the paddle position, e.g. by having a special setTimer that periodically looks at how close the paddle is to where it needs to be, and if necessary calls .stop() on the paddle's animation in order to re-execute with more aggressive parameters, closing the gap.

Related

Why is GPU render time inconsistent?

I'm building a WebGL application using THREE and am noticing some odd timing on the GPU. I don't have repro code available at the moment but I thought I'd ask the question in case it's a known browser quirk or something common and fixable.
Scene Setup
Scene with ~2,000,000 polygons, 136 Meshes, and 568 Object3D instances.
Using THREE.Composer with the FXAA and Unreal Bloom passes.
Using THREE.OrbitControls.
The scene is only rendered when something is known to have changed. For example, a draw is scheduled when the user drags the scene to move the camera with the controls or something in the scene moves. The scene is often static so we try not to render unnecessarily in those cases.
The Problem
The issue happens when the scene has been static (not drawn for a bit) and then the user changes the camera position by dragging. Once the user starts dragging the framerate is very choppy -- maybe 10-20 fps or lower -- for several frames before smoothing back out to something closer to 60. This happens consistently when leaving the scene alone for several seconds and then dragging again. If the mouse is dragged consistently after the initial stutter then the framerate stays smooth. Nothing different is being rendered for these frames.
This stuttering doesn't happen and the scene remains snappy if it's rendered every frame using requestAnimationFrame.
Here's the performance profiler with the stutter when the scene is only being rendered when something changes. You can see that there is a lot more time spent on the GPU during the frames that stutter before smoothing out again:
And the profiler when the scene is rendered at 60 fps:
Any thoughts? Why is there so much more GPU work happening suddenly on drag? Could the draw be blocked by some other rendering process? Why would it happen so consistently after not rendering for a few seconds? I've profiled using the latest version of Chrome but the stutter is present in Firefox, as well.
Thank you!
without a live sample there is no easy way to know BUT....
1 Three.js can do frustum culling on objects.
That means if some objects are off outside of the view they won't get drawn. So, put the camera in such a way that all objects are visible will run slower than if only some objects are visible
2 Primitive Clipping
Same as above except at the GPU level. The GPU clips primitives (it doesn't draw or compute pixels outside the view) so similar to above, if the lots of the things you're trying to draw happen to be outside the view it will run faster than if everything is inside the view.
3 Depth(Z) Buffer rejection
Similar to above again, if your objects are opaque then if a pixel is is behind an existing pixel via the depth test the GPU will skip calling the pixel shader if it can. This means if you draw 568 things and the first one you draw is the closest thing to the camera and covers up many things behind it than it will run faster than if all those things behind it draw drawn first. Three.js has the option to sort before drawing. Usually sorting is turned on for transparency since transparent objects need to be drawn back to front. For opaque objects though drawing front to back will be faster if any front objects occlude objects further back.
4 Drawing too many frames?
Another question is how are you queuing your draws? ideally you only queue a single draw and until the drawing has happened don't queue any more.
So
// bad
someElement.addEventListener('mousemove', render);
The code above will try to render for every mouse move even if that's > 60 fps
// bad
someElement.addEventListener('mousemove', () => {
requestAnimationFrame(render);
});
The code above may queue up lots and lots of requestAnimationFrames all of which will get executed on the next frame, drawing your scene multiple times per frame
// good?
let frameQueued = false;
function requestFrame() {
if (!frameQueued) {
frameQueued = true;
requestAnimationFrame(render);
}
}
function render(time) {
frameQueued = false;
...
}
someElement.addEventListener('mousemove', () => {
requestFrame();
});
Or something along those lines so that at most you only queue on render and don't queue any more until that render has completed. The code above is just one example of a way to structure your code so that you don't draw more frames than you need to.

Should I use ctx.translate for an endless game-map?

Well, just imagine you keep going up but your player stays put in the middle, and as you go up the map generates itself randomly.
With the help of:
ctx.translate(0, 1);
the map moves towards you as you move up.
now, I have a few methods in mind and of them is ctx.translate, but I have a few questions:
1) in the long run, what I fear is that it will keep the memory of the previous drawings once they go out of the canvas borders and eventually the ctx x/y system will go to numbers as high as millions.
2)I need something which is CPU friendly. I am just not sure what ctx.translate does under the hood exactly, does it behave in the likes of ctx.clearRect and then redraws everything?
3) anything better to achieve the same thing will be lovely, I already know about the old clearRect(which is heavy) and redraw method, just looking for other options.
EDIT: the player may change his X coordinate in some position too.

Stop second sprite leaving the canvas JavaScript

I'm creating a game which involves one sprite bouncing around and the user controlling another sprite to avoid being hit.
I'm having two problems:
I've managed to get the first sprite to bounce within the canvas but the second one is still disappearing at the moment.
I can't seem to get the two sprites to detect collision (they are both circular).
Remarkably I can operate Github so it's there if anyone wants to cast a critical eye (please do!) https://github.com/SallyBoulton/Javascript-Game.git

JavaScript canvas game development

Ive been having a really baffling slow down issue with the game I am working on probably because I am unsure how to handle graphics (most likely responsible for the slow down) in javascript without using a third party framework like Phaser/ImapactJS/EaselJS etc)*. The following is the low down on how I am approaching my graphics. I would be very thankful for some tips or methods on how to do this right.
My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices.
I am using a spritesheet to load all (most of) my tiles before the main loop is run. This image is roughly 4000 x 4000 (keeping it below 4096 because the GPU cant handle texture sizes larger than that).
I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.
The map is currently 6x6 tiles in size
A character spritesheet is also loaded and drawn on to the canvas after the map has been drawn. The character displays a different frame of the animation on every cycle of the main loop. There are sets of animations for the character each contained in the same spritesheet.
The character sprite sheet is roughly 4000x3500
The character is roughly 350x250 px
Other objects also use the same sprite sheet. Currently there is only one object.
Possibly helpful questions:
Am I using too many spritesheets or too few?
Should I only draw something if it's coordinates are in bounds of the screen?
How should I go about garbage collection? Do I need to set image objects to null when no longer in use?
Thanks in advance for input. I would just like to know if I am going about it the right way and pick your brains as how to speed it up enough.
*Note that I plan to port the JS game to cocoonJS which provides graphics acceleration for the canvas element on mobile.
** If interested please visit my Patreon page for fun!
You have asked lots of questions here, I'll address the ones I've run into.
I would like to start out by saying very clearly,
Use a profiler
Find out whether each thing you are advised to do, by anybody, is making an improvement. Unless we work on your code, we can only give you theories on how to optimise it.
How should I go about garbage collection? Do I need to set image objects to null when no longer in use?
If you are no longer using an object, setting its reference to null will probably mean it gets garbage collected. Having nulls around is not necessarily good but this is not within the scope of this question.
For high performance applications, you want to avoid too much allocation and therefore too much garbage collection activity. See what your profiler says - the chrome profiler can tell you how much CPU time the garbage collector is taking up. You might be OK at the moment.
I then use the drawImage function to cycle through and draw each tile on a part of the canvas using information (w, h, x, y) stored in the tile array. I do this on every cycle of the main loop using my drawMap function.
This is quite slow - instead consider drawing the current on screen tiles to a background canvas, and then only drawing areas which were previously obscured.
For example, if your player walks to the left, there is going to be a lot of tiles on the left hand side of the screen which have come into view; you will need to draw the background buffer onto the screen, offset to account for the movement, and then draw the missing tiles.
My game is tile based - using tiles designed at 500x500 px because I want them to display decently on high definition devices
If I interpret this right, your tiles are 500x500px in diameter, and you are drawing a small number of these on screen. and then for devices without such a high resolution, the canvas renderer is going to be scaling these down. You really want to be drawing pixels 1:1 on each device.
Would you be able, instead, to have a larger number of smaller tiles on screen - thereby avoiding the extra drawing at the edges? Its likely that the tiles around the edges will sometimes draw only a few pixels of one edge, and the rest of the image will be cropped anyway, so why not break them up further?
Should I only draw something if it's coordinates are in bounds of the screen?
Yes, this is a very common and good optimisation to take. You'll find it makes a big difference.
Am I using too many spritesheets or too few?
I have found that when I have a small number of sprite sheets, the big performance hit is when I frequently switch between them. If during one draw phase, you draw all your characters from character_sheet.png and then draw all the plants from plant_sheet.png you'll be ok. Switching between them can cause lots of trouble and you'll see a slow down. You will know this is happening if your profiler tells you that drawImage is taking a big proportion of your frame.

Get Second Point By First And Distance

I'm building an online game, and using node and whatnot, anyway i'm not too keen on constant streams and streams of data just for animations, i've set up a way for it to animate client side and so on... but i found a problem, all i was doing was setting the new coordinates and telling all the clients to animate their character to that point, but if you refreshed the page, the player would be there instantly.
I have got a distance,speed of movement,time of movement,start and destination... i know where they started moving, i know where their destination is, i know when they started moving and at what speed, and in a linear fashion.
What i need to work out, is where the player is (whilst animating) at that specific time when other players join the game.
Try http://en.wikipedia.org/wiki/Kinematics
Or http://en.wikipedia.org/wiki/Speed
the distance travelled can be calculated by rearranging the definition to d=v*t
The simplest approach would be to tween the position. That involves creating a series of intermediate steps along the path between the current position and the updated one. This works best if you know the frequency of updates. You can choose these points linearly or use an easing function to smooth it out.
If you really are doing a physical simulation though, it'll probably look more natural if you take the physical model into consideration. I'd try the simple case first before seeing whether you need to go into more mathematically complex territory.

Categories

Resources