How to rotate/transform image using arrow keys - javascript

I'm relatively new to canvas and I'm trying to make a space ship type game. I have everything else I'd like down, except for the ship turning itself. I want to make the image of the ship rotate when the arrow keys are clicked.
So if the left arrow key is clicked, it will turn to face the left, and the right arrow key is clicked it will turn to face the right, and so on. I really can't figure this out, if anyone can show me how to do this I would really appreciate it.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
/*Variable to store score*/
var score = 0;
/*Variable that stores the players object properties*/
var x = 50;
var y = 100;
var speed = 6;
var sideLength = 50;
/*Flags to track when keypress is active*/
var down = false;
var up = false;
var left = false;
var right = false;
/*Variables that store target position and size*/
var targetX = 0;
var targetY = 0;
var targetLength = 25;
/*If a number is within range b to c*/
function isWithin(a, b, c) {
return (a > b && a < c)
}
var countDown = 30;
/*Id to track set time*/
var id = null;
/*Listening for if one of the keys is pressed*/
canvas.addEventListener('keydown', function (event) {
event.preventDefault();
console.log(event.key, event.keyCode);
if (event.keyCode === 40) {
down = true;
}
if (event.keyCode === 38) {
up = true;
}
if (event.keyCode === 37) {
left = true;
}
if (event.keyCode === 39) {
right = true;
}
});
/*Listening for if one of the keys is released*/
canvas.addEventListener('keyup', function (event) {
event.preventDefault();
console.log(event.key, event.keyCode);
if (event.keyCode === 40) {
down = false;
}
if (event.keyCode === 38) {
up = false;
}
if (event.keyCode === 37) {
left = false;
}
if (event.keyCode === 39) {
right = false;
}
});
/*Function to show menu*/
function menu() {
erase();
context.fillStyle = '#000000';
context.font = '36px Arial';
context.textAlign = 'center';
context.fillText('Collect The Thing', canvas.width / 2, canvas.height / 4);
context.font = '30px Arial';
context.fillText('Press to Start', canvas.width / 2, canvas.height / 2);
/*Listen for click to start game*/
canvas.addEventListener('click', startGame);
}
/*Function to start the game*/
function startGame() {
/*reduce the countdown timer every 1 second*/
id = setInterval(function () {
countDown--;
}, 1000)
/*remove click events*/
canvas.removeEventListener('click', startGame);
moveTarget();
draw();
}
/*Show game over screen*/
function endGame() {
/*stop the countdown*/
clearInterval(id);
/*clear game board*/
erase();
context.fillStyle = '#000000';
context.font = '36px Arial';
context.textAlign = 'center';
context.fillText('Finale Score: ' + score, canvas.width / 2, canvas.height / 4);
}
/*Move target to random location in canvas*/
function moveTarget() {
targetX = Math.round(Math.random() * canvas.width - targetLength);
targetY = Math.round(Math.random() * canvas.height - targetLength);
}
/*Clear the Canvas*/
function erase() {
context.fillStyle = '#FFFFFF';
context.fillRect(0, 0, 600, 500);
}
/*Main animation drawing loop with game logic*/
function draw() {
erase();
/*Move the player sqaure*/
if (down) {
y += speed;
}
if (up) {
y -= speed;
}
if (right) {
x += speed;
}
if (left) {
x -= speed;
}
if (y + sideLength > canvas.height) {
y = canvas.height - sideLength;
}
if (y < 0) {
y = 0;
}
if (x < 0) {
x = 0;
}
if (x + sideLength > canvas.width) {
x = canvas.width - sideLength;
}
/*Collide with target*/
if (isWithin(targetX, x, x + sideLength) || isWithin(targetX + targetLength, x, x + sideLength)) {
if (isWithin(targetY, y, y + sideLength) || isWithin(targetY + targetLength, y, y + sideLength)) {
/*respawn target in a random location*/
moveTarget();
/*Increase score by 1*/
score++;
}
}
//Draw player object
context.fillRect(x, y, sideLength, sideLength);
context.drawImage(baseImage, x, y, sideLength, sideLength);
/*Draw target sqaure*/
context.fillStyle = '#00FF00';
context.fillRect(targetX, targetY, targetLength, targetLength);
//Timer and Score
context.fillStyle = '#000000';
context.font = '24px Arial';
context.textAlign = 'left';
context.fillText('Score: ' + score, 10, 24);
context.fillText('Time Remaining: ' + countDown, 10, 50);
if (countDown <= 0) {
endGame();
} else {
window.requestAnimationFrame(draw);
}
}
baseImage= new Image();
baseImage.src='xwing3.png';
baseImage.onload= function() {
menu();
}
canvas.focus();

I think in this regard you have two options.
You could have a sprite for every direction that you want the ship to face, then when you draw the image, you could choose the sprite that matches.
if(left == true) {baseImage.src='xwing3left.png';}
You could use the canvas rotate() method. This would make things more complicated, but it actually rotates the canvas and could give more opportunity to experiment.
It actually applies a transformation matrix to the canvas before it draws so you could do things like:
context.rotate(45);
context.fillRect(x,y,width,height);
Just be careful, because rotate always occurs around the origin, so you might need to use translate() as well to make it work the way you expect.
Hope this helps! :)

Related

How to stop an object from jumping past a certain point?

Catbus game
I'm trying to make my cat only jump once until it lands back on the ground. I've tried to add a statement that makes it only go to a certain point, but the velocity keeps working against it. It begins to act like a basketball that has been bounced to much. I wouldn't want to add a collider (even though I have debated it). It would just make it worse...
The code is as follows:
let img; //background
var bgImg; //also the background
var x1 = 0;
var x2;
var scrollSpeed = 4; //how fast background is
let bing; //for music
let cat;
var mode; //determines whether the game has started
let gravity = 0.2; //jumping forces
let velocity = 0.1;
let upForce = 6;
let startY = 730; //where cat bus jumps from
let startX = 70;
var font1; //custom fonts
var font2;
p5.disableFriendlyErrors = true; //avoids errors
function preload() {
bgImg = loadImage("backgwound.png"); //importing background
bing = loadSound("catbus theme song.mp3"); //importing music
font1 = loadFont("Big Font.TTF");
font2 = loadFont("Smaller Font.ttf");
}
function setup() {
createCanvas(1000, 1000); //canvas size
img = loadImage("backgwound.png"); //background in
x2 = width;
bing.loop(); //loops the music
cat = {
//coordinates for catbus
x: startX,
y: startY,
};
catGif = createImg("catgif.gif"); //creates catbus
catGif.position(cat.x, cat.y); //creates position
catGif.size(270, 100); //creates how big
mode = 0; //game start
textSize(50); //text size
}
function draw() {
let time = frameCount; //start background loop
image(img, 0 - time, 0);
image(bgImg, x1, 2, width, height);
image(bgImg, x2, 2, width, height);
x1 -= scrollSpeed;
x2 -= scrollSpeed;
if (x1 <= -width) {
x1 = width;
}
if (x2 <= -width) {
x2 = width;
} //end background loop
fill("white"); //text colour
if (mode == 0) {
textSize(20);
textFont(font1);
text("press SPACE to start the game!", 240, 500); //what text to type
}
if (mode == 0) {
textSize(35);
textFont(font2);
text("CATBUS BIZZARE ADVENTURE", 90, 450); //what text to type
}
cat.y = cat.y + velocity; //code for jumping
velocity = velocity + gravity;
if (cat.y > startY) {
velocity = 0;
// cat.y = startY;
}
catGif.position(cat.x, cat.y);
}
function keyPressed() {
if (keyCode === 32) { //spacebar code
// if ((cat.y = 730)) {
// cat.y > 730;
mode = 1;
velocity += -upForce;
}
// }
}
You can simply do this to the keyPressed function
function keyPressed() {
if (keyCode === 32 && velocity == 0) { //spacebar code
// if ((cat.y = 730)) {
// cat.y > 730;
mode = 1;
velocity += -upForce;
}
}

can not rotate a rectangular shape in canvas

I am new in HTML5 canvas. I am trying to build game area using HTML canvas where someone can drive around a car inside
Canvas area like if I press the left arrow key the car will turn to the left and if press the right arrow key the car will turn to the right side. And up and down arrow keys are responsible for moving the car upward or downward. And the car must stay within the canvas area. Here, I use rotate method to turn the car right or left. But it is not working, actually the car is getting away from the canvas and behaving like a crap.
Anyone has any idea to solve the problem? I am totally stuck here. Thanks in advance.
Initially I am displaying a rectangle instead of car.
My js file is given below.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = innerWidth - 100;
canvas.height = innerHeight - 100;
const canvasW = canvas.width;
const canvasH = canvas.height;
let upPressed = false,
downPressed = false,
rightPressed = false,
leftPressed = false;
class PlayerCar {
constructor(carX, carY, carWidth, carHeight) {
this.carX = carX;
this.carY = carY;
this.carWidth = carWidth;
this.carHeight = carHeight;
}
draw() {
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.rect(this.carX, this.carY, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
}
}
const playerCar = new PlayerCar(100, 100, 40, 60);
playerCar.draw();
function navigation() {
const handleKeyDown = (e) => {
if (e.key === "ArrowUp") {
upPressed = true;
}
if (e.key === "ArrowDown") {
downPressed = true;
}
if (e.key === "ArrowRight") {
rightPressed = true;
}
if (e.key === "ArrowLeft") {
leftPressed = true;
}
};
const handleKeyUp = (e) => {
if (e.key === "ArrowUp") {
upPressed = false;
}
if (e.key === "ArrowDown") {
downPressed = false;
}
if (e.key === "ArrowRight") {
rightPressed = false;
}
if (e.key === "ArrowLeft") {
leftPressed = false;
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvasW, canvasH);
if (upPressed) {
playerCar.carY -= 5;
}
if (downPressed) {
playerCar.carY += 5;
}
if (leftPressed) {
ctx.save();
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate((Math.PI / 180) * 0.2);
playerCar.carX -= 5;
ctx.restore();
}
if (rightPressed) {
ctx.save();
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate((Math.PI / 180) * -0.2);
playerCar.carX += 5;
ctx.restore();
}
if (playerCar.carX < 0) playerCar.carX = 0;
if (playerCar.carX > canvasW - playerCar.carWidth)
playerCar.carX = canvasW - playerCar.carWidth;
if (playerCar.carY < 0) playerCar.carY = 0;
if (playerCar.carY > canvasH - playerCar.carHeight)
playerCar.carY = canvasH - playerCar.carHeight;
playerCar.draw();
}
function startGame() {
animate();
}
startGame();
navigation();
I would first move all of the update info to a method in the car class vice doing it in the animate loop.
This is where cos and sin come in and getting familiar with angles. You also must understand the canvas relation the the object it draws is always at (x, y) of (0, 0) unless you translate it to the center. To do that draw your object in this manner:
ctx.fillStyle = "blue";
ctx.save();
ctx.beginPath();
ctx.translate(this.carX, this.carY)
ctx.rotate(this.angle)
ctx.rect(-this.carWidth/2, -this.carHeight/2, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
ctx.restore();
Use of save() and restore() are a must unless you want to translate and rotate you object back to its original. It's the same ting but simpler. So now I am translating the car around the canvas and the car itself is drawn at negative half the width and height to ensure the canvas (0, 0) corner is in the center of the car. This is because canvas always rotates from the top-left corner.
Now create a method called update() and put you control logic in there:
update() {
if (rightPressed) {
this.angle += this.rot
} else if (leftPressed) {
this.angle -= this.rot
}
if (upPressed) {
this.carX += Math.cos(this.angle+toRadians(-90)) * 5;
this.carY += Math.sin(this.angle+toRadians(-90)) * 5;
}
}
Be aware I added angle and rot to the constructor also. What this is doing is when you press left or right the car rotate accordingly. As for pressing up we are going to translate it by the rotation. Since this would normally make the car drive to the right we have to also add -90 degrees to the current angle to ensure the car drives forwards. Just remove +toRadians(-90) and see what happens.
Multiplying it by 5 is an arbitrary number for speed. You can even make it part of the constructor and set it there. i.e. this.speed = 5
Doing the same thing for downPressed but instead use +toRadians(90)
toRadians() is just a simple function added to your code to convert degrees to radians.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
const canvasW = canvas.width;
const canvasH = canvas.height;
let upPressed = false,
downPressed = false,
rightPressed = false,
leftPressed = false;
class PlayerCar {
constructor(carX, carY, carWidth, carHeight) {
this.carX = carX;
this.carY = carY;
this.carWidth = carWidth;
this.carHeight = carHeight;
this.angle = 0;
this.rot = 0.1; //control how fast it turns
}
draw() {
ctx.fillStyle = "blue";
ctx.save();
ctx.beginPath();
ctx.translate(this.carX, this.carY)
ctx.rotate(this.angle)
ctx.rect(-this.carWidth/2, -this.carHeight/2, this.carWidth, this.carHeight);
ctx.fill();
ctx.closePath();
ctx.restore();
}
update() {
if (rightPressed) {
this.angle += this.rot
} else if (leftPressed) {
this.angle -= this.rot
}
if (upPressed) {
this.carX += Math.cos(this.angle+toRadians(-90)) * 5;
this.carY += Math.sin(this.angle+toRadians(-90)) * 5;
}
if (downPressed) {
this.carX += Math.cos(this.angle+toRadians(90)) * 5;
this.carY += Math.sin(this.angle+toRadians(90)) * 5;
}
}
}
function toRadians(deg) {
return (deg * Math.PI) / 180;
}
const playerCar = new PlayerCar(100, 100, 40, 60);
playerCar.draw();
function navigation() {
const handleKeyDown = (e) => {
if (e.key === "ArrowUp") {
upPressed = true;
}
if (e.key === "ArrowDown") {
downPressed = true;
}
if (e.key === "ArrowRight") {
rightPressed = true;
}
if (e.key === "ArrowLeft") {
leftPressed = true;
}
};
const handleKeyUp = (e) => {
if (e.key === "ArrowUp") {
upPressed = false;
}
if (e.key === "ArrowDown") {
downPressed = false;
}
if (e.key === "ArrowRight") {
rightPressed = false;
}
if (e.key === "ArrowLeft") {
leftPressed = false;
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvasW, canvasH);
if (playerCar.carX < 0) playerCar.carX = 0;
if (playerCar.carX > canvasW - playerCar.carWidth)
playerCar.carX = canvasW - playerCar.carWidth;
if (playerCar.carY < 0) playerCar.carY = 0;
if (playerCar.carY > canvasH - playerCar.carHeight)
playerCar.carY = canvasH - playerCar.carHeight;
playerCar.draw();
playerCar.update();
}
function startGame() {
animate();
}
startGame();
navigation();
<canvas></canvas>
To be clear on why your code is not doing what you expect think about this. You are trying to translate and rotate the context without ever accessing the object. If you were to add ctx.fillRect() to your animate loop would you think it's going to just know that you want to change the car? Same goes for translate and rotate. Try adding a fillStyle and fillRect to your rightPressed
if (rightPressed) {
ctx.save();
playerCar.carX += 5;
ctx.translate(
playerCar.carX + playerCar.width / 2,
playerCar.carY + playerCar.height / 2
);
ctx.rotate(45);
ctx.fillStyle = 'grey'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.restore();
}
You will see when you press right the context does what you want just not the context of the object. This is why adding it directly top the class should be done. Now you are specifically targeting the object you want.

Variable does not go into local storage and does not appear on other page. (JavaScript/HTML)

I am trying to create a scoreboard for my game by using local storage to carry over the score variable after a game is finished by a user. However, this is not working for some reason. I am relatively new to coding so I did some research on local storage but couldn't get the code to work to no avail. Could someone help me with this code thanks.
Page 1:
<html>
<title>Level Selector</title>
<canvas id="myCanvas" width="750" height="400"></canvas>
<style type="text/css">
canvas { background: #eee; }
</style>
<script>
document.addEventListener('load', draw);
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;//Ball is moving in x direction at a constant rate
var dy = -2;//Ball is moving in y direction at a constant rate
var ballRadius = 10;//To see if ball is colliding with brick/canvas
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;//This variable is false because the 'right arrow' key is not pressed.
var leftPressed = false;//This variable is false because the 'left arrow' key is not pressed.
var brickRowCount = 5;
var brickColumnCount = 8;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var paused = false;
var bricks = [];//this is an array holding all the bricks
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };//If status is '1' then draw it. However, is status is '0', fill in with background
}
}
document.addEventListener("keydown", keyDownHandler, false);//Functions only when key is pressed
document.addEventListener("keyup", keyUpHandler, false);//Functions only when key is not pressed
document.addEventListener("mousemove", mouseMoveHandler, false);//Functions only when mouse curcor moves
//keyCode(39) is the code for the 'right arrow' key and keyCode(37) is the code for the 'left arrow' key
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;//This represents the hoizontal mouse movement.
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
window.addEventListener('keydown', pauseGameKeyHandler, false);
function pauseGameKeyHandler(e) {
var keyCode = e.keyCode;
switch(keyCode){
case 80: //p
togglePause();
break;
}
}
function togglePause() {
paused = !paused;
draw();
}
/*************************************************************/
// NEW
const ballPowerupHalfWidth = 30;
const paddlePowerupHalfWidth = 30;
let ballPowerups = [];
let paddlePowerups = [];
// This function adds powerup to random position
function addPowerups() {
// I check only if none exist, you could
// add more than 1 powerup if you want
if (ballPowerups.length < 1) {
// otherwise half the triangle could be outside canvas
const padding = 50;
const xMin = 0 + padding;
const xMax = canvas.width - padding;
const yMin = 0 + padding;
const yMax = canvas.height - padding;
ballPowerups.push({
x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
});
}
// I check only if none exist, you could
// add more than 1 powerup if you want
if (paddlePowerups.length < 1) {
// otherwise half the triangle could be outside canvas
const padding = 50;
const xMin = 0 + padding;
const xMax = canvas.width - padding;
const yMin = 0 + padding;
const yMax = canvas.height - padding;
paddlePowerups.push({
x: Math.floor(Math.random()*(xMax-xMin+1)+xMin),
y: Math.floor(Math.random()*(yMax-yMin+1)+yMin),
});
}
}
// NEW: do all collision detections
function doCollisionDetection() {
// ball powerups
ballPowerups.forEach((powerup, i) => {
rectangleCollisionDetection(
{x: powerup.x, y: powerup.y},
{w: ballPowerupHalfWidth, h: ballPowerupHalfWidth},
() => {
console.log('BALL POWERUP COLLISION');
// remove powerup
ballPowerups.splice(i, 1);
dy = dy/2
setTimeout(() => { dy=2 }, 5000)
// to make effect last 10 seconds:
// 1. add effect
// 2. and setTimeout(() => { /* code that removes effect */ }, 10000);
});
});
// paddle powerups
paddlePowerups.forEach((powerup, i) => {
rectangleCollisionDetection(
{x: powerup.x, y: powerup.y},
{w: ballPowerupHalfWidth, h: ballPowerupHalfWidth},
() => {
console.log('PADDLE POWERUP COLLISION');
// remove powerup
paddlePowerups.splice(i, 1);
paddleHeight = paddleHeight*1.5
paddleWidth = paddleWidth*1.5
setTimeout(() => { paddleHeight=10; }, 10000)
});
});
// bricks
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
rectangleCollisionDetection(b, {w: brickWidth, h: brickHeight}, () => {
console.log('BRICK COLLISION');
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, CONGRATULATIONS!");
window.location = "Intro Screen.html";
}
});
}
}
}
// NEW: collision detection between ball and rectangle shaped
// collision boundary (only need center(x, y) and half width)
function rectangleCollisionDetection(center, size, callback) {
if(
x > center.x &&
x < center.x+size.w &&
y > center.y &&
y < center.y+size.h
) {
callback && callback();
}
}
function drawBallpowerup() {
ballPowerups.forEach(powerup => {
ctx.beginPath();
ctx.moveTo(powerup.x, powerup.y);
ctx.lineTo(powerup.x+ballPowerupHalfWidth, powerup.y+ballPowerupHalfWidth);
ctx.lineTo(powerup.x+ballPowerupHalfWidth*2, powerup.y);
ctx.fillStyle = "#42f445";
ctx.fill();
ctx.closePath();
});
}
function drawPaddlepowerup() {
paddlePowerups.forEach(powerup => {
ctx.beginPath();
ctx.moveTo(powerup.x, powerup.y);
ctx.lineTo(powerup.x+paddlePowerupHalfWidth, powerup.y+paddlePowerupHalfWidth);
ctx.lineTo(powerup.x+paddlePowerupHalfWidth*2, powerup.y);
ctx.fillStyle = "#ce6210";
ctx.fill();
ctx.closePath();
});
}
// my big changes end here
/*************************************************************/
//this is the score variable of the game
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
//this is the lives variable of the game
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
//this creates the ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the paddle
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
//this creates the bricks
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
// clears canvas content from previous frame
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();//this code draws the ball onto the canvas
drawPaddle();//this code draws the paddle onto the canvas
drawBricks();//this code draws the bricks onto the canvas
addPowerups();
doCollisionDetection();
drawScore();//this code draws the score variable onto the canvas
drawLives();//this code draws the lives variable onto the canvas
drawBallpowerup();
drawPaddlepowerup();
//Reverse Ball movement when the ball collides with wall in 'x' direction (Left/Right wall)
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
//Reverse Ball movement when the ball collides with wall in 'y' direction (Top/Bottom wall)
if(y + dy < ballRadius) {
dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;//If the ball collides with the paddle, the ball is rebounded in the opposite direction.
}
else {
lives--;
if(!lives) {
alert("GAME OVER");
localStorage.setItem("score", score);
}
window.location = "Intro Screen.html";
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 2;
dy = -2;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {//limits paddle movement in between the canvas width
paddleX += 7;//Paddle shifts 7 pixels in the positive x direction
}
else if(leftPressed && paddleX > 0) {//limits paddle movement in between the canvas width
paddleX -= 7;//Paddle shifts 7 pixels in the negative x direction
}
x += dx;//Ball is updated by painting it over each position it moves in
y += dy;//Ball is updated by painting it over each position it moves in
if(!paused) {
requestAnimationFrame(draw);
}
}
draw();
</script>
<body onload="draw();>
</body>
</html>
Page 2:
if (typeof(Storage) !== "undefined") {
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("score"));
}
When I run it and after playing the game, the score should be added onto the scoreboard in decending order (highest to lowest). I have trouble bringing over the variable.
While there are no standard specifications about it, most browsers will consider different pages served from the file:// protocol as being different-origin.
This means your two pages will be considered as different-origin and will thus have their own Storage Area that they won't be able to share, just like you won't be able to access the Storage Area from www.xxxxx.com from www.yyyyy.com.
To overcome this limitation, the easiest is to run a local web-server on your machine. Many OSes comes with preinstalled such server, and all it requires is to activate it, and for the ones that don't do it, there are many free and easy solutions.
And if you are planning to play with web standards, it's a must have anyway.

How to draw a smooth continuous line with mouse using html canvas and javascript

I'm attempting to create a simple draw/paint programme using html5 canvas and plain javascript. I've got it working ok, but when drawing and moving the mouse too fast the line disconnects and I just end up with a line of dots - how can I make this a smooth continuous line?
Advice would be much appreciated! I'm quite new to JS so code examples would be really useful, thanks in advance.
Current JS is:
var canvas, ctx
var mouseX, mouseY, mouseDown = 0
function draw(ctx,x,y,size) {
ctx.fillStyle = "#000000"
ctx.beginPath()
ctx.arc(x, y, size, 0, Math.PI*2, true)
ctx.closePath()
ctx.fill()
}
function clearCanvas(canvas,ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
function onMouseDown() {
mouseDown = 1
draw(ctx, mouseX, mouseY, 2)
}
function onMouseUp() {
mouseDown = 0
}
function onMouseMove(e) {
getMousePos(e)
if (mouseDown == 1) {
draw(ctx, mouseX, mouseY, 2)
}
}
function getMousePos(e) {
if (!e)
var e = event
if (e.offsetX) {
mouseX = e.offsetX
mouseY = e.offsetY
}
else if (e.layerX) {
mouseX = e.layerX
mouseY = e.layerY
}
}
function init() {
canvas = document.getElementById('sketchpad')
ctx = canvas.getContext('2d')
canvas.addEventListener('mousedown', onMouseDown, false)
canvas.addEventListener('mousemove', onMouseMove, false)
window.addEventListener('mouseup', onMouseUp, false)
}
init();
<canvas id="sketchpad" width="500" height="500"></canvas>
Drawing a smooth curve with the mouse.
Sadly it is not that easy if you wish to stay true to the artists intended line.
It involves recording the whole mouse stroke. When the stroke is complete, reduce the number of points to the detail limit (set by artist) then apply a bezier smoothing function on the remaining points.
It can be done as the stroke is drawn but for some devices this can become too much if the line becomes very long. As the line detail reduction looks at all points when showing the smoothed line live some people dont like the way it slightly changes as the line gets longer.
Demo
The code below demonstrates a solution I have found useful.
Use the left button to draw with smoothing done one button release.
Use the right button to draw with live smoothing (blue line).
Middle mouse button click to clear.
Use the two sliders at the top to set the amount of smoothing, and the amount of detail. Left click to drag out a stroke, the raw line is shown. When the mouse is released the line is then simplified, smoothed, and added to the background image.
var canvas = document.getElementById("canV");
var ctx = canvas.getContext("2d");
// mouse stuff
var mouse = {
x:0,
y:0,
buttonLastRaw:0, // user modified value
buttonRaw:0,
buttons:[1,2,4,6,5,3], // masks for setting and clearing button raw bits;
};
function mouseMove(event){
mouse.x = event.offsetX; mouse.y = event.offsetY;
if(mouse.x === undefined){ mouse.x = event.clientX; mouse.y = event.clientY;}
if(event.type === "mousedown"){ mouse.buttonRaw |= mouse.buttons[event.which-1];
}else if(event.type === "mouseup"){mouse.buttonRaw &= mouse.buttons[event.which+2];
}else if(event.type === "mouseout"){ mouse.buttonRaw = 0; mouse.over = false;
}else if(event.type === "mouseover"){ mouse.over = true; }
event.preventDefault();
}
canvas.addEventListener('mousemove',mouseMove);
canvas.addEventListener('mousedown',mouseMove);
canvas.addEventListener('mouseup' ,mouseMove);
canvas.addEventListener('mouseout' ,mouseMove);
canvas.addEventListener('mouseover' ,mouseMove);
canvas.addEventListener("contextmenu", function(e){ e.preventDefault();}, false);
// Line simplification based on
// the Ramer–Douglas–Peucker algorithm
// referance https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
// points are and array of arrays consisting of [[x,y],[x,y],...,[x,y]]
// length is in pixels and is the square of the actual distance.
// returns array of points of the same form as the input argument points.
var simplifyLineRDP = function(points, length) {
var simplify = function(start, end) { // recursize simplifies points from start to end
var maxDist, index, i, xx , yy, dx, dy, ddx, ddy, p1, p2, p, t, dist, dist1;
p1 = points[start];
p2 = points[end];
xx = p1[0];
yy = p1[1];
ddx = p2[0] - xx;
ddy = p2[1] - yy;
dist1 = (ddx * ddx + ddy * ddy);
maxDist = length;
for (var i = start + 1; i < end; i++) {
p = points[i];
if (ddx !== 0 || ddy !== 0) {
t = ((p[0] - xx) * ddx + (p[1] - yy) * ddy) / dist1;
if (t > 1) {
dx = p[0] - p2[0];
dy = p[1] - p2[1];
} else
if (t > 0) {
dx = p[0] - (xx + ddx * t);
dy = p[1] - (yy + ddy * t);
} else {
dx = p[0] - xx;
dy = p[1] - yy;
}
}else{
dx = p[0] - xx;
dy = p[1] - yy;
}
dist = dx * dx + dy * dy
if (dist > maxDist) {
index = i;
maxDist = dist;
}
}
if (maxDist > length) { // continue simplification while maxDist > length
if (index - start > 1){
simplify(start, index);
}
newLine.push(points[index]);
if (end - index > 1){
simplify(index, end);
}
}
}
var end = points.length - 1;
var newLine = [points[0]];
simplify(0, end);
newLine.push(points[end]);
return newLine;
}
// This is my own smoothing method
// It creates a set of bezier control points either 2nd order or third order
// bezier curves.
// points: list of points
// cornerThres: when to smooth corners and represents the angle between to lines.
// When the angle is smaller than the cornerThres then smooth.
// match: if true then the control points will be balanced.
// Function will make a copy of the points
var smoothLine = function(points,cornerThres,match){ // adds bezier control points at points if lines have angle less than thres
var p1, p2, p3, dist1, dist2, x, y, endP, len, angle, i, newPoints, aLen, closed, bal, cont1, nx1, nx2, ny1, ny2, np;
function dot(x, y, xx, yy) { // get do product
// dist1,dist2,nx1,nx2,ny1,ny2 are the length and normals and used outside function
// normalise both vectors
dist1 = Math.sqrt(x * x + y * y); // get length
if (dist1 > 0) { // normalise
nx1 = x / dist1 ;
ny1 = y / dist1 ;
}else {
nx1 = 1; // need to have something so this will do as good as anything
ny1 = 0;
}
dist2 = Math.sqrt(xx * xx + yy * yy);
if (dist2 > 0) {
nx2 = xx / dist2;
ny2 = yy / dist2;
}else {
nx2 = 1;
ny2 = 0;
}
return Math.acos(nx1 * nx2 + ny1 * ny2 ); // dot product
}
newPoints = []; // array for new points
aLen = points.length;
if(aLen <= 2){ // nothing to if line too short
for(i = 0; i < aLen; i ++){ // ensure that the points are copied
newPoints.push([points[i][0],points[i][1]]);
}
return newPoints;
}
p1 = points[0];
endP =points[aLen-1];
i = 0; // start from second poitn if line not closed
closed = false;
len = Math.hypot(p1[0]- endP[0], p1[1]-endP[1]);
if(len < Math.SQRT2){ // end points are the same. Join them in coordinate space
endP = p1;
i = 0; // start from first point if line closed
p1 = points[aLen-2];
closed = true;
}
newPoints.push([points[i][0],points[i][1]])
for(; i < aLen-1; i++){
p2 = points[i];
p3 = points[i + 1];
angle = Math.abs(dot(p2[0] - p1[0], p2[1] - p1[1], p3[0] - p2[0], p3[1] - p2[1]));
if(dist1 !== 0){ // dist1 and dist2 come from dot function
if( angle < cornerThres*3.14){ // bend it if angle between lines is small
if(match){
dist1 = Math.min(dist1,dist2);
dist2 = dist1;
}
// use the two normalized vectors along the lines to create the tangent vector
x = (nx1 + nx2) / 2;
y = (ny1 + ny2) / 2;
len = Math.sqrt(x * x + y * y); // normalise the tangent
if(len === 0){
newPoints.push([p2[0],p2[1]]);
}else{
x /= len;
y /= len;
if(newPoints.length > 0){
var np = newPoints[newPoints.length-1];
np.push(p2[0]-x*dist1*0.25);
np.push(p2[1]-y*dist1*0.25);
}
newPoints.push([ // create the new point with the new bezier control points.
p2[0],
p2[1],
p2[0]+x*dist2*0.25,
p2[1]+y*dist2*0.25
]);
}
}else{
newPoints.push([p2[0],p2[1]]);
}
}
p1 = p2;
}
if(closed){ // if closed then copy first point to last.
p1 = [];
for(i = 0; i < newPoints[0].length; i++){
p1.push(newPoints[0][i]);
}
newPoints.push(p1);
}else{
newPoints.push([points[points.length-1][0],points[points.length-1][1]]);
}
return newPoints;
}
// creates a drawable image
var createImage = function(w,h){
var image = document.createElement("canvas");
image.width = w;
image.height =h;
image.ctx = image.getContext("2d");
return image;
}
// draws the smoothed line with bezier control points.
var drawSmoothedLine = function(line){
var i,p;
ctx.beginPath()
ctx.moveTo(line[0][0],line[0][1])
for(i = 0; i < line.length-1; i++){
p = line[i];
p1 = line[i+1]
if(p.length === 2){ // linear
ctx.lineTo(p[0],p[1])
}else
if(p.length === 4){ // bezier 2nd order
ctx.quadraticCurveTo(p[2],p[3],p1[0],p1[1]);
}else{ // bezier 3rd order
ctx.bezierCurveTo(p[2],p[3],p[4],p[5],p1[0],p1[1]);
}
}
if(p.length === 2){
ctx.lineTo(p1[0],p1[1])
}
ctx.stroke();
}
// smoothing settings
var liveSmooth;
var lineSmooth = {};
lineSmooth.lengthMin = 8; // square of the pixel length
lineSmooth.angle = 0.8; // angle threshold
lineSmooth.match = false; // not working.
// back buffer to save the canvas allowing the new line to be erased
var backBuffer = createImage(canvas.width,canvas.height);
var currentLine = [];
mouse.lastButtonRaw = 0; // add mouse last incase not there
ctx.lineWidth = 3;
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.clearRect(0,0,canvas.width,canvas.height);
var drawing = false; // if drawing
var input = false; // if menu input
var smoothIt = false; // flag to allow feedback that smoothing is happening as it takes some time.
function draw(){
// if not drawing test for menu interaction and draw the menus
if(!drawing){
if(mouse.x < 203 && mouse.y < 24){
if(mouse.y < 13){
if(mouse.buttonRaw === 1){
ctx.clearRect(3,3,200,10);
lineSmooth.angle = (mouse.x-3)/200;
input = true;
}
}else
if(mouse.buttonRaw === 1){
ctx.clearRect(3,14,200,10);
lineSmooth.lengthMin = (mouse.x-3)/10;
input = true;
}
canvas.style.cursor = "pointer";
}else{
canvas.style.cursor = "crosshair";
}
if(mouse.buttonRaw === 0 && input){
input = false;
mouse.lastButtonRaw = 0;
}
ctx.lineWidth = 0.5;
ctx.fillStyle = "red";
ctx.clearRect(3,3,200,10);
ctx.clearRect(3,14,200,10);
ctx.fillRect(3,3,lineSmooth.angle*200,10);
ctx.fillRect(3,14,lineSmooth.lengthMin*10,10);
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillStyle = "#000"
ctx.strokeRect(3,3,200,10);
ctx.fillText("Smooth "+(lineSmooth.angle * (180 / Math.PI)).toFixed(0)+"deg",5,2)
ctx.strokeRect(3,14,200,10);
ctx.fillText("Detail "+lineSmooth.lengthMin.toFixed(0) + "pixels",5,13);
}else{
canvas.style.cursor = "crosshair";
}
if(!input){
ctx.lineWidth = 3;
if(mouse.buttonRaw === 4 && mouse.lastButtonRaw === 0){
currentLine = [];
drawing = true;
backBuffer.ctx.clearRect(0,0,canvas.width,canvas.height);
backBuffer.ctx.drawImage(canvas,0,0);
currentLine.push([mouse.x,mouse.y])
}else
if(mouse.buttonRaw === 4){
var lp = currentLine[currentLine.length-1]; // get last point
// dont record point if no movement
if(mouse.x !== lp[0] || mouse.y !== lp[1] ){
currentLine.push([mouse.x,mouse.y]);
ctx.beginPath();
ctx.moveTo(lp[0],lp[1])
ctx.lineTo(mouse.x,mouse.y);
ctx.stroke();
liveSmooth = smoothLine(
simplifyLineRDP(
currentLine,
lineSmooth.lengthMin
),
lineSmooth.angle,
lineSmooth.match
);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(backBuffer,0,0);
ctx.strokeStyle = "Blue";
drawSmoothedLine(liveSmooth );
ctx.strokeStyle = "black";
}
}else
if(mouse.buttonRaw === 0 && mouse.lastButtonRaw === 4){
ctx.textAlign = "center"
ctx.fillStyle = "red"
ctx.fillText("Smoothing...",canvas.width/2,canvas.height/5);
smoothIt = true;
}else
if(smoothIt){
smoothIt = false;
var newLine = smoothLine(
simplifyLineRDP(
currentLine,
lineSmooth.lengthMin
),
lineSmooth.angle,
lineSmooth.match
);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(backBuffer,0,0);
drawSmoothedLine(newLine);
drawing = false;
}
if(mouse.buttonRaw === 1 && mouse.lastButtonRaw === 0){
currentLine = [];
drawing = true;
backBuffer.ctx.clearRect(0,0,canvas.width,canvas.height);
backBuffer.ctx.drawImage(canvas,0,0);
currentLine.push([mouse.x,mouse.y])
}else
if(mouse.buttonRaw === 1){
var lp = currentLine[currentLine.length-1]; // get last point
// dont record point if no movement
if(mouse.x !== lp[0] || mouse.y !== lp[1] ){
currentLine.push([mouse.x,mouse.y]);
ctx.beginPath();
ctx.moveTo(lp[0],lp[1])
ctx.lineTo(mouse.x,mouse.y);
ctx.stroke();
}
}else
if(mouse.buttonRaw === 0 && mouse.lastButtonRaw === 1){
ctx.textAlign = "center"
ctx.fillStyle = "red"
ctx.fillText("Smoothing...",canvas.width/2,canvas.height/5);
smoothIt = true;
}else
if(smoothIt){
smoothIt = false;
var newLine = smoothLine(
simplifyLineRDP(
currentLine,
lineSmooth.lengthMin
),
lineSmooth.angle,
lineSmooth.match
);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(backBuffer,0,0);
drawSmoothedLine(newLine);
drawing = false;
}
}
// middle button clear
if(mouse.buttonRaw === 2){
ctx.clearRect(0,0,canvas.width,canvas.height);
}
mouse.lastButtonRaw = mouse.buttonRaw;
requestAnimationFrame(draw);
}
draw();
.canC { width:1000px; height:500px; border:1px black solid;}
<canvas class="canC" id="canV" width=1000 height=500></canvas>
You could save the last position and draw a line between the last point and the actual point.
if (lastX && lastY && (x !== lastX || y !== lastY)) {
ctx.fillStyle = "#000000";
ctx.lineWidth = 2 * size;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
// ...
lastX = x;
lastY = y;
}
On mouseup event set the two variables to zero.
var canvas, ctx
var mouseX, mouseY, mouseDown = 0,
lastX, lastY;
function draw(ctx,x,y,size) {
if (lastX && lastY && (x !== lastX || y !== lastY)) {
ctx.fillStyle = "#000000";
ctx.lineWidth = 2 * size;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
}
ctx.fillStyle = "#000000";
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
lastX = x;
lastY = y;
}
function clearCanvas(canvas,ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
function onMouseDown() {
mouseDown = 1
draw(ctx, mouseX, mouseY, 2)
}
function onMouseUp() {
mouseDown = 0;
lastX = 0;
lastY = 0;
}
function onMouseMove(e) {
getMousePos(e)
if (mouseDown == 1) {
draw(ctx, mouseX, mouseY, 2)
}
}
function getMousePos(e) {
if (!e)
var e = event
if (e.offsetX) {
mouseX = e.offsetX
mouseY = e.offsetY
}
else if (e.layerX) {
mouseX = e.layerX
mouseY = e.layerY
}
}
function init() {
canvas = document.getElementById('sketchpad')
ctx = canvas.getContext('2d')
canvas.addEventListener('mousedown', onMouseDown, false)
canvas.addEventListener('mousemove', onMouseMove, false)
window.addEventListener('mouseup', onMouseUp, false)
}
init();
<canvas id="sketchpad" width="600" height="300"></canvas>
Good question! And I recommend you a site https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API to learn more canvas API.
I think using lineTo is better than arc.So I hope this code will help you.
var canvas, ctx;
var mouseDown = 0, lastX, lastY;
function draw(ctx,x,y) {
ctx.beginPath();
ctx.moveTo(lastX,lastY);
ctx.lineTo(x,y);
ctx.closePath();
ctx.stroke();
}
function clearCanvas(canvas,ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
function onMouseDown(e) {
var xy = getMousePos(e);
lastX = xy.mouseX;
lastY = xy.mouseY;
mouseDown = 1;
}
function onMouseUp() {
mouseDown = 0
}
function onMouseMove(e) {
if (mouseDown == 1) {
var xy = getMousePos(e);
draw(ctx, xy.mouseX, xy.mouseY);
lastX = xy.mouseX, lastY = xy.mouseY;
}
}
function getMousePos(e) {
var o = {};
if (!e)
var e = event
if (e.offsetX) {
o.mouseX = e.offsetX
o.mouseY = e.offsetY
}
else if (e.layerX) {
o.mouseX = e.layerX
o.mouseY = e.layerY
}
return o;
}
function init() {
canvas = document.getElementById('sketchpad')
ctx = canvas.getContext('2d')
canvas.addEventListener('mousedown', onMouseDown, false)
canvas.addEventListener('mousemove', onMouseMove, false)
canvas.addEventListener('mouseup', onMouseUp, false)
}
init();

cloning a moving ball in javascript on a HTML canvas

Need help with cloning a moving ball in javascript. So the ball inherits the same property and actions of the moving ball when clicking it. I have tried using cloneNode(), using prototype and inheritance.
The cloning area within the code is after the comment //Clone prototype and constructor
Here is the full code below and the Demo in JS fiddle at the bottom of this code.
#balling {
border:1px solid rgb(0,0,0);
}
</style>
</head>
<body>
<canvas id="balling" width="500" height="400"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('balling');
var context = canvas.getContext('2d');
// The Properties of the Circle and Position within the Viewport
var CircleOptions = {
posBall: {
x: 160,
y: 180
},
radius: 40,
startAngle: 0,
endAngle: Math.PI * 2,
anticlockwise: false,
radians: 0,
xMove: Math.random(),
yMove: Math.random(),
speed:2,
angle:80,
velocityX:1,
velocityY:1
};
//Math to make the ball move
function moveBall() {
CircleOptions.radians = CircleOptions.angle * Math.PI/180;
CircleOptions.xMove = Math.cos(CircleOptions.radians) * CircleOptions.speed * CircleOptions.velocityX;
CircleOptions.yMove = Math.sin(CircleOptions.radians) * CircleOptions.speed * CircleOptions.velocityY;
}
//Function to draw the ball
function DrawOptions() {
//Reset Canvas
context.fillStyle = "white";
context.fillRect(0, 0, canvas.width, canvas.height);
//Drawing of the ball
context.fillStyle = "rgb(142, 68, 173)";
context.beginPath();
context.arc(CircleOptions.posBall.x, CircleOptions.posBall.y, CircleOptions.radius, CircleOptions.startAngle, CircleOptions.endAngle, CircleOptions.anticlockwise);
context.closePath();
context.fill();
}
//finding the coordinates of the circle
function CircleCoordinates() {
CircleOptions.left = CircleOptions.posBall.x - CircleOptions.radius,
CircleOptions.right = CircleOptions.posBall.x + CircleOptions.radius,
CircleOptions.top = CircleOptions.posBall.y - CircleOptions.radius,
CircleOptions.bottom = CircleOptions.posBall.y + CircleOptions.radius;
}
// Animate and call the function to move the ball
setInterval(Move, 20);
//Function call for the ball
moveBall();
//The function to make it move, reset canvas for movement and color/create shape of ball
function Move() {
//Function call for drawing and pinpointing the coordinates
DrawOptions();
CircleCoordinates();
//Power to make it move
CircleOptions.posBall.x += CircleOptions.xMove;
CircleOptions.posBall.y += CircleOptions.yMove;
//checks for ball hitting the Wall
if(CircleOptions.posBall.x > canvas.width || CircleOptions.posBall.x < 0) {
CircleOptions.angle -= 770;
moveBall();
} else if(CircleOptions.posBall.y > canvas.height || CircleOptions.posBall.y < 0) {
CircleOptions.angle -= 2760;
moveBall();
} else if(CircleOptions.posBall.y == canvas.height || CircleOptions.posBall.y > canvas.width) {
CircleOptions.angle += 90;
moveBall();
}
}
canvas.addEventListener('click', function (e) {
var clickedX = e.pageX - this.offsetLeft;
var clickedY = e.pageY - this.offsetTop;
if (clickedX < CircleOptions.right && clickedX > CircleOptions.left && clickedY > CircleOptions.top && clickedY < CircleOptions.bottom) {
// alert('Double Me Please!');
Clone();
}
});
// Clone prototype and constructor
function Clone() {
var newCanvas = document.getElementById('balling');
var context = newCanvas.getContext('2d');
context.fillStyle = "rgb(142, 68, 173)";
context.beginPath();
context.arc(CircleOptions.posBall.x, CircleOptions.posBall.y, CircleOptions.radius, CircleOptions.startAngle, CircleOptions.endAngle, CircleOptions.anticlockwise);
context.closePath();
context.fill();
return newCanvas;
}
//function call for clone
//For cursor style in and out element
canvas.addEventListener('mouseover', function () {
document.body.style.cursor = "pointer";
});
canvas.addEventListener('mouseout', function () {
document.body.style.cursor = "default";
});
</script>
An Updated Fiddle Demo: http://jsfiddle.net/coder101/CMW24/5/
In your jsFiddle version:
The Clone method and call at the bottom don't do anything.
Your CircleOptions is really not options, it's the object that represents the ball.
Your Move function is the repeating controller that makes it move around.
Your setInterval method is what starts it running by calling Move and uses the existing DrawOptions and CircleOptions; CircleCoordinates doesn't do anything at all.
If you want to clone the ball, you'd want to create an array of CircleOptions objects (change the name) and then loop through them inside Move or they should probably each have their own Move method and act on that. But if it's JavaScript, having them all move within one method would be less processor intensive.
I cleaned up the code and removed the code that didn't do anything. Now I'd make the balls belong to an array and make your click event add more balls. I'll leave that exercise to you.
var canvas = document.getElementById('balling');
var context = canvas.getContext('2d');
var ball = function( new_x, new_y) {
var b = {};
b.posBall = {
x: new_x,
y: new_y
};
b.radius = 40;
b.startAngle = 0;
b.endAngle = Math.PI * 2;
b.anticlockwise = false;
b.radians = 0;
b.xMove = Math.random();
b.yMove = Math.random();
b.speed = 2;
b.angle = 80;
b.velocityX = 1;
b.velocityY = 1;
return b;
}
//Function to clear the canvas
function DrawReset() {
//Reset Canvas
context.fillStyle = "white";
context.fillRect(0, 0, canvas.width, canvas.height);
//Drawing of the ball
context.fillStyle = "rgb(142, 68, 173)";
context.beginPath();
context.arc(CurrentBall.posBall.x, CurrentBall.posBall.y, CurrentBall.radius, CurrentBall.startAngle, CurrentBall.endAngle, CurrentBall.anticlockwise);
context.closePath();
context.fill();
}
//Math to make the ball move
function moveBall() {
CurrentBall.radians = CurrentBall.angle * Math.PI / 180;
CurrentBall.xMove = Math.cos(CurrentBall.radians) * CurrentBall.speed * CurrentBall.velocityX;
CurrentBall.yMove = Math.sin(CurrentBall.radians) * CurrentBall.speed * CurrentBall.velocityY;
}
//The function to make it move, reset canvas for movement and color/create shape of ball
function Move() {
//Function call for drawing and pinpointing the coordinates
DrawReset();
//Power to make it move
CurrentBall.posBall.x += CurrentBall.xMove;
CurrentBall.posBall.y += CurrentBall.yMove;
//checks for ball hitting the Wall
if (CurrentBall.posBall.x > canvas.width || CurrentBall.posBall.x < 0) {
CurrentBall.angle -= 770;
moveBall();
} else if (CurrentBall.posBall.y > canvas.height || CurrentBall.posBall.y < 0) {
CurrentBall.angle -= 2760;
moveBall();
} else if (CurrentBall.posBall.y == canvas.height || CurrentBall.posBall.y > canvas.width) {
CurrentBall.angle += 90;
moveBall();
}
}
canvas.addEventListener('click', function (e) {
var clickedX = e.pageX - this.offsetLeft;
var clickedY = e.pageY - this.offsetTop;
alert(e.pageX + ' ' + e.pageY);
if (clickedX > CurrentBall.right && clickedX > CurrentBall.left && clickedY > CurrentBall.top && clickedY < CurrentBall.bottom) {
alert('clicked number ');
}
});
var CurrentBall = ball(160,180);
// Animate and call the function to move the ball
setInterval(Move, 20);

Categories