I am attempting to create a simple game where I have two rectangles, a human-controlled player and a "collider" that has to be avoided.
I am trying to draw the two rectangles using fillRect(), however only one shows up. For example, putting the "lime" colored rectangle first would result in it being drawn, but putting the "red" colored rectangle line first causes neither to be drawn.
I would expect a result where both rectangles are drawn/appear at the same time on the canvas:
<canvas id="gc" width="800" height="600"></canvas>
<script>
window.onload=function() {
canv=document.getElementById("gc");
ctx=canv.getContext("2d");
document.addEventListener("keydown",keyPush);
setInterval(game,1000/100);
}
// Variables
player_created = false;
collider_created = false;
player_width = 20;
player_height = 20;
collider_width = 15;
collider_height = 15;
player_velocity = 10;
collider_velocity = 20;
player_x = (document.getElementById("gc").getAttribute("width") - player_width)/2;
player_y = (document.getElementById("gc").getAttribute("height") - player_height)/2;
collider_x = (document.getElementById("gc").getAttribute("width") - collider_width)/4;
collider_y = (document.getElementById("gc").getAttribute("height") - collider_height)/4;
var player;
var collider;
// Objects
function Player(x, y, vx, vy, w, h) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.w = w;
this.h = h;
}
function Collider(x, y, vx, vy, w, h) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.w = w;
this.h = h;
}
function game() {
ctx.fillStyle="black"; // Color canvas
ctx.fillRect(0,0,canv.width,canv.height);
if(!player_created) {
player = new Player(player_x, player_y, player_velocity, player_velocity, player_width, player_height);
player_created = true;
}
if(!collider_created) {
collider = new Collider(collider_x, collider_y, collider_velocity, collider_velocity, collider_width, collider_height);
collider_created = true;
}
colliderWallCollision(collider, canv.width, canv.height);
playerWallCollision(player, canv.width, canv.height);
ctx.fillStyle="lime"; // Color player
ctx.fillRect(player.x, player.y, player.w, player.h);
ctx.fillStyle="red"; // Color collider
ctx.fillRect(collider.x, collider.y, collider.w. collider.h);
}
function playerWallCollision(entity, bound_x, bound_y) {
if (entity.x + entity.w > bound_x) {
entity.x = bound_x - entity.w;
}
if (entity.x < 0) {
entity.x = 0
}
if (entity.y + entity.h > bound_y) {
entity.y = bound_y - entity.h;
}
if (entity.y < 0) {
entity.y = 0
}
}
function colliderWallCollision(entity, bound_x, bound_y) {
if (entity.x + entity.w >= bound_x || entity.x <= 0) {
entity.vx = -entity.vx
}
if (entity.y + entity.h >= bound_y || entity.y <= 0) {
entity.vy = -entity.vy
}
}
function keyPush(evt) { // Read keystrokes
switch(evt.keyCode) {
// Vertical
case 87: // w
player.y -= player.vy;
break;
case 83: // s
player.y += player.vy;
break;
// Horizontal
case 65: // a
player.x -= player.vx;
break;
case 68: // d
player.x += player.vx;
break;
}
}
</script>
The second rectangle is failing to draw due to a syntax error on this line:
ctx.fillRect(collider.x, collider.y, collider.w. collider.h);
The following update will resolve that problem:
// Change . to ,
ctx.fillRect(collider.x, collider.y, collider.w, collider.h);
See the snippet below for a working version in action:
<canvas id="gc" width="800" height="600"></canvas>
<script>
window.onload=function() {
canv=document.getElementById("gc");
ctx=canv.getContext("2d");
document.addEventListener("keydown",keyPush);
setInterval(game,1000/100);
}
// Variables
player_width = 20;
player_height = 20;
collider_width = 15;
collider_height = 15;
player_velocity = 10;
collider_velocity = 20;
player_x = (document.getElementById("gc").getAttribute("width") - player_width)/2;
player_y = (document.getElementById("gc").getAttribute("height") - player_height)/2;
collider_x = (document.getElementById("gc").getAttribute("width") - collider_width)/4;
collider_y = (document.getElementById("gc").getAttribute("height") - collider_height)/4;
var player;
var collider;
// Objects
function Player(x, y, vx, vy, w, h) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.w = w;
this.h = h;
}
function Collider(x, y, vx, vy, w, h) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.w = w;
this.h = h;
}
function game() {
ctx.fillStyle="black"; // Color canvas
ctx.fillRect(0,0,canv.width,canv.height);
if(!player) {
player = new Player(player_x, player_y, player_velocity, player_velocity, player_width, player_height);
}
if(!collider) {
collider = new Collider(collider_x, collider_y, collider_velocity, collider_velocity, collider_width, collider_height);
}
colliderWallCollision(collider, canv.width, canv.height);
playerWallCollision(player, canv.width, canv.height);
ctx.fillStyle="lime"; // Color player
ctx.fillRect(player.x, player.y, player.w, player.h);
ctx.fillStyle="red"; // Color collider
/* Typo here */
ctx.fillRect(collider.x, collider.y, collider.w, collider.h);
}
function playerWallCollision(entity, bound_x, bound_y) {
if (entity.x + entity.w > bound_x) {
entity.x = bound_x - entity.w;
}
if (entity.x < 0) {
entity.x = 0
}
if (entity.y + entity.h > bound_y) {
entity.y = bound_y - entity.h;
}
if (entity.y < 0) {
entity.y = 0
}
}
function colliderWallCollision(entity, bound_x, bound_y) {
if (entity.x + entity.w >= bound_x || entity.x <= 0) {
entity.vx = -entity.vx
}
if (entity.y + entity.h >= bound_y || entity.y <= 0) {
entity.vy = -entity.vy
}
}
function keyPush(evt) { // Read keystrokes
switch(evt.keyCode) {
// Vertical
case 87: // w
player.y -= player.vy;
break;
case 83: // s
player.y += player.vy;
break;
// Horizontal
case 65: // a
player.x -= player.vx;
break;
case 68: // d
player.x += player.vx;
break;
}
}
</script>
Related
Im making a pong game and I want to make the ball have a speedX and a speedY that is added to the ball that makes it move along the X and Y axis but im not sure how to adjust those variables based off of the balls angle. In function ballPhysics() I need to replace the 0's with something to get the speed it should go along that axis. But if anyone finds anything else that should be worked on itd be great if you let me know thanks.
let cvs, ctx;
let width = 600, height = 500;
let keysPressed = [];
class Wall {
constructor(x, y, w, h, speed) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
}
}
class Ball {
constructor(x, y , w, h, speedX, speedY, angle) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speedX = speedX;
this.speedY = speedY;
this.angle = angle;
}
}
let left = new Wall(25, 250, 10, 100, 10);
let right = new Wall(width-25, 250, 10, 100, 10)
let ball = new Ball(width/2, height/2, 5, 5, 0, 0, 0);
function ballPhysics() {
ball.x += ball.speedX;
ball.y += ball.speedY;
ball.speedX = 0//figure out direction;
ball.speedY = 0//figure out direction;
}
function start() {
ball.x = width/2;
ball.y = height/2;
if(Math.random() < 0.5) {
ball.angle = 90;
} else {
ball.angle = -90;
}
console.log(ball.angle);
}
function update() {
setInterval(function () {
ballPhysics();
for(let i = 0; i < keysPressed.length; i++) {
if(keysPressed[i] == 'KeyW' && left.y >= 0) {
left.y -= left.speed;
}
if(keysPressed[i] == 'KeyS' && left.y + left.h <= height) {
left.y += left.speed;
}
if(keysPressed[i] == 'ArrowUp' && right.y >= 0) {
right.y -= right.speed;
}
if(keysPressed[i] == 'ArrowDown' && right.y + right.h <= height) {
right.y += right.speed;
}
if(keysPressed[i] == 'Space') {
start();
}
}
}, 16)
}
function renderPlayers() {
ctx.fillStyle = '#FF0000';
ctx.fillRect(left.x, left.y, left.w, left.h);
ctx.fillRect(right.x, right.y, right.w, right.h);
}
function renderBall() {
ctx.fillStyle = '#0000FF';
ctx.fillRect(ball.x, ball.y, ball.w, ball.h);
}
function render() {
ctx.clearRect(0, 0, cvs.width, cvs.height);
renderBall();
renderPlayers();
requestAnimationFrame(render);
}
window.addEventListener("DOMContentLoaded", function () {
cvs = document.getElementById("cvs");
ctx = cvs.getContext("2d");
cvs.width = width;
cvs.height = height;
update();
render();
});
window.addEventListener('keydown', function(e) {
if(!keysPressed.includes(e.code)) {
keysPressed.push(e.code);
}
});
window.addEventListener('keyup', function(e) {
for(let i = 0; i < keysPressed.length; i++) {
if(keysPressed[i] == e.code) {
keysPressed.splice(i, 1);
}
}
});
#cvs {
border: solid 1px black;
background: #D1C3C3;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Platformer</title>
<link rel="stylesheet" href="/style.css" />
<script src="/script.js" defer></script>
</head>
<body>
<canvas width="0" height="0" id="cvs"></canvas>
</body>
</html>
I am developing a basic game where the user needs to go through the openings and avoid crashing with the obstacles. My issue now is that the flow of the game is from the bottom to the top, when in fact I need the obstacles to come from the top to the bottom.
What am I missing in the code? Any help is appreciated.
let myObstacles = [];
let myGameArea = {
canvas: document.createElement("canvas"),
frames: 0,
start: function() {
this.canvas.width = 700;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
this.canvas.classList.add('canvasBg');
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
},
score: function() {
var points = Math.floor(this.frames / 5);
this.context.font = "18px serif";
this.context.fillStyle = "black";
this.context.fillText("Score: " + points, 350, 50);
}
}
class Component {
constructor(width, height, color, x, y) {
this.width = width;
this.height = height;
this.color = color;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
}
update() {
let ctx = myGameArea.context;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
newPos() {
this.x += this.speedX;
this.y += this.speedY;
}
left() {
return this.x;
}
right() {
return this.x + this.width;
}
top() {
return this.y;
}
bottom() {
return this.y + this.height;
}
crashWith(obstacle) {
return !(
this.bottom() < obstacle.top() ||
this.top() > obstacle.bottom() ||
this.right() < obstacle.left() ||
this.left() > obstacle.right()
);
}
}
function checkGameOver() {
let crashed = myObstacles.some(function(obstacle) {
return player.crashWith(obstacle);
});
if (crashed) {
myGameArea.stop();
}
}
document.onkeydown = function(e) {
switch (e.keyCode) {
case 38: // up arrow
player.speedY -= 1;
break;
case 40: // down arrow
player.speedY += 1;
break;
case 37: // left arrow
player.speedX -= 1;
break;
case 39: // right arrow
player.speedX += 1;
break;
}
};
function updateObstacles() {
for (i = 0; i < myObstacles.length; i++) {
myObstacles[i].y += -3;
myObstacles[i].update();
}
myGameArea.frames += 1;
if (myGameArea.frames % 60 === 0) {
let x = myGameArea.canvas.width;
let y = myGameArea.canvas.height;
let minWidth = 20;
let maxWidth = 200;
let width = Math.floor(
Math.random() * (maxWidth - minWidth + 1) + minWidth
);
var minGap = 70;
var maxGap = 200;
var gap = Math.floor(Math.random() * (maxGap - minGap + 1) + minGap);
myObstacles.push(new Component(width, 10, "green", 0, y));
myObstacles.push(
new Component(y-width-gap, 10, "green", width+gap, y)
);
}
}
document.onkeyup = function(e) {
player.speedX = 0;
player.speedY = 0;
};
function updateGameArea() {
myGameArea.clear();
player.newPos();
player.update();
updateObstacles();
checkGameOver();
myGameArea.score();
};
myGameArea.start();
let player = new Component(30, 30, "red", 0, 110);
I got it to work by changing 3 things in your updateObstacles function.
First, change myObstacles[i].y += -3 to myObstacles[i].y += 3
Second, change let y = myGameArea.canvas.height to let y = 0
Third, change
new Component(y-width-gap, 10, "green", width+gap, y)
to
new Component(x-width-gap, 10, "green", width+gap, y)
Full code:
function updateObstacles() {
for (i = 0; i < myObstacles.length; i++) {
myObstacles[i].y += 3;
myObstacles[i].update();
}
myGameArea.frames += 1;
if (myGameArea.frames % 60 === 0) {
let x = myGameArea.canvas.width;
let y = 0;
let minWidth = 20;
let maxWidth = 200;
let width = Math.floor(
Math.random() * (maxWidth - minWidth + 1) + minWidth
);
var minGap = 70;
var maxGap = 200;
var gap = Math.floor(Math.random() * (maxGap - minGap + 1) + minGap);
myObstacles.push(new Component(width, 10, "green", 0, y));
myObstacles.push(
new Component(x-width-gap, 10, "green", width+gap, y)
);
}
}
Example jsfiddle
In the below code, pressing C or V should change speed of that ball.
Press V ~10 times and after 5-10 seconds press an arrow button. Where is my mistake?
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
function circle(x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
function ball() {
this.speed = 5;
this.x = width / 2;
this.y = height / 2;
this.xSpeed = this.speed;
this.ySpeed = 0;
this.size = 5;
};
ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
}
if (this.y > height) {
this.y = 0;
} else if (this.y < 0) {
this.y = height;
}
};
ball.prototype.draw = function() {
circle(this.x, this.y, this.size, true);
};
ball.prototype.setDirection = function(direction) {
if (direction === "up") {
this.xSpeed = 0;
this.ySpeed = -this.speed;
} else if (direction === "down") {
this.xSpeed = 0;
this.ySpeed = this.speed;
} else if (direction === "right") {
this.xSpeed = this.speed;
this.ySpeed = 0;
} else if (direction === "left") {
this.xSpeed = -this.speed;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
ball.prototype.doCommand = function(direction) {
if (direction === "X") {
this.size += 2;
} else if (direction === "Z") {
this.size -= 2;
} else if (direction === "C") {
this.speed -= 2;
} else if (direction === "V") {
this.speed += 2;
}
if (this.speed < 0) {
this.speed = 1;
}
if (this.size < 0) {
this.size = 1;
}
}
var Ball = new ball();
var commands = ["Z", "X", "C", "V"];
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down",
90: "Z",
88: "X",
67: "C",
86: "V"
};
$("body").keydown(function(event) {
var direction = keyActions[event.keyCode];
for (var n = 0; n < commands.length; n++) {
if (direction === commands[n]) {
Ball.doCommand(direction);
} else {
Ball.setDirection(direction);
}
};
});
setInterval(function() {
ctx.clearRect(0, 0, width, height);
Ball.draw();
Ball.move();
ctx.strokeRect(0, 0, width, height);
}, 30);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
I have updated your code.
First thing in keydown Handler we don't need for loop. I have changed this.
I have updated Do Command as well. Here is the problem: you are not updating xspeed & yspeed in the doCommand I did that change for c & v.
I hope this is what you are expecting.
Please find the updated code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"><title>Drawing some circles...</title>
</head>
<body>
<script src = "https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id = "canvas" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
function circle(x,y,radius,fillCircle)
{
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
if(fillCircle)
{
ctx.fill();
}
else
{
ctx.stroke();
}
};
function ball()
{
this.speed = 5;
this.x = width/2;
this.y = height/2;
this.xSpeed = this.speed;
this.ySpeed = 0;
this.size = 5;
};
ball.prototype.move = function()
{
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x<0)
{
this.x = width;
}
else if(this.x>width)
{
this.x = 0;
}
if (this.y>height)
{
this.y = 0;
}
else if(this.y<0)
{
this.y = height;
}
};
ball.prototype.draw = function()
{
circle(this.x,this.y,this.size,true);
};
ball.prototype.setDirection = function(direction)
{
if(direction ==="up")
{
this.xSpeed = 0;
this.ySpeed = -this.speed;
}else if(direction ==="down")
{
this.xSpeed = 0;
this.ySpeed = this.speed;
}else if(direction ==="right")
{
this.xSpeed = this.speed;
this.ySpeed = 0;
}else if(direction ==="left")
{
this.xSpeed = -this.speed;
this.ySpeed = 0;
}else if(direction ==="stop")
{
this.xSpeed = 0;
this.ySpeed = 0;
}
};
ball.prototype.doCommand = function(direction)
{
if(direction ==="X")
{
this.size +=2;
}else if(direction ==="Z"){
this.size -=2;
}else if(direction ==="C"){
this.speed -=2;
}else if(direction ==="V"){
this.speed +=2;
}
if(this.speed<0)
{
this.speed = 1;
}
if(this.size<0)
{
this.size = 1;
}
if(direction ==="V" || direction ==="C") {
if(this.xSpeed!=0) {
this.xSpeed = this.speed;
}
if(this.ySpeed!=0) {
this.ySpeed = this.speed;
}
}
}
var Ball = new ball();
var commands = ["Z","X","C","V"];
var keyActions = {
32:"stop",
37:"left",
38:"up",
39:"right",
40:"down",
90:"Z",
88:"X",
67:"C",
86:"V"
};
$("body").keydown(function (event)
{
var direction = keyActions[event.keyCode];
if(commands.includes(direction))
{
Ball.doCommand(direction);
}
else{
Ball.setDirection(direction);
}
});
setInterval(function()
{
ctx.clearRect(0,0,width,height);
Ball.draw();
Ball.move();
ctx.strokeRect(0,0,width,height);
}, 30);
</script>
</body>
</html>
I'm working on a game that uses projectiles and a shielding system. The player would hold down 'Space' to use the shield. My plan is to get the projectiles to bounce of of the enemies shields (I've implemented speed so I already know how to do that). The problem I am having is with the collision, since the player rotates to follow the mouse I struggled with finding the best way to create the shield but I eventually settled on an arc, I used some trigonometry to get the left, leftHalf, mid, rightHalf, and right point of the arc/shield. The Player with Shield. The issue is I can't get the collision to work from just 5, x/y coordinates (the arc is just being drawn for show I'm only sending the points to the server). This is what I have for my collision so far:
p: Player object
self: bullet object
bot: a variable based on the direction the character is facing (bottom: true or false)
shieldLeft, sheildRight, etc: an array containing x and y coordinate 0 for x, 1 for y
if (self.getDistance(p) < 32 && self.parent !== p.id)
{
if (p.isShielding == true)
{
switch(self.bot)
{
case true:
if (self.x >= p.shieldRight[0] && self.x <= p.shieldLeft[0])
{
console.log("BOT X");
if ((self.y >= p.shieldLeft[1] || self.y >= p.shieldRight[1]) && self.y <= p.shieldMid[1])
{
console.log("BOT Y");
self.spdX = -self.spdX;
self.spdY = -self.spdY;
}
}
break;
case false:
if (self.x <= p.shieldRight[0] && self.x >= p.shieldLeft[0])
{
console.log("TOP X");
if ((self.y <= p.shieldLeft[1] || self.y <= p.shieldRight[1]) && self.y >= p.shieldMid[1])
{
console.log("TOP Y");
self.spdX = -self.spdX;
self.spdY = -self.spdY;
}
}
break;
}
}
}
I would really appreciate any help, I can't continue with the game features until there actually is a game. Thank you!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
border-radius: 10px;
cursor: crosshair;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// Anonymous closure
(function() {
// Enforce strict rules for JS code
"use strict";
// App variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var bounds = null;
var ctx = null;
var player = null;
var projectiles = [];
projectiles.length = 5;
// Classes
// Constructor function
function Player(x,y) {
this.x = x;
this.y = y;
this.dx = 0.0;
this.dy = 0.0;
this.rotation = 0.0;
this.targetX = 0.0;
this.targetY = 0.0;
this.isShieldUp = false;
this.isShieldRecharging = false;
this.shieldPower = this.shieldPowerMax;
this.left = false;
this.right = false;
this.up = false;
this.down = false;
window.addEventListener("keydown",this.onkeydown.bind(this));
window.addEventListener("keyup",this.onkeyup.bind(this));
window.addEventListener("mousemove",this.onmousemove.bind(this));
}
// shared properties/functions across all instances
Player.prototype = {
width: 10,
height: 10,
shieldRadius: 15.0,
shieldArcSize: 3.0, // In Radians
shieldPowerMax: 50.0,
shieldPowerCharge: 0.5,
shieldPowerDrain: 0.75,
onkeydown: function(e) {
switch(e.key) {
case " ": this.isShieldUp = true && !this.isShieldRecharging; break;
case "w": this.up = true; break;
case "s": this.down = true; break;
case "a": this.left = true; break;
case "d": this.right = true; break;
}
},
onkeyup: function(e) {
switch(e.key) {
case " ": this.isShieldUp = false; break;
case "w": this.up = false; break;
case "s": this.down = false; break;
case "a": this.left = false; break;
case "d": this.right = false; break;
}
},
onmousemove: function(e) {
this.targetX = e.clientX - bounds.left;
this.targetY = e.clientY - bounds.top;
},
tick: function() {
var x = (this.targetX - this.x);
var y = (this.targetY - this.y);
var l = Math.sqrt(x * x + y * y);
x = x / l;
y = y / l;
this.rotation = Math.acos(x) * (y < 0.0 ? -1.0 : 1.0);
if (this.isShieldUp) {
this.shieldPower = this.shieldPower - this.shieldPowerDrain;
if (this.shieldPower < 0.0) {
this.shieldPower = 0.0;
this.isShieldUp = false;
this.isShieldRecharging = true;
}
} else {
this.shieldPower = this.shieldPower + this.shieldPowerCharge;
if (this.shieldPower > this.shieldPowerMax) {
this.shieldPower = this.shieldPowerMax;
this.isShieldRecharging = false;
}
}
if (this.up) { --this.y; this.dy = -1; } else
if (this.down) { ++this.y; this.dy = 1; } else { this.dy = 0; }
if (this.left) { --this.x; this.dx = -1; } else
if (this.right) { ++this.x; this.dx = 1; } else { this.dx = 0; }
},
render: function() {
ctx.fillStyle = "darkred";
ctx.strokeStyle = "black";
ctx.translate(this.x,this.y);
ctx.rotate(this.rotation);
ctx.beginPath();
ctx.moveTo(0.5 * this.height,0.0);
ctx.lineTo(-0.5 * this.height,0.5 * this.width);
ctx.lineTo(-0.5 * this.height,-0.5 * this.width);
ctx.lineTo(0.5 * this.height,0.0);
ctx.fill();
ctx.stroke();
if (this.isShieldUp) {
ctx.strokeStyle = "cyan";
ctx.beginPath();
ctx.arc(0.0,0.0,this.shieldRadius,this.shieldArcSize * -0.5,this.shieldArcSize * 0.5,false);
ctx.stroke();
}
ctx.rotate(-this.rotation);
ctx.translate(-this.x,-this.y);
ctx.fillStyle = "black";
ctx.fillRect(canvasWidth - 80,canvasHeight - 20,75,15);
ctx.fillStyle = this.isShieldRecharging ? "red" : "cyan";
ctx.fillRect(canvasWidth - 75,canvasHeight - 15,65 * (this.shieldPower / this.shieldPowerMax),5);
}
};
function Projectile(x,y,dx,dy) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
Projectile.prototype = {
radius: 2.5,
tick: function(player) {
this.x = this.x + this.dx;
this.y = this.y + this.dy;
if (this.x + this.radius < 0.0) { this.x = canvasWidth + this.radius; }
if (this.x - this.radius > canvasWidth) { this.x = -this.radius; }
if (this.y + this.radius < 0.0) { this.y = canvasHeight + this.radius; }
if (this.y - this.radius > canvasHeight) { this.y = -this.radius; }
if (player.isShieldUp) {
var px = (player.x - this.x);
var py = (player.y - this.y);
var pl = Math.sqrt(px * px + py * py);
var ml = Math.sqrt(this.dx * this.dx + this.dy * this.dy);
var mx = this.dx / ml;
var my = this.dy / ml;
px = px / pl;
py = py / pl;
if (Math.acos(px * mx + py * my) < player.shieldArcSize * 0.5 && pl < player.shieldRadius) {
px = -px;
py = -py;
this.dx = this.dx - 2.0 * px * (this.dx * px + this.dy * py) + player.dx;
this.dy = this.dy - 2.0 * py * (this.dx * px + this.dy * py) + player.dy;
}
}
},
render: function() {
ctx.moveTo(this.x + this.radius,this.y);
ctx.arc(this.x,this.y,this.radius,0.0,2.0 * Math.PI,false);
}
}
// Game loop
function loop() {
// Tick
player.tick();
for (var i = 0; i < projectiles.length; ++i) {
projectiles[i].tick(player);
}
// Render
ctx.fillStyle = "#555555";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
player.render();
ctx.fillStyle = "white";
ctx.strokeStyle = "black";
ctx.beginPath();
for (var i = 0; i < projectiles.length; ++i) {
projectiles[i].render();
}
ctx.fill();
ctx.stroke();
//
requestAnimationFrame(loop); // Runs the loop at 60hz
}
// "Main Method", executes after the page loads
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
bounds = canvas.getBoundingClientRect();
ctx = canvas.getContext("2d");
player = new Player(90.0,80.0);
for (var i = 0; i < projectiles.length; ++i) {
projectiles[i] = new Projectile(
Math.random() * canvasWidth,
Math.random() * canvasHeight,
Math.random() * 2.0 - 1.0,
Math.random() * 2.0 - 1.0
);
}
loop();
}
})();
</script>
</body>
</html>
I'm trying to make a brick game with a ball and a player (platform). If the ball hits the player, it should go off in the other direction like ping pong. However, it's not detecting the collision.
Here's the code
html:
<canvas id="canvas" width= "400" height= "400"></canvas>
css:
#canvas{border:1px solid black}
Js:
var width = 400
var height = 400
var drawRect = function (x, y) {
ctx.fillRect(x, y, 30, 5)
};
// The Ball constructor
var Player = function () {
this.x = 395
this.y = 395
this.xSpeed = 5;
this.ySpeed = 0;
};
// Update the ball's position based on its speed
Player.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
} else if (this.y < 0) {
this.y = height;
} else if (this.y > height) {
this.y = 0;
}
};
// Draw the ball at its current position
Player.prototype.draw = function () {
drawRect(this.x, this.y);
};
// Set the ball's direction based on a string
Player.prototype.setDirection = function (direction) {
if (direction === "left") {
this.xSpeed = -5;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 5;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var player = new Player();
// An object to convert keycodes into action names
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("html").keydown(function (event) {
var direction = keyActions[event.keyCode];
player.setDirection(direction);
});
var Ball = function () {
this.x = 100;
this.y = 100;
this.xSpeed = -2
this.ySpeed = 3;
};
var circle = function (x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false)
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
}
Ball.prototype.move = function () {
this.x += this.xSpeed
this.y += this.ySpeed
};
Ball.prototype.draw = function () {
circle(this.x, this.y, 3, true);
};
Ball.prototype.checkCollision = function () {
if (this.x < 0 || this.x > 400) {
this.xSpeed = -this.xSpeed
}
if (this.y < 0) {
this.ySpeed = -this.ySpeed
}
};
Ball.prototype.checkCollisionPlayer = function () {
if (this.x === Player.x || this.y === player.y) {
this.ySpeed = -this.ySpeed
this.xSpeed = -this.xSpeed
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
setInterval(function () {
ctx.clearRect(0, 0, 400, 400);
player.draw();
player.move();
ball.draw();
ball.move();
ball.checkCollision();
ball.checkCollisionPlayer();
}, 40);
var ball = new Ball();
Thanks for your support. :)
I've added a simple box collision and update the classes to have the box dimensions of the ball and player. Remember that the ball box has to adjust for radius offset.
update
The kind of collision detection needed for the boxes you have to know side or corner that was hit. I updated the example as a starting point for this but it's needs to have the corners added and I also don't know the optimal detection. The blocks are setup for testing. I hope this helps.
var width = 400
var height = 400
function Brick(x, y, w, h, color) {
this.x = x;
this.y = y;
this.color = color;
this.w = w;
this.h = h;
this.hits = 0;
}
Brick.prototype.draw = function() {
ctx.save();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.fillStyle = "white";
ctx.fillText(this.hits, this.x + 2, this.y + 10);
ctx.restore();
};
var bricks = [
new Brick(80, 120, 15, 15, 'red'),
new Brick(220, 90, 15, 15, 'blue'),
new Brick(340, 100, 50, 20, 'green')
];
// The Ball constructor
var Player = function() {
this.x = 395
this.y = 395
this.xSpeed = 5;
this.ySpeed = 0;
this.w = 30;
this.h = 5;
};
// Update the ball's position based on its speed
Player.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
} else if (this.y < 0) {
this.y = height;
} else if (this.y > height) {
this.y = 0;
}
};
// Draw the ball at its current position
Player.prototype.draw = function() {
ctx.fillRect(this.x, this.y, this.w, this.h);
};
// Set the ball's direction based on a string
Player.prototype.setDirection = function(direction) {
if (direction === "left") {
this.xSpeed = -5;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 5;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var player = new Player();
// An object to convert keycodes into action names
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("html").keydown(function(event) {
var direction = keyActions[event.keyCode];
player.setDirection(direction);
});
var Ball = function() {
this.x = 100;
this.y = 100;
this.xSpeed = -2
this.ySpeed = 3;
this.radius = 3;
};
var circle = function(x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false)
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
}
Ball.prototype.move = function() {
this.x += this.xSpeed
this.y += this.ySpeed
if ((this.y + this.radius) > ctx.canvas.height) {
// floor to ceiling
this.y = 0;
}
};
Ball.prototype.draw = function() {
circle(this.x, this.y, this.radius, true);
};
Ball.prototype.getBox = function() {
return {
x: this.x - this.radius,
y: this.y - this.radius,
w: this.radius * 2,
h: this.radius * 2
};
};
Ball.prototype.checkCollision = function() {
if (this.x < 0 || this.x > 400) {
this.xSpeed = -this.xSpeed
}
if (this.y < 0) {
this.ySpeed = -this.ySpeed
} else {
var boxA = this.getBox();
switch (boxCollide(boxA, player)) {
case 1:
case 3:
this.ySpeed = -this.ySpeed;
break;
case 2:
case 4:
this.xSpeed = -this.xSpeed;
break;
}
}
};
// does box a collide with box b
// box = {x:num,y:num,w:num,h:num}
function boxCollide(a, b) {
var ax2 = a.x + a.w;
var ay2 = a.y + a.h;
var bx2 = b.x + b.w;
var by2 = b.y + b.h;
// simple hit true, false
//if (ax2 < b.x || a.x > bx2 || ay2 < b.y || a.y > by2) return false;
// return true
var xInRange = (a.x >= b.x && a.x <= bx2 || ax2 >= b.x && ax2 <= bx2);
var yInRange = (a.y >= b.y && a.y <= by2 || ay2 >= b.y && ay2 <= by2);
// Clockwise hit from top 1,2,3,4 or -1
if (ay2 > b.y && a.y < by2 && xInRange) return 1; // A hit the top of B
if (a.x < bx2 && ax2 > b.x && yInRange) return 2; // A hit the right of B
if (a.y < by2 && ay2 > b.y && xInRange) return 3; // A hit the bottom of B
if (ax2 > b.x && a.x < bx2 && yInRange) return 4; // A hit the right of B
return -1; // nohit
}
Ball.prototype.checkCollisionPlayer = function() {
if (this.x === Player.x || this.y === player.y) {
this.ySpeed = -this.ySpeed
this.xSpeed = -this.xSpeed
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
setInterval(function() {
ctx.clearRect(0, 0, 400, 400);
player.draw();
player.move();
ball.draw();
ball.move();
ball.checkCollision();
ball.checkCollisionPlayer();
var boxA = ball.getBox();
for (var i = 0; i < bricks.length; i++) {
switch (boxCollide(boxA, bricks[i])) {
case 1:
ball.y = bricks[i].y - ball.radius - 1;
ball.ySpeed = -ball.ySpeed;
bricks[i].hits++;
break;
case 3:
ball.y = bricks[i].y + ball.radius + bricks[i].h + 1;
ball.ySpeed = -ball.ySpeed;
bricks[i].hits++;
break;
case 2:
ball.x = bricks[i].x + ball.radius + bricks[i].w + 1;
ball.xSpeed = -ball.xSpeed;
bricks[i].hits++;
break;
case 4:
ball.x = bricks[i].x - ball.radius - 1;
ball.xSpeed = -ball.xSpeed;
bricks[i].hits++;
break;
}
bricks[i].draw();
}
},
40);
var ball = new Ball();
#canvas {
border: 1px solid black
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>