can not rotate a rectangular shape in canvas - javascript

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.

Related

Motion effect for standing object

I have trying to achieve motion effect for the standing object.
I assume that my object will be able to go to the right or the left for example.
And I wanna make illusion like that object is still moving. Even if currently is not moving. (Meanwhile background can moving still...)
'use strict';
const pressedKeys = [];
const canvas = document.querySelector('#game');
const ctx = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 150;
class Player
{
xPosition = 150;
yPosition = 50;
speed = 5;
isMoving = false;
update(pressedKeys)
{
if (pressedKeys['ArrowLeft']) {
this.xPosition -= this.speed;
} else if (pressedKeys['ArrowRight']) {
this.xPosition += this.speed;
}
}
draw(ctx)
{
ctx.fillStyle = '#2976f2';
ctx.fillRect(this.xPosition, this.yPosition, 30, 30);
}
}
const player = new Player();
function animate()
{
window.requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height)
if (player.isMoving) {
player.update(pressedKeys);
}
player.draw(ctx);
}
animate();
window.addEventListener('keyup', function (event) {
delete pressedKeys[event.key];
player.isMoving = false;
})
window.addEventListener('keydown', function (event) {
switch (event.key) {
case 'ArrowLeft':
case 'ArrowRight':
pressedKeys[event.key] = true;
player.isMoving = true;
break;
}
})
canvas {
border: 1px solid blue;
}
<canvas id="game"></canvas>
Usually this kind of effect is done by constantly duplicating the desired object, move it to the exact same screen position and ultimately fade it out over time e.g. within one second.
In your case though we can simplify things a bit since you want to keep that "motion blurred" look even if it ain't moving.
So first we need to another property to your Player class oldX. It holds the position of the object before a movement occured. By subtracting oldX from x we can determine if the object is moving to the left or to the right - so we know where to put the trailing duplicates.
If we know the direction, we can start creating duplicates using a simple for loop like:
for (var a = 0; a < 7; a++) {
ctx.fillRect(this.x - (this.x - this.oldX) / this.speed * a * 2, this.y, 30, 30);
}
this will create seven equal looking squares - so it won't look good yet. The duplicate next to the original should have almost the same color while the last one should almost blend with the background. To do this we can use the globalAlpha property of the canvases context. A value of 1 is opaque while 0 is completely transparent.
Putting it all together:
const keys = [];
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 150;
class Player {
x = 150;
y = 50;
oldX = 150;
speed = 5;
moving = false;
update(keys) {
this.oldX = this.x;
if (keys['ArrowLeft']) {
this.x -= this.speed;
} else if (keys['ArrowRight']) {
this.x += this.speed;
}
}
draw(ctx) {
ctx.fillStyle = '#2976f2';
ctx.fillRect(this.x, this.y, 30, 30);
ctx.save();
for (var a = 0; a < 7; a++) {
ctx.globalAlpha = 0.5 - (a / 7) * 0.5;
ctx.fillRect(this.x - (this.x - this.oldX) / this.speed * a * 2, this.y, 30, 30);
}
ctx.restore();
}
}
const player = new Player();
function animate() {
window.requestAnimationFrame(animate);
ctx.clearRect(0, 0, canvas.width, canvas.height)
if (player.moving) {
player.update(keys);
}
player.draw(ctx);
}
animate();
window.addEventListener('keyup', function(event) {
delete keys[event.key]
player.moving = false;
})
window.addEventListener('keydown', function(event) {
switch (event.key) {
case 'ArrowLeft':
case 'ArrowRight':
keys[event.key] = true;
player.moving = true;
break;
}
})
canvas {
border: 1px solid blue;
}
<canvas id="game"></canvas>

How to rotate/transform image using arrow keys

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! :)

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.

Matter.js for collision detection

I'm relatively new to asking questions here, so please bear with me. I am trying to create a top down driving game with Matter.js as the primary physics engine. I would like the red car to collide with the green square. However, I am still stuck on knowing how to implement Matter.js onto my game. Any form of response will be greatly appreciated!
<html>
<canvas width=1000 height=500 style='border:1px solid black'>
</canvas>
<body onload='start()'>
<script src='matter.js'>
</script>
<script>
function start() {
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var x = 100;
var y = 100;
var s = 0;
var rot = 0;
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
} else if (e.keyCode == 38) {
upPressed = true;
} else if (e.keyCode == 40) {
downPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
} else if (e.keyCode == 38) {
upPressed = false;
} else if (e.keyCode == 40) {
downPressed = false;
}
}
function car() {
ctx.fillStyle = 'red';
ctx.fillRect(-20, -20, 40, 40);
ctx.beginPath();
ctx.moveTo(-20, -19);
ctx.lineTo(-20, -20);
ctx.lineTo(0, -30);
ctx.lineTo(20, -20);
ctx.lineTo(20, -19);
ctx.fill();
ctx.closePath();
ctx.fillStyle = 'black';
ctx.fillRect(-25, -20, 5, 10);
ctx.fillRect(-25, 10, 5, 10);
ctx.fillRect(20, -20, 5, 10);
ctx.fillRect(20, 10, 5, 10);
ctx.fillRect(-15, -5, 30, 20);
}
function block() {
ctx.fillStyle = 'green';
ctx.fillRect(200, 100, 50, 50);
}
function draw() {
requestAnimationFrame(draw);
ctx.clearRect(0, 0, 1000, 500);
if (s > 15) {
s = 15;
}
if (s < -15) {
s = -15;
}
if (upPressed) {
s++;
}
if (downPressed) {
s *= .9;
}
if (!upPressed) {
s *= .99;
}
if (leftPressed) {
rot -= s / 3;
}
if (rightPressed) {
rot += s / 3;
}
ctx.fillText(upPressed, 10, 10);
x += s * Math.cos(rot * Math.PI / 180);
y += s * Math.sin(rot * Math.PI / 180);
ctx.save();
ctx.translate(x, y);
ctx.rotate((rot + 90) * Math.PI / 180);
car();
ctx.restore();
block();
}
draw();
}
</script>
</body>
</html>
You would have to redo most of your code, but the movement code CAN be moved over fairly easily.
First you need to make a new engine and run it:
//Create engine - All the game stuff
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
// create an engine
var engine = Engine.create(),
world = engine.world;
// create a renderer
var render = Render.create({
canvas: document.getElementById("canv"),
engine: engine,
options: {
width: 500,
height: 500,
wireframes: false,
background: '#6DDA4A'
}
});
engine.world.gravity.y = 0;
Render.run(render);
// create runner
var runner = Runner.create();
Runner.run(runner, engine);
Next, you should make and add a new car object and the block into the world. You can edit these values to whatever you need them to be.
Note: rot is not an actual parameter you need, I'm just using it to set the rotation of the car later.
var car = Bodies.rectangle(100, 100, 50, 80, {
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,//Makes it so the car won't bounce off of objects
render: {
fillStyle: "#FF0000",
/*sprite: {
//You can use this to apply a background image to the car
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
var block = Bodies.rectangle(350, 100, 100, 400, {
isStatic: true,//Makes block unmovable
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,
render: {
fillStyle: "#0000FF",
/*sprite: {
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
World.add(world, [car, block]);
For updating the car, you can either use body.setPosition or body.applyForce. Since it's a car, I would use body.applyForce so that the car keeps rolling after you've stopped pressing a button. Rotation can also be done with body.setAngle or body.rotate. This time, I'm going to use body.setAngle so the turning feels better.
function updateCar() {
//Declare variables for velocity
var speed = 5;
var carRot = car.rot*180/Math.PI;
var velY = speed * Math.cos(carRot * Math.PI / 180);
var velX = speed * Math.sin(carRot * Math.PI / 180)*-1;
var pushRot = 0;
//Update variables
if (upPressed==false&&downPressed==false) {
velY = 0;
velX = 0;
}
else {
//alert(carX+", "+carY);
}
if (downPressed == true) {
velY *= -1;
velX *= -1;
}
if (leftPressed) {
pushRot = -0.1;
}
if (rightPressed) {
pushRot = 0.1;
}
car.rot += pushRot;
//Set position of car
carX += velX;
carY += velY;
Body.applyForce(car, {x:carX,y:carY}, {x:velX/200,y:velY/200});
Body.setAngle(car, car.rot);
requestAnimationFrame(updateCar);
}
window.requestAnimationFrame(updateCar);
Check out a demo here

I'm trying to get a blue square to move around in the canvas by using arrow keys?

const WIDTH = 640;
const HEIGHT = 480;
const PLAYER_SIZE = 20;
const REPAINT_DELAY = 50;
const EASY_DELAY = 1750;
const MODERATE_DELAY = 1000;
const HARD_DELAY = 750;
const MAX_BLOCKS = 100;
var context;
var DX;
var DY;
DX and DY are the position of the blue square. What I'm trying to accomplish is that when using the arrow keys I am moving the Position of the blue square.
var rightKey = false;
var leftKey = false;
var upKey = false;
var downKey = false;
window.onload = init;
function init()
{
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
context.fillStyle = "#0000FF";
DX = WIDTH / 2 - PLAYER_SIZE / 2;
DY = HEIGHT / 2 - PLAYER_SIZE / 2;
setInterval('draw()', 25)
}
function clearCanvas()
{
context.clearRect(0,0,WIDTH,HEIGHT);
}
function draw()
{
clearCanvas();
if (rightKey) DX += 5;
else if (leftKey) DX -= 5;
if (upKey) DY -= 5;
else if (downKey) DY += 5;
if (DX <= 0) DX = 0;
if ((DX + DY) >= WIDTH) DX = WIDTH - DY;
if (DY <= 0) DY = 0;
if ((DY + DX) >= HEIGHT) DY = HEIGHT - DX;
context.fillRect(DX, DY, PLAYER_SIZE, PLAYER_SIZE);
}
function onKeyDown(evt) {
if (evt.keyCode == 39) rightKey = true;
else if (evt.keyCode == 37) leftKey = true;
if (evt.keyCode == 38) upKey = true;
else if (evt.keyCode == 40) downKey = true;
}
function onKeyUp(evt) {
if (evt.keyCode == 39) rightKey = false;
else if (evt.keyCode == 37) leftKey = false;
if (evt.keyCode == 38) upKey = false;
else if (evt.keyCode == 40) downKey = false;
}
I think here at the end I'm missing two lines of code that sort of call the two previous functions? That's where I'm getting confused.
This is what I have so far it isn't working for me at the moment. Any help would be appreciated!
The error in your code is this:
setInterval('draw()', 25)
when it should be
setInterval(draw, 25)
setInterval's first argument should be function, now it's a string.
Here's my simple
Updated demo with class based moving objects:
https://jsfiddle.net/mulperi/oh7n3Lx9/
Also, see here why requestAnimationFrame() is better than setTimeout() or setInterval():
Why is requestAnimationFrame better than setInterval or setTimeout
For keypresses I suggest you make an object that holds boolean values for all keys and then, on the update-functions of different objects like player for example, you just check if the keys it needs are being pressed.
And you don't need to use keyCode anymore, see here:
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
I hope that helps you!
Here is the full code of my take on moving the player objects around the canvas. It may help you to think about the structure of your code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>World's BEstest Game</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1 style="font-family: Comic Sans MS; color: hotpink; text-shadow: 2px 2px 2px pink">2 Player Movement</h1>
<p>Class based player objects and keyboard controls</p>
<p>Use the arrow and WASD keys to move your balls</p>
<canvas id="canvas" style="border:1px solid black; border-radius: 5px;">
</canvas>
<script>
const c = document.getElementById("canvas");
const ctx = c.getContext("2d");
let settings = {
width: 100,
height: 100,
speed: 1
};
c.width = settings.width;
c.height = settings.height;
/*
Object holding boolean values for every keypress
*/
let keyPresses = {};
function listenKeyboard() {
document.addEventListener("keyup", keyUp);
document.addEventListener("keydown", keyDown);
};
const keyUp = e => {
keyPresses[e.key] = false;
};
const keyDown = e => {
// console.log(e.key)
keyPresses[e.key] = true;
};
class Player {
constructor(x, y, color, left, right, up, down, radius) {
this.x = x;
this.y = y;
this.color = color;
this.left = left;
this.right = right;
this.up = up;
this.down = down;
this.radius = radius;
}
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
}
update() {
if (keyPresses[this.left]) {
this.x -= settings.speed;
}
if (keyPresses[this.right]) {
this.x += settings.speed;
}
if (keyPresses[this.up]) {
this.y -= settings.speed;
}
if (keyPresses[this.down]) {
this.y += settings.speed;
}
// Screen bounds
if (this.x < 0 + this.radius) this.x = 0 + this.radius;
if (this.y < 0 + this.radius) this.y = 0 + this.radius;
if (this.x > settings.width - this.radius) this.x = settings.width - this.radius;
if (this.y > settings.height - this.radius) this.y = settings.width - this.radius;
}
}
/*
Creating the player objects
*/
let p1 = new Player(25, 25, "red", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", 10);
let p2 = new Player(75, 75, "black", "a", "d", "w", "s", 5);
function draw() {
ctx.clearRect(0, 0, settings.width, settings.height);
p1.draw();
p2.draw();
};
function update() {
draw();
listenKeyboard();
p1.update();
p2.update();
requestAnimationFrame(update);
};
requestAnimationFrame(update);
</script>
</body>
</html>

Categories