I do not understand the code highlighted below that has a comment "I DO NOT UNDERSTAND WHAT IS GOING ON HERE". I know it is a call back function. But I do not understand how the function operates and the purpose. For the record I understand everything else. I have never seen a function written like this before. I do understand that the OR statements are for detecting which browser.
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
// I DO NOT UNDERSTAND WHAT IS GOING ON HERE
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
console.log("inside callback");
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var linearSpeed = 100;
// pixels / second
var newX = linearSpeed * time / 1000;
if(newX < canvas.width - myRectangle.width - myRectangle.borderWidth / 2) {
myRectangle.x = newX;
}
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
drawRectangle(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//
var myRectangle = {
//position
x: 0,
y: 75,
//dimension
width: 100,
height: 50,
// stlye
borderWidth: 5
};
drawRectangle(myRectangle, context);
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
When you OR two values together with JavaScript, you don't explicitly get a boolean... you get back the first truthy value. This is often used to provide defaults or fallbacks. For example:
console.log( null || 'some string'); // Logs 'some string'
var myOption = 'some value';
myOption = myOption || 'default value'; // myOption is 'some value'
What's happening specifically in your code is that the function requestAnimationFrame took a long time to be standardized. Each browser vendor made their own version of it with their own prefix. This function is going through each possible name of that function until it hits one. (A function is "truthy" where undefined or null is not.)
Related
I've read many posts and gone through several tutorials on HTML5 and the canvas specifically, but so far I have been unable to replicate my exact problem. If there is an answer for it already out there, please point me in the right direction.
My ultimate goal is to make a simple Pong game. I've drawn the basic objects using JavaScript and now I am trying to get the player (left) paddle to move. The problem I am running into with my current code is that instead of moving the paddle, it fills in the area it travels to. Through various trials and error of adapting and trying different methods I don't think the paddle is being elongated (adding pixels to the height), but it seems like a new paddle object is being created rather than the one being moved.
I've looked it over and over again (you guys aren't a first-ditch effort), but can't seem to figure out what's happening. Any help would be much appreciated.
// Requests a callback 60 times per second from browser
var animate = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) { window.setTimeout(callback, 1000/60) };
// Get canvas and set context
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillStyle = "white";
// Settle variables for canvas width and height
var canvas_width = 500;
var canvas_height = 400;
// Set varaibles for paddle width and height
var paddle_width = 15;
var paddle_height = 75;
// Initializes variables
var playerScore = 0;
var computerScore = 0;
var player = new Player();
var computer = new Computer();
var ball = new Ball((canvas_width/2),(canvas_height/2));
// Renders the pong table
var render = function() {
player.render();
computer.render();
ball.render();
};
var update = function() {
player.update();
};
// Callback for animate function
var step = function() {
update();
render();
animate(step);
};
// Creates paddle object to build player and computer objects
function Paddle(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.x_speed = 0;
this.y_speed = 0;
};
function Player() {
this.paddle = new Paddle(1, ((canvas_height/2) - (paddle_height/2)), paddle_width, paddle_height);
};
function Computer() {
this.paddle = new Paddle((canvas_width - paddle_width - 1), ((canvas_height/2) - (paddle_height/2)), paddle_width, paddle_height);
};
// Creates ball object
function Ball(x, y) {
this.x = x;
this.y = y;
this.radius = 10;
};
// Adds render functions to objects allowing them to be drawn on canvas
Ball.prototype.render = function() {
context.beginPath();
context.arc(this.x, this.y, this.radius, Math.PI * 2, false);
context.fillStyle = "white";
context.fill();
context.closePath();
};
Paddle.prototype.render = function() {
context.fillStyle = "white";
context.fillRect(this.x, this.y, this.width, this.height);
};
Player.prototype.render = function() {
this.paddle.render();
};
// Appends a move method to Paddle prototype
Paddle.prototype.move = function(x, y) {
this.y += y;
this.y_speed = y;
};
// Updates the location of the player paddle
Player.prototype.update = function() {
for(var key in keysDown) {
var value = Number(key);
if(value == 38) {
this.paddle.move(0, -4);
} else if (value == 40) {
this.paddle.move(0, 4);
} else {
this.paddle.move(0, 0);
}
}
};
Computer.prototype.render = function() {
this.paddle.render();
};
// Draws center diving line
context.strokeStyle = "white";
context.setLineDash([5, 3]);
context.beginPath();
context.moveTo((canvas_width/2), 0);
context.lineTo((canvas_width/2), canvas_height);
context.stroke();
context.closePath();
// Draws score on canvas
context.font = "40px Arial";
context.fillText('0', (canvas_width * .23), 50);
context.fillText('0', (canvas_width * .73), 50);
window.onload = function() {
animate(step);
};
var keysDown = {};
window.addEventListener("keydown", function(event) {
keysDown[event.keyCode] = true;
});
window.addEventListener("keyup", function(event) {
delete keysDown[event.keyCode];
});
My apologies: I cut the html/css code and meant to paste it, but forgot.
pong.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Pong</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas" width="500" height="400"></canvas>
<script src="main.js"></script>
</body>
</html>
style.css:
#canvas {
background-color: black;
}
The canvas itself has no "objects", it's just a bitmap, and anything you draw on it just changes the colours of certain pixels, making it look like it's drawing "on top" of what's already there but it doesn't even do that. It just flips pixel colours.
I don't see any code that "resets" the canvas for your next frames, so you're literally just drawing the same paddle at a different height value by colouring different pixels with the paddle's colours without recolouring the original pixels using the background colour.
The easiest solution here is to add a context.clearRect(0, 0, canvas.width, canvas.height); at the start of render():
var render = function() {
// clear the canvas so we can draw a new frame
context.clearRect(0,0,canvas.width,canvas.height);
// draw the frame content to the bitmap
player.render();
computer.render();
ball.render();
};
Note that this reveals you also need to draw your scores and center line every frame. Either that, or you need to make sure your paddles (and your ball) first restore the background colour on their old position, before drawing themselves on their new position, which would require considerably more code.
I'm trying to get an image to oscillate. But i'm having some issues. I'm using this tutorial http://www.html5canvastutorials.com/advanced/html5-canvas-oscillation-animation/
and I tried changing line 55-61 of the tutorial to load the image src. But it's not displaying anything.
Any advice?
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle, context) {
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = '#8ED6FF';
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = 'black';
context.stroke();
}
function animate(myRectangle, canvas, context, startTime) {
// update
var time = (new Date()).getTime() - startTime;
var amplitude = 150;
// in ms
var period = 2000;
var centerX = canvas.width / 2 - myRectangle.width / 2;
var nextX = amplitude * Math.sin(time * 2 * Math.PI / period) + centerX;
myRectangle.x = nextX;
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// draw
drawRectangle(myRectangle, context);
// request new frame
requestAnimFrame(function() {
animate(myRectangle, canvas, context, startTime);
});
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myRectangle = new Image();
myRectangle.src = "http://www.skilledsoldiers.com/e107_plugins/aacgc_gamelist/icons/dota2_icon.png";
myRectangle.onload = function()
};
drawRectangle(myRectangle, context);
// wait one second before starting animation
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(myRectangle, canvas, context, startTime);
}, 1000);
</script>
You need to use context.drawImage instead of trying to draw a rectangle with an image.
function drawImage(myRectangle, context) {
context.drawImage(myRectangle.img, myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
}
See this fiddle: http://jsfiddle.net/fb4vS/
I'm trying to do a js app that would basically move some balls on a canvas element. I set the context.fillStyle = "rgba(12, 34, 56, 0.2)"; the problem is that the balls become opaque from transparent after a short period of time. How can I maintain their transparency and why do they become opaque?
here is simplified version of my code:
function startScript(){
var layer1 = document.getElementById("layer1");
var context1 = layer1.getContext("2d");
var posX = 5;
context1.fillStyle = "rgba(12, 34, 56, 0.05)";
animate();
function animate() {
posX+=3;
context1.arc(posX, 200, 5, 0, Math.PI*2);
context1.fill();
// request new frame
requestAnimFrame(function() {
animate();
});
}
}
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
You have to use context1.beginPath before your new line draws
Otherwise, the context remembers and redraws the previous arc in addition to the new arc.
Also, you should do context1.closePath() after drawing a circle-arc.
Otherwise the context is drawing an unclosed arc instead of a circle.
context1.beginPath();
context1.arc(posX, 200, 5, 0, Math.PI*2);
context1.closePath();
context1.fill();
I tried to make some simply game using requestAnimFrame but animation doesn't work and I don't know why. Maybe some one can help? Here is the code:
// requestAnimationFrame() shim by Paul Irish
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
//Create canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 640;
canvas.height = 480;
document.body.appendChild(canvas);
// The main game loop
var lastTime;
function main() {
var now = Date.now();
var dt = now - lastTime;
draw();
update(dt);
lastTime = now;
requestAnimFrame(main);
}
main();
function ball(){
this.radius = 5;
this.x = 300;
this.y = 50;
this.vx = 200;
this.vy = 200;
this.ax = 0;
this.ay = 0;
this.color = "red";
this.draw = function(){
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc( this.x, this.y, this.radius, 0, 2 * Math.PI );
ctx.fill();
};
}
function draw() {
newBall = new ball();
newBall.draw();
}
function update(dt) {
newBall = new ball();
newBall.x += newBall.vx * dt;
}
In update(dt) function ball dosen't move and I don't know why...
There are several errors in your code:
You're initializing variables outside of a function, always use an initializer (immediately invoked function) for that.
As mentioned by kalley you are creating a new ball at the starting position for every draw instead of using a global object.
Even if your ball would draw correctly it would be outside the drawing area within the next frame because Date.now() is measured in seconds (use .getMilliseconds()).
Lastly the ball stays at the same position because the canvas isn't cleaned up after each draw.
what you're looking for:
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
theBall.draw();
}
There are several other things but this fiddle should do for now.
I'm trying to make a simple animation for cow with HTML5 canvas. The code works for Google Chrome but does not work in Mozilla Firefox, Safari etc. My function (code) is given below:
function animalView(objectToMove) {
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
this.a = 0;
(function() {
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
(function drawFrame() {
window.requestAnimationFrame(drawFrame, canvas);
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
this.a += 10;
objectToMove.tail = Math.sin( this.a );
objectToMove.draw(context);
context.restore();
}());
}
I noticed that the value of this.a is not being remembered when the call back function calls function().