Canvas game framerate drop - javascript

Good evening, first i'm not sure i should post this here, since i have litteraly no idea what's wrong here (only clue is it happened after i moved all my variables at the top of my code while trying to "clean up" a little).
but here is the problem: i've created a canvas game and after moving my variables (i think) i started getting major framedrops. Game weighs less than 20Ko, images are super tiny and simple, i have a for loop in the update loop but it never seemed to be a problem (it's not infinite) so in short i do not know what's wrong here
here is a bit of code since links to code "must be accompanied by code" (dont know what's up with that)
for (var i = 0; i<boxes.length; i++){
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var col = coli(player,boxes[i])
};
i've tried different things, like disabling functions (anim and colision), friction and gravity but nothing seems to have any effect, and i dont know that much about the dom except how to look at my own variables so i havent found anything with firebug.
Really hope someone has an idea

You need to add ctx.beginPath() before using ctx.rect, moveTo, lineTo, arc, and any function you need to use ctx.stroke() or ctx.fill() to see.
beginPath tell the canvas 2D context that you wish to start a new shape. If you do not do this you end up adding more and more shapes each update.
From your fiddle
function update() {
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = pat;
//===============================================================
ctx.beginPath() // <=== this will fix your problem. It removes all the
// previous rects
//===============================================================
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
// or use ctx.fillRect(...
var col = coli(player, boxes[i])
};
ctx.fill();

Related

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

html canvas returning line not connecting

I was trying out a simple script to create a rectangle and it seemed to work find except that the final leg of the polygon doesn't connect with the first leg properly. The strange thing is that all the other legs do connect properly.
Before anyone suggests that I use the built-in drawRect() or similar function, I should emphasize that this is just a simple example of a far more complex figure I'm trying to draw. I'm just confused why this is happening.
newX = 10;
letterHeight = 100;
ctx.strokeStyle = "#999999";
ctx.lineWidth = 6;
ctx.moveTo(newX,letterHeight*0.5);
ctx.lineTo(newX+letterWidth,letterHeight*0.5);
ctx.lineTo(newX+letterWidth,letterHeight);
ctx.lineTo(newX, letterHeight);
ctx.lineTo(newX, letterHeight*0.5);
ctx.stroke();
It seems to me that this probably has something to do with the line width and I could consider some problem-specific crude fix for that but is there a more general fix if that's the case?
Link to how the script rendered (using firefox)
Use ctx.closePath(); just before the stroke command to close the path. You should also be starting the path with ctx.beginPath();

Animating canvas' .stroke() without external libraries

I know it's been asked quite a lot (I did google it), but how can I animate .stroke() command on canvas? I found some examples, but they all rely on external overpowered (for my purposes) libraries or require use of pre-generated SVG files.
I have this page here (I know it sucks, but I am learning the curves with it among other things). What I need is to make the lines coming of the bottom "button" to "grow" or have an effect at least similar to what other buttons provide with circle. For circles I used jquery's knob library, but for lines... It feels like this can be done with transformation or something, but I can't put my finger on it. Any advice?
There are a couple ways to do this, but the easiest (and native) method doesn't require much code. Here is a WORKING FIDDLE of a canvas stroke() animation. The accompanying JavaScript is below. This is a very simple example, but it should give you the right idea.
var canvasObj = function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
animate = function() {
ctx.beginPath();
ctx.moveTo( 0, 0 );
ctx.lineTo( x,y );
ctx.stroke();
x += 5;
y += 2.5;
setTimeout( animate, 200 );
};
return {
'animate': animate
};
};
Explanation: The thing that makes this work is the closure that is created by the internal function animate within the canvasObj function. The variables x and y are available at the parent function level, and can be manipulated by the animate function. animate is calling itself by using setTimeout which creates the animation effect. And that's really it. Hope this helps you get on your way.

Canvas element not updating

I am trying to visualise a reinforcement agent moving through a 2d grid. I coded up a visualisation using canvas, and everytime my agent makes a move I try to update the grid. I was hoping to see an animation, but instead I see nothing until the agent has completed all this moves and I see the final state. If I step through with Google Chromes Developer tools then I can see the individual steps. I do not think it is a problem of my code just running to fast, because each step takes a couple of seconds.
My implementation is as follows, with the function gridWorld() called once to create a new object and executeAction called every time I want to draw. As shown I have used ctx.save(), and ctx.restore(), but that is only an attempt to solve this problem, and it seems to have made no difference.
Thanks
var execute gridWorld = function(action) {
var canvas = document.getElementById("grid");
this.ctx = canvas.getContext("2d");
this.executeAction = function(action) {
this.ctx.save()
// ... Do reinforcement learning stuff
// For every cell in grid, do:
this.ctx.fillStyle = "rgb(244,0,0)"
this.ctx.fillRect(positionX, poisitonY, 10,10)
this.ctx.restore();
}
}
Even if the code takes a long time to execute, the browser will not update the display until there is an actual break in the code. Use setTimeout() to cause a break in code execution whenever you want the canvas to update.
Your not going to see animations because they are happening way too fast. You need to break them up like in the following example.
Live Demo
If I did something like this for example
for(x = 0; x < 256; x++){
player.x = x;
ctx.fillStyle = "#000";
ctx.fillRect(0,0,256,256);
ctx.fillStyle = "#fff";
ctx.fillRect(player.x,player.y,4,4);
}
You would only ever see the player at the end of the board every time that function is called, and you wouldn't see any of the animations in between, because the loop runs too fast. Thats why in my live demo I do it in small increments and call the draw every 15 milliseconds so you have a chance to actually see whats being put on the canvas.

Question about the javascript-canvas object (save, transform, restore)

I've been playing around with canvas a lot lately. Now I am trying to build a little UI-library, here is a demo to a simple list (Note: Use your arrow keys, Chrome/Firefox only)
As you can tell, the performance is kinda bad - this is because I delete and redraw every item on every frame:
this.drawItems = function(){
this.clear();
if(this.current_scroll_pos != this.scroll_pos){
setTimeout(function(me) { me.anim(); }, 20, this);
}
for (var i in this.list_items){
var pos = this.current_scroll_pos + i*35;
if(pos > -35 && pos < this.height){
if(i == this.selected){
this.ctx.fillStyle = '#000';
this.ctx.fillText (this.list_items[i].title, 5, pos);
this.ctx.fillStyle = '#999';
} else {
this.ctx.fillText (this.list_items[i].title, 5, pos);
}
}
}
}
I know there must be better ways to do this, like via save() and transform() but I can't wrap my head around the whole idea - I can only save the whole canvas, transform it a bit and restore the whole canvas. The information and real-life examples on this specific topic are also pretty rare, maybe someone here can push me in the right direction.
One thing you could try to speed up drawing is:
Create another canvas element (c2)
Render your text to c2
Draw c2 in the initial canvas with the transform you want, simply using drawImage
drawImage takes a canvas as well as image elements.
Ok, I think I got it. HTML5 canvas uses a technique called "immediate mode" for drawing, this means that the screen is meant to be constantly redrawn. What sounds odd (and slow) first is actually a big advantage for stuff like GPU-acceleration, also it is a pretty common technique found in opengl or sdl. A bit more information here:
http://www.8bitrocket.com/2010/5/15/HTML-5-Canvas-Creating-Gaudy-Text-Animations-Just-Like-Flash-sort-of/
So the redrawing of every label in every frame is totally OK, I guess.

Categories