I want to move the rectangle horizontally,however,it enters the updateStageObjects() function several times but does not update the value of myRectangle.x.How do I fix this?
<script type="text/javascript">
var interval = 10;
var x=0;
var y=0;
var myRectangle;
var context ;
var canvas;
function Rectangle(x, y, width, height, borderWidth) {
this.x=x;
this.y=y;
this.width = width;
this.height = height;
this.borderWidth = borderWidth;
}
function DrawRects(){
myRectangle = new Rectangle (250,70,100,50, 5); 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 updateStageObjects() {
var amplitude = 150;
var centerX = 240;
myRectangle.x += 100;
alert(myRectangle.x+" "+myRectangle.y);
}
function clearCanvas() {
context.clearRect(0,0,canvas.width, canvas.height);
}
function DrawRect(){
setTimeout(CheckCanvas,10);
clearCanvas();
updateStageObjects();
DrawRects();
}
function CheckCanvas(){
return !!(document.createElement('canvas').getContext);
}
function CheckSound(){
return !!(document.createElement('sound').canPlayType)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function Checkstorage(){
return !!(window.localStorage)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function DrawCanvas(){
if (CheckCanvas()){
canvas = document.getElementById('Canvas');
DrawRects();
setInterval(DrawRect, 10);
}
}
</script>
html
<canvas id="Canvas" width="800px" height="800px" onclick="DrawCanvas()"> Nor supported</canvas>
As Chris has pointed out your DrawRects() always draws the same co-ords, try adding a couple more variables like
var dx = 250;
var dy = 70;
Then change your new Rectangle to
myRectangle = new Rectangle (dx,dy,100,50, 5);
Next change your myRectangle.x += 100 line to
dx += 100;
Hope this helps.
Every time you call updateStageObjects(), it is followed immediately by a call to DrawRects(), which creates a new rectangle at exactly (250,70,100,50, 5). So you'll never notice it increment by 100.
You'll need to pass some numbers back and forth between these functions if you want one of them to remember the changes made in another.
Related
So, I have one line that bounce from walls of my border while changing colours. But now I must create the second, white line, that will go like 3 or 4 seconds after first line erasing it. So it will be only 4 second lenght colour line bouncing from walls. And I have no idea how to do it. I already tried to use setTimeout, creating multiple functions etc.
var ctx=document.getElementById("canvas1").getContext("2d");
ctx.strokeStyle="red";
ctx.lineWidth=1;
var x=0
var y=0
var dx=1
var dy=1
function rysuj(){
ctx.strokeStyle="#"+((1<<24)*Math.random()|0).toString(16);
ctx.beginPath()
ctx.moveTo(x,y);
ctx.lineTo(x+dx,y+dy);
ctx.stroke();
if(x>200||x<0) dx=-dx;
if(y>150||y<0) dy=-dy;
x=x+dx;
y=y+dy;
}
setInterval ('rysuj()', 5);
<canvas id="canvas1" style="width:1000px; height:500px; border-style:solid;">
</canvas>
Looks like the key is to have two draw functions (note, this isn't ideal, but it works) and always have the "white" function explicitly set the strokeStyle. This is because the context for both draw functions is retrieved from the same canvas, and unless you explicitly set it on the "white" draw, it will be whatever it was from the previous "red" draw.
See below:
var getCanvasContext = function(strokeColor) {
var ctx = document.getElementById("canvas1").getContext("2d");
ctx.strokeStyle=strokeColor;
ctx.lineWidth=1;
return {ctx: ctx, x: 0, y:0, dx:1, dy:1, change: strokeColor !== "white"};
}
var drawRed = function(canvasContext) {
var ctx = canvasContext.ctx,
x = canvasContext.x,
y = canvasContext.y,
dx = canvasContext.dx,
dy = canvasContext.dy;
if (canvasContext.change) {
ctx.strokeStyle="#"+((1<<24)*Math.random()|0).toString(16);
}
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x+dx, y+dy);
ctx.stroke();
if(x>200||x<0) dx=-dx;
if(y>150||y<0) dy=-dy;
x=x+dx;
y=y+dy;
canvasContext.ctx = ctx;
canvasContext.x = x;
canvasContext.y = y;
canvasContext.dx = dx;
canvasContext.dy = dy;
};
var drawWhite = function(canvasContext) {
var ctx = canvasContext.ctx,
x = canvasContext.x,
y = canvasContext.y,
dx = canvasContext.dx,
dy = canvasContext.dy;
ctx.strokeStyle="#ffffff";
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x+dx, y+dy);
ctx.stroke();
if(x>200||x<0) dx=-dx;
if(y>150||y<0) dy=-dy;
x=x+dx;
y=y+dy;
canvasContext.ctx = ctx;
canvasContext.x = x;
canvasContext.y = y;
canvasContext.dx = dx;
canvasContext.dy = dy;
};
var redContext = getCanvasContext("red");
var whiteContext = getCanvasContext("white");
setInterval(function() {
drawRed(redContext);
}, 5);
setTimeout(function() {
setInterval(function() {
drawWhite(whiteContext)
}, 5);
}, 4000);
Hopefully this helps (see fiddle: JSFiddle Link)
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.
Right now my code works like I want it to but when I created my timer to redraw the triangle it overlayed a new triangle every time it was called, so to stop this I put clearRect in, but now it clears the entire canvas negating my fill of black that I have. How can I either add a new timer that still provides the same effect of moving triangles but that doesn't require clearRect or how can I fix what I have to have the background of the canvas stay black but not overlay new triangles every time? Any help is appreciated!
Edit: I also tried two different timers together instead of a timer for handleClick, but got weird results with the speed of the triangles, does anyone know why that is?:
timer = setInterval(init, 30);
timer = setInterval(Triangle, 30);
Code:
<html>
<head>
<script>
var canvas;
var context;
var triangles = [];
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
resizeCanvas();
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
canvas.onclick = function(event) {
handleClick(event.clientX, event.clientY);
};
timer = setInterval(handleClick, 30);
}
function Triangle(x,y,color) {
this.x = x;
this.y = y;
this.color = color;
this.vx = Math.random() * 10 - 5; //5-3
this.vy = Math.random() * 10 - 5;
for (var i=0; i < triangles.length; i++) {
var t = triangles[i];
t.x += t.vx;
t.y += t.vy;
if (t.x + t.vx > canvas.width || t.x + t.vx < 0)
t.vx = -t.vx;
if (t.y + t.vy > canvas.height || t.y + t.vy < 0)
t.vy = -t.vy;
}
}
function handleClick(x,y) {
context.clearRect(0,0, canvas.width,canvas.height);
var colors = ['red','green','purple','blue','yellow'];
var color = colors[Math.floor(Math.random()*colors.length)];
triangles.push(new Triangle(x, y, color));
for(i=0; i < triangles.length; i++) {
drawTriangle(triangles[i]);
}
}
function drawTriangle(triangle) {
context.beginPath();
context.moveTo(triangle.x,triangle.y);
context.lineTo(triangle.x + 50,triangle.y + 50);
context.lineTo(triangle.x + 50,triangle.y - 50);
context.fillStyle = triangle.color;
context.fill();
}
function resizeCanvas() {
canvas.width = window.innerWidth-10;
canvas.height = window.innerHeight-10;
fillBackgroundColor();
for(i=0; i < triangles.length; i++) {
drawTriangle(triangles[i]);
}
}
function fillBackgroundColor() {
context.fillStyle = 'black';
context.fillRect(0,0,canvas.width,canvas.height);
}
window.onload = init;
</script>
</head>
<body>
<canvas id="canvas" width="500" height="500">
</body>
</html>
I spent a few minutes reading threw your code, and found one thing that stood out to me. To begin, when you call the timer = setInterval(handleClick, 30); the commands are run from top to bottom in the handleClick function. So when we look at that function, the first thing you draw is the black background. Then, you push out a brand new triangle. Following this, you draw all the triangles in the array using a loop. This is where the issue is. What you are doing is drawing all the past triangles, ontop of the refreshed black rectangle.
Try setting your code to something like this.
function handleClick(x,y) {
context.clearRect(0,0, canvas.width,canvas.height);
var colors = ['red','green','purple','blue','yellow'];
var color = colors[Math.floor(Math.random()*colors.length)];
triangles.push(new Triangle(x, y, color));
triangles.shift(); //This removes the first point in the array, and then shifts all other data points down one index.
for(i=0; i < triangles.length; i++) {
drawTriangle(triangles[i]);
}
}
Pleaase let me know if I miss interpreted any of your code, or if you have a follow up question.
I want to put an image instead of red rectangles in my function that draws enemies.
function drawEnemy(x,y){
ctx.fillStyle= "red";
ctx.fillRect(x,y,50,50);
}
This is the interval/loop im trying to run it in:
var timer = setInterval(function(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle= "yellow";
ctx.fillRect(xPos,yPos,10,150);
drawPikachu(x,y);
drawEnemy(enemyX, enemyY);
yPos -= moveY;
enemyY -= enemyMoveY;
if(enemyY > drawSurface.height ||
collisionCheck(enemyX,enemyY,enemySize,xPos,yPos,30)) {
enemyY = -50;
enemyX = Math.ceil(Math.random()*(drawSurface.width-50));
}
},50)
;
A simple Google, found a seemingly suitable answer:
window.onload = function() {
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("scream");
ctx.drawImage(img,10,10);
};
Source: http://www.w3schools.com/tags/canvas_drawimage.asp
You just have to get a ref to an image, and draw it using the canvas context.
you need a context reference to draw it:
// prepare your enemy sprite once
var enemyImg = document.getElementById('enemy');
function drawEnemy(x, y, ctx) {
// desired dimensions of the enemy sprite
var width = 100
var height = 100
// draw enemy sprite
ctx.drawImage(enemyImg, x, y, width, height);
}
I wanted a rectangle to move horizontally..However, the rectangle is not animating..How do I fix this?
<script type="text/javascript">
var interval = 10;
var x=0;
var y=0;
var rect = null;
var context ;
var canvas;
function Rectangle(x, y, width, height, borderWidth) {
this.x=x;
this.y=y;
this.width = width;
this.height = height;
this.borderWidth = borderWidth;
}
function DrawRects(){
myRectangle = new Rectangle (250,70,100,50, 5);
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 updateStageObjects() {
var amplitude = 150;
var centerX = 240;
var nextX = myRectangle.x+ 10;
myRectangle.x = nextX;
}
function clearCanvas() {
context.clearRect(0,0,canvas.width, canvas.height);
}
function DrawRect(){
alert("Test1");
setTimeout(CheckCanvas,10);
//clearCanvas();
updateStageObjects();
DrawRects();
alert("Test2");
}
function CheckCanvas(){
return !!(document.createElement('canvas').getContext);
}
function CheckSound(){
return !!(document.createElement('sound').canPlayType)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function Checkstorage(){
return !!(window.localStorage)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function DrawCanvas(){
if (CheckCanvas()){
canvas = document.getElementById('Canvas');
context =canvas.getContext('2d');
$('#Result').text('Canvas supported...');
$('#Result').text($('#Result').text()+'Sound supported...'+CheckSound());
$('#Result').text($('#Result').text()+'Video supported...'+CheckVideo());
$('#Result').text($('#Result').text()+'Storage supported...'+Checkstorage());
DrawRects();
setInterval(DrawRect(), 10);
}
}
</script>
Html:
<canvas id="Canvas" width="800px" height="800px" onclick="DrawCanvas()"> Nor supported</canvas>
You need to do
setInterval(DrawRect, 10);
Using DrawRect() will invoke the function once, and then try to call the result of that function, as a function (which it isn't) every 10 milliseconds.