Canvas World to Screen stuttering - javascript

I'm coding a game in the style of agar.io where I want to move the player to the direction relative to the mouse position.
This is how I check the mouse position, returning a Vector object;
let mouse_vector = new Vector();
canvas.onmousemove = function() {
mouse_vector = mouse(event);
}
function mouse(evt) {
mouse_vector = new Vector(evt.clientX - canvas.width/2, evt.clientY - canvas.height/2);
return mouse_vector;
}
The player is an object with an x and y coordinate to which I add the vector pointing towards the mouse. I have 1 canvas that represents the world and is hidden. The other canvas is my viewport, on which I draw the cropped world relative to the player position.
I'm using requestAnimationFrame here, but I tried using Interval as well.
function draw() {
player.x += mouse_vector.x * 0.005;
player.y += mouse_vector.y * 0.005;
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
canvasCtx.drawImage(game, player.x-canvas.width/2, player.y-canvas.height/2, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
canvasCtx.arc(canvas.width/2, canvas.height/2, player.r, 0, 2*Math.PI);
canvasCtx.fill();
requestAnimationFrame(draw);
}
My issue is that the game starts stuttering over time. I would like it to be as smooth as at the start. I'm suspecting the issue is related to some kind of caching. I've noticed the game uses a lot of CPU power. Any ideas?

The issue I was having was that I was not using the beginPath() method when filling arcs. Seems that not reseting the previous draw builds up and causes performance loss over time.
canvasCtx.beginPath(); // addition
canvasCtx.arc(canvas.width/2, canvas.height/2, player.r, 0, 2*Math.PI);
canvasCtx.fill();

So at the end of the day, you'll be re-drawing the whole map every 16ms to get 60fps which is the target of requestAnimationFrame - so you'll not be escaping the CPU hogging problem, unless you do some optimisation about the drawing.
About the logic you are doing: it doesn't seem from this piece of code that there can be anything that could be building up or leaking memory, so I suggest pasting your code to a code-sharing site like codepen.io and sharing it with the community, we'd have more chance of debugging it.

Related

Grid on HTML5 canvas game

I'm making an HTML5 canvas game and I want to make a grid. The map is infinite, and I want there to be a grid on the ground. But whatever I do, the same gets slower and slower over time and just gets too laggy to play.
Here's my current draw grid function.
function drawGrid() {
for (x=0;x<=canvas.width;x+=80) {
ctx.moveTo(x, offset[0] % 80);
ctx.lineTo(x, canvas.height + offset[0] % 80);
}
for (y=0;y<=canvas.height;y+=80) {
ctx.moveTo(offset[1] % 80, y);
ctx.lineTo(canvas.width + offset[1] % 80, y);
}
ctx.stroke();
}
I Just don't exactly understand why it gets so laggy.
EDIT: The canvas is cleared every frame by drawing a rectangle over everything, and this function runs every frame
I also don't think it's a different part of my code, If I run it without this function it doesn't lag.

Animating coordinates in JavaScript - precalculated values vs. on-the-fly calculation

I'm working on a looping animation using JavaScript and HTML5 <canvas>. The animation consists of using canvas' lineTo() method to connect between 10 and 200 coordinates to create an animated shape. The animation is looping and has a duration of 10-20 seconds. Using requestAnimationFrame() I'm looking at around 60fps, each iteration of which the position of each coordinate is updated.
What is the most efficient way of approaching this type of animation?
Approach 1 - on-the-fly calculations
Currently I'm just calculating and updating the position of each point in each iteration of requestAnimationFrame(). The performance is OK, but on older devices I've noticed the CPU usage spiking and occasional rendering lags. The calculations are pretty basic geometrical manipulations.
Approach 2 - pre-calculated positions
I have been toying with the idea of pre-calculating each possible position that a pointcould have, and storing that in memory. Then during the requestAnimationFrame() loop, I can simply access the coordinates for each point and update its position. But I'm unsure of the performance implications and whether this would really make an impact.
I plan on testing approach 2 to see if there is a noticeable difference. But I'm curious if there is another approach I should consider? Is canvas even the right tool for the job here, or should I be looking at something like WebGL?
*** Edit: here are the calculation & canvas drawing functions so you have an idea of the computation run on each frame:
Animation.prototype = {
... the rest of the prototype setup ...
// This function runs once per `requestAnmiationFrame()` call:
updateNodes: function() {
let progress = this.getProgressRadians(); // simple time offset
// This loops over between 10-200 node objects, updating their positions
this.nodes.forEach(node => {
let offset =
((Math.sin(progress - node.numberOffset) + 1) / 2) *
this.pixelWaveHeight;
if (this.waveGrows) {
offset =
offset * (node.index / (this.nodes.length - 1)) * this.waveGrows;
}
if (this.waveAngleRadians) {
offset +=
Math.tan(this.waveAngleRadians) * this.spaceBetweenNodes * node.index;
}
let yValue = this.canvas.height - offset - this.pixelBaseHeight;
node.y = yValue;
});
},
// This function runs at the end of each `requestAnimationFrame()` call
draw: function() {
let ctx = this.canvas.ctx;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
ctx.beginPath();
ctx.moveTo(0, this.canvas.height);
this.nodes.forEach(node => {
ctx.lineTo(node.x, node.y);
});
ctx.lineTo(this.canvas.width, this.canvas.height);
ctx.lineTo(0, this.canvas.height);
ctx.closePath();
ctx.fill();
}
}
Most of those properties are static, e.g. calculated once at the beginning and then just accessed:
pixelWaveHeight - Number
waveGrows - Number

Preventing elements from jumping abruptly in canvas?

This is my pseudocode:
when move button is pressed:
currentCirclePos = circleX;
moveTimer = setInterval(move, 10);
My move function looks like this:
var move = function() {
circleX += move a bit;
};
In some cases, the element does not move at all. For those situations, I have the following code :
while(Math.abs(circleX - currentCirclePos) < some distance away){
drawCircle(circleX, circleY);
circleX += gradual shift;
}
This does not change the position of my circle gradually but draws it abruptly some distance away. I don't understand why is that happening. Could anyone help me debug the issue? Let me know if I need to post more code.
This is my requestAnimationFrame code:
requestAnimationFrame(animate);
function animate(){
ctx.clearRect(0,0,cw,ch);
ctx.rect(0, 0, cw, ch);
ctx.fillStyle = 'white';
ctx.fill();
drawCircle(circleX, circleY);
requestAnimationFrame(animate);
}
UPDATE : The while loop was not inside the animation function but now it is. However, it did not make any difference at all.
The problem is that You're using setInterval instead of requestAnimationFrame - it's more reliable way to do this kind of operations on canvas.
Please check this tutorial - author solves this problem pretty straightforward on example.

Why use context.save and context.restore()?

Why is it need to use context.save and context.restore() in any Javascript that is drawing lines to a canvas?
this.context = this.canvas.getContext("2d");
I am certain that it has to do with this line of code this.canvas.getContext("2d"); and canvas was defined above.
this.canvas = document.getElementById(config.canvasId);
Code:
BarChart.prototype.drawGridlines = function(){
var context = this.context;
context.save();
context.strokeStyle = this.gridColor;
context.lineWidth = 2;
// draw y axis grid lines
for (var n = 0; n < this.numGridLines; n++) {
var y = (n * this.height / this.numGridLines) + this.y;
context.beginPath();
context.moveTo(this.x, y);
context.lineTo(this.x + this.width, y);
context.stroke();
}
context.restore();
};
context.save() saves the current state of the context (strokeStyle, lineWidth, etc...) then your code will change those values. At the end of your code you call context.restore() which will restore the previous values that your code has changed.
This way you don't need to manually restore everything you changed and your code will not affect other code on the page that has previously modified these values.
You don't. context.save and context.restore are often used for efficient texture translation and rotation, hence show up in many examples.
Save stores your position, angle and various other canvas states. Then you can move to the position/angle you want to draw your image. Restore can then snap your co-ord grid back to the save point. Much easier than rotating points in space mathematically, and the only way to rotate images i know of with canvas 2d context mode.
If your doing simple drawing of boxes, lines or unrotated images then don't bother.

Using jQuery / HTML5 to animate a circle

For a personal project, I'm tyring to make a timer application (for controlling Poker blind schedules). I know there are several solutions already on the market, but for reasons which are too lengthy to go into here, we need a bespoke system. Although the output template of the system will ultimately be definable by the end user, we would like to include a widget which shows a circle that gets animated as the time counts down. Here's an illustration of a working example, showing the yellow circle and what we'd like to achieve (or something similar, anyway):
My question is, how would one code the animation as shown below using either jQuery or raw HTML5 / CSS3 animations? This is for a web application using jQuery, so there are no other library options I can use.
Advanced thanks!
If you can use HTML5, canvas is probably your best bet. Mozilla has some decent tutorials on drawing arcs. This should be enough to get you started.
var canvas = document.getElementById('canvasid'),
width = canvas.width,
height = canvas.height,
ctx = canvas.getContext('2d');
function drawTimer(deg) {
var x = width / 2, // center x
y = height / 2, // center y
radius = 100,
startAngle = 0,
endAngle = deg * (Math.PI/180),
counterClockwise = true;
ctx.clearRect(0, 0, height, width);
ctx.save();
ctx.fillStyle = '#fe6';
// Set circle orientation
ctx.translate(x, y);
ctx.rotate(-90 * Math.PI/180);
ctx.beginPath();
ctx.arc(0, 0, radius, startAngle, endAngle, counterClockwise);
ctx.lineTo(0, 0);
ctx.fill();
}
setInterval(function() {
// Determine the amount of time elapsed; converted to degrees
var deg = (elapsedTime / totalTime) * 360;
drawTimer(deg);
}, 1000);
You can achieve this with CSS3 and jQuery.
Check out my example here http://blakek.us/css3-pie-graph-timer-with-jquery/ which with slight modification you could make the timer look how you want it.
In HTML5 you can draw in a canvas.
For example:
// Create the yellow face
context.strokeStyle = "#000000";
context.fillStyle = "#FFFF00";
context.beginPath();
context.arc(100,100,50,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
Link
You should really check out Processing!
Especially Processing.js. There have been some interesting things made with it for iPhone
First solution i can think of is html5 canvas implementation. From the example above it becomes clear we're talking mobile, so what support does canvas get around mobile browsers i can't tell. developer.mozilla.org provides sufficient documentation. Using canvas to achieve such count down should be pretty simple task. Good luck.
HTML5 Canvas arc command (MDN) is probably what you're looking for. Just decrease the end angle over time to have your timer decrease.

Categories