Why is my ball bouncing off of nothing? - javascript

Im making a simple pong game and when you move the red box up with 'w' the ball still bounces on nothing back to the left. I feel like maybe the bounding box is set up incorrectly to the left side. I cant figure out what I did wrong?
var canvas;
var context;
var timer;
var interval = 1000 / 60;
var player1;
var player2;
var ball;
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
//player = new Player();
player1 = new GameObject();
player2 = new GameObject();
ball = new GameObject();
timer = setInterval(animate, interval);
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
ball.move();
//Move the Player to the right
if (w) {
console.log("");
player1.y += -8;
}
if (s) {
console.log("");
player1.y += 8;
}
if (d) {
console.log("");
player2.y += -8;
}
if (u) {
console.log("");
player2.y += 8;
}
if (player1.y > canvas.height - player1.height / 2) {
player1.y = canvas.height - player1.height / 2;
}
if (player1.y < player1.height / 2) {
player1.y = player1.height / 2;
}
if (player2.y > canvas.height - player2.height / 2) {
player2.y = canvas.height - player2.height / 2;
}
if (player2.y < player2.height / 2) {
player2.y = player2.height / 2;
}
//bounce
if (ball.x > canvas.width - ball.width / 2) {
ball.vx = -ball.vx;
//ball.x = 300;
color = "#ff0000";
}
if (ball.x < 0 + ball.width / 2) {
//this flips it if its a negative sign.
ball.vx = -ball.vx;
//ball.x = 300;
color = "#FF4500";
}
//-------------------------------------------------------
//Define Booleans for each key
var w = false;
var s = false;
var u = false;
var d = false;
//Add Event Listeners
document.addEventListener("keydown", press);
document.addEventListener("keyup", release);
document.addEventListener("keydown", presss);
document.addEventListener("keyup", releases);
//Event Functions
function press(e) {
//---This logs key codes into the browser's console.
console.log("Pressed" + e.keyCode);
if (e.keyCode == 87) {
w = true;
}
if (e.keyCode == 83) {
s = true;
}
}
function release(e) {
//---This logs key codes into the browser's console.
//console.log("Released" + e.keyCode);
if (e.keyCode == 87) {
w = false;
}
if (e.keyCode == 83) {
s = false;
}
}
function presss(e) {
//---This logs key codes into the browser's console.
//console.log("Pressed" + e.keyCode);
if (e.keyCode == 40) {
u = true;
}
if (e.keyCode == 38) {
d = true;
}
}
function releases(e) {
//---This logs key codes into the browser's console.
//console.log("Released" + e.keyCode);
if (e.keyCode == 40) {
u = false;
}
if (e.keyCode == 38) {
d = false;
}
}
// JavaScript Document
function GameObject() {
//player's location
this.x = canvas.width / 4;
this.y = canvas.height / 2;
//player's dimensions
this.width = 50;
this.height = 250;
//barriers
//ballss velocity or speed on each axis
this.vx = 8;
this.vy = 0;
//player's color
var red = "#ff0000";
this.blue = "#0000FF";
this.color = "#ff0000";
this.other = "#0000FF";
//This draws the player to the screen
this.drawRect = function() {
context.save();
context.fillStyle = this.color;
context.translate(this.x, this.y);
context.fillRect((-this.width / 2), (-this.height / 2), this.width, this.height);
context.restore();
}
this.second_drawRect = function() {
context.save();
context.fillStyle = this.blue;
context.translate(canvas.width / 1.5, this.y);
context.fillRect((-this.width / 2), (-this.height / 2), this.width, this.height);
context.restore();
}
this.drawCircle = function() {
context.save();
context.fillStyle = this.color;
context.translate(this.x, this.y);
context.beginPath();
context.arc(0, 0, 50, 0, 360 * Math.PI / 180, true)
context.fill();
context.stroke();
//context.fillRect((-this.width/2), (-this.height/2), this.width, this.height);
context.restore();
}
//This changes the player's position
this.move = function() {
this.x += this.vx;
this.y += this.vy;
}
this.left = function() {
return this.x - this.width / 1;
}
this.right = function() {
return this.x + this.width / 2;
}
this.top = function() {
return this.y - this.height / 4;
}
this.bottom = function() {
return this.y + this.height / 4;
}
//////////////////////////////////////////////////////////////
this.leftt = function() {
return this.x - this.width / 2;
}
this.rightt = function() {
return this.x + this.width / 2;
}
this.topp = function() {
return this.y - this.height / 2;
}
this.bottomm = function() {
return this.y + this.height / 2;
}
this.hitTestObject = function(obj) {
if (this.left() < obj.right() &&
this.right() > obj.left() &&
this.top() < obj.bottom() &&
this.bottom() > obj.top()) {
return true
}
return false;
}
}
<canvas id="canvas" width = "1024" height ="800" >
Your browser is outdated and does not support HTML5. Please update to the latest version.
</canvas>

Related

My collision detection code is wrong and idk where is the problem and how to fix it?

I know how to put where my collision function is now but as you can see my function is wrong and I would like some help, please.
Here's my collison function
this.cd = function(){
ctx.clearRect(x,y1,width,y1 - y2);
if (myPlayer.x >= myObstacles.x || myPlayer.x <= myObstacles.x + myObstacles.width || myPlayer.y >= 0 || myPlayer.y <= myObstacles.yStart){
alert('GAME OVER');
clearInterval(interval);
}else if (myRectangle.x >= myObstacles.x || myPlayer.x <= myObstacles.x + myObstacles.width || myPlayer.y >= myObstacles.yEnd || myPlayer.y <= myObstacles.height){
alert('GAME OVER');
clearInterval(interval);
}else{
}
}
And here's my full code
let b1 = document.getElementById('button1');
let c = document.getElementById('myCanvas');
let ctx = c.getContext('2d');
//Control movements of the player
// document.addEventListener('keydown', keyDownHandler, false);
// document.addEventListener('keyup', keyUpHandler, false);
// var rightPressed = false;
// var leftPressed = false;
// var upPressed = false;
// var downPressed = false;
// function keyDownHandler(e) {
// //Right arrow key
// if(e.keyCode == 39) {
// rightPressed = true;
// }
// //Left arrow key
// else if(e.keyCode == 37) {
// leftPressed = true;
// }
// //Down arrow key
// if(e.keyCode == 40) {
// downPressed = true;
// }
// //Up arrow key
// else if(e.keyCode == 38) {
// upPressed = true;
// }
// }
//make a component for rectangle and obstacle
let myPlayer;
let timerID;
let H_gap = 250;
class Obstacles {
constructor(x, y, width, height, color) {
// vars
this.x = x;
this.y = y;
this.width = width;
this.color = color;
this.gap = Math.floor(Math.random() * 30 + 1) + 50; //50 - 150 random generated
this.y1 = Math.floor(Math.random() * (c.height - 40 - 40 + 1)) + 40; // prevent gap is too high or too low
this.y2 = this.y1 + this.gap; // define y2 (start point of lower rect)
// functions of obstacles
this.draw = function () {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, 0, this.width, this.y1);
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y2, this.width, c.height);
}
this.move = function () {
ctx.clearRect(this.x, 0, this.width, this.y1);
ctx.clearRect(this.x, this.y2, this.width, c.height);
this.x -= 10;
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, 0, this.width, this.y1);
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y2, this.width, c.height);
}
// this.cd = function(){
// ctx.clearRect(x,y1,width,y1 - y2);
// if (myPlayer.x >= myObstacles.x || myPlayer.x <= myObstacles.x + myObstacles.width || myPlayer.y >= 0 || myPlayer.y <= myObstacles.yStart){
// alert('GAME OVER');
// clearInterval(interval);
// }else if (myRectangle.x >= myObstacles.x || myPlayer.x <= myObstacles.x + myObstacles.width || myPlayer.y >= myObstacles.yEnd || myPlayer.y <= myObstacles.height){
// alert('GAME OVER');
// clearInterval(interval);
// }else{
// }
// }
}
}
class Player {
constructor(x, y, width, height, color) {
// vars
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
// functions of player
this.draw = function () {
// ctx.clearRect(0,0,480,320);
// if(rightPressed) {
// playerX += 5;
// }
// else if(leftPressed) {
// playerX -= 5;
// }
// if(downPressed) {
// playerY += 5;
// }
// else if(upPressed) {
// playerY -= 5;
// }
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
}
b1.addEventListener('click', gameStart)
function gameStart() {
// pre load stuffs onto the screen
myPlayer = new Player(30, 240, 30, 30, "red")
myPlayer.draw();
myObstacles = [];
myObstacles.push(new Obstacles(350, 0, 50, 320, "green"));
myObstacles.push(new Obstacles(350 + H_gap, 0, 50, 320, "green"));
myObstacles.push(new Obstacles(350 + 2 * H_gap, 0, 50, 320, "green"));
myObstacles.push(new Obstacles(350 + 3 * H_gap, 0, 50, 320, "green"));
for (let i = 0; i < myObstacles.length; i++) {
myObstacles[i].draw();
}
clearInterval(updateGame);
timerID = setInterval(updateGame, 100) // set updategame timer
}
function updateGame() {
// update the rect
for (let i = 0; i < myObstacles.length; i++) {
myObstacles[i].move();
}
// check if obstacles outside of canvas
if (myObstacles[0].x < -50) {
myObstacles.shift();
n_x = myObstacles[myObstacles.length - 1].x
myObstacles.push(new Obstacles(n_x + H_gap, 0, 50, 320, "green"));
}
}

Creating orbiting weapon sprite with JS canvas creates animation errors/glitches

I am trying to make a game in which a player has an equippable weapon. As of now, I have set this weapon to be an image of a bow, and I want to have said weapon to move around the player while facing the mouse. This is similar to buildroyale.io, where the player rotates along with his weapon to face the mouse.
As of now, with the help of #Justin, I've got the bow rotating (somewhat) on the screen. It only shows up when the left click is down, as desired, but does not rotate as expected. Here is a clip showcasing how it moves: clip
Here is the code I use:
class EventHandler {
equip_weapon() {
if (holding) {
player.weapon = player.bag.slot_1;
canv.globalAlpha = 1;
player.weapon.equip();
player.weapon.update();
}
}
}
class Weapon {
image_path;
constructor(image_path) {
this.x = player.x + 30;
this.y = player.y + 30;
this.width = 120;
this.height = 120;
this.angle = 0;
this.distance = 50;
this.image = image_path;
}
equip() {
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
canv.save();
canv.translate(this.x, this.y);
canv.rotate(this.angle);
canv.drawImage(this.image, this.distance, -this.height/2, this.width, this.height);
canv.restore();
}
update() {
this.x = player.x + player.width / 2;
this.y = player.y + player.height / 2;
}
}
bow = new Weapon(bow_image);
player.bag.slot_1 = bow;
aim_bounds = document.documentElement.getBoundingClientRect();
class Player {
constructor() {
this.name = null;
this.speed = 5;
this.skin = player_sheet;
this.can_move = true;
this.is_moving = false;
this.width = 68;
this.height = 68;
this.scale = 1;
this.x = 566;
this.y = 316;
this.direction = facing.down;
this.frame = 0;
this.shadow_offset = 25;
this.frame_rate = 10;
this.health = 100;
this.clip_amount = 10;
this.weapon = null;
// Player inventory
this.bag = {
slot_1 : null,
slot_2 : null,
slot_3 : null,
slot_4 : null,
slot_5 : null,
offhand : null,
armor : null
}
this.is_menu_open = false;
console.log("Player constructed!");
}
update() {
// Animation updates
if (game.tick % this.frame_rate == 0 && this.is_moving && !this.is_menu_open) {
this.frame += 68;
if (this.frame >= 272) { this.frame = 0; }
} else if (!this.is_moving) { this.frame = 0; }
// Movement updates
if (this.can_move) {
if (controller.up) { this.direction = facing.up; this.y -= this.speed; this.is_moving = true; }
else if (controller.down) { this.direction = facing.down; this.y += this.speed; this.is_moving = true; }
else if (controller.left) { this.direction = facing.left; this.x -= this.speed; this.is_moving = true; }
else if (controller.right) { this.direction = facing.right; this.x += this.speed; this.is_moving = true; }
if (!controller.up && !controller.down && !controller.left && !controller.right) { this.is_moving = false; }
}
// Checks
if (this.is_menu_open) { this.can_move = false; } else { this.can_move = true; }
document.getElementById("health_bar").value = this.health;
if (this.is_menu_open) { menu.style.display = "block"; } else { menu.style.display = "none"; }
}
animate() {
// Player shadow
canv.drawImage(player_shadow, this.x, this.y + this.shadow_offset);
// Player
canv.globalAlpha = 1;
canv.drawImage(player_sheet, (sprite.x + this.frame), (sprite.y * this.direction),
sprite.width, sprite.height,
this.x, this.y,
this.width, this.height);
}
}
Here is a download to my current code in case you need more to debug: game.zip
The way I handle this is to make sure my image is first oriented correctly. In my case my bow image would look like this (ignore the quality). Just see that it faces right.
In the draw function I use translate() to position the image and I use the x and y inside the drawImage(img, x, y, w, h) to draw the image centered along the top edge of the canvas. The x (set to 50 in this example) position is essentially the radius of the image rotation and the y is just to center my bow's arrow on the y axis of the canvas.
Using Math.atan2() I can rotate the image
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
In this snippet I have two lines that are commented out. If you uncomment them you will better see what is happening.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;
let mouse = {x: 10, y: 10}
let canvasBounds = canvas.getBoundingClientRect();
canvas.addEventListener('mousemove', e => {
mouse.x = e.x - canvasBounds.x
mouse.y = e.y - canvasBounds.y
})
let bow = new Image();
bow.src = "https://lh3.googleusercontent.com/g5Sr3HmGZgWx07sRQMvgvtxZ-ErhWNT0_asFdhLIlw-EQMTuUq3BV3YY8d5rrIrZBiJ-Uo2l836Qlmr8dmaCi-dcCCqN6veS6xnE8jSrmdtRtZKnmF5FQ5aTxuVBgB28n6ICoxSlpA=w2400";
class Weapon {
constructor() {
this.x = 200;
this.y = 200;
this.w = 60;
this.h = 60;
this.angle = 0
}
draw() {
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
//ctx.fillStyle = 'lightgrey';
//ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(bow, 50, -this.h/2, this.w, this.h)
ctx.restore();
}
}
let bowArrow = new Weapon();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
bowArrow.draw();
requestAnimationFrame(animate)
}
animate();
<canvas id="canvas"></canvas>
UPDATE:
Here is what I changed in your files and it works well on my end.
engine.controller.js change mousemove and add listener for resize. I'm also pretty sure there's a way you can get rid of the getMouse function since the listener below gets mouse coordinates for you.
canvas.addEventListener("mousemove", function (event) {
mouse_position = event
mouse.x = event.x - canvas_bounds.x;
mouse.y = event.y - canvas_bounds.y;
})
window.addEventListener('resize', () => {
canvas_bounds = canvas.getBoundingClientRect();
})
engine.eventhandler.js
class Weapon {
image_path;
constructor(image_path) {
this.x = player.x + player.width/2;
this.y = player.y + player.height/2;
this.w = 60;
this.h = 60;
this.angle = 0;
this.image = image_path;
}
equip() {
this.x = player.x + player.width/2;
this.y = player.y + player.height/2;
this.angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
canv.save();
canv.translate(this.x, this.y);
canv.rotate(this.angle);
canv.drawImage(this.image, 50, -this.h/2, this.w, this.h);
canv.restore();
}
}
engine.main.js
function setup() {
game = new Game;
player = new Player;
controller = new Controller;
event_handler = new EventHandler;
canvas.width = 1200;
canvas.height = 700;
canvas_bounds = canvas.getBoundingClientRect();
// REMOVE LATER
bow = new Weapon(bow_image);
player.bag.slot_1 = bow;
document.getElementById("bag").style.display = "block";
}
engine.setup.js
// Weapon stuff
var weapon_equiped = false;
var canvas = document.getElementById("canvas");
let mouse = {
x : 10,
y : 10
}
let canvas_bound;
var mouse_position, holding;
var rect, mouse_x, mouse_y;
...and
//you have a space between canvas. height in both fillRect
canv.fillRect(0, 0, canvas.width, canvas. height);
I think that's all I changed. Pretty sure you can use your mouse_x or the mouse.x but you probably don't need both in your code.

Stop user from scrolling using arrow keys while canvas based game is running

I have a canvas game in my webpage and it operates with arrow key controls, but whenever somebody tries to play it the page scrolls. Is there any way I can prevent it? The code for my game is here. All I need is for the page to not be bouncing up and down whenever somebody is trying to play. I know it would be easier to just use the wasd keys but to me that feels like putting duct tape on a leak on the hull of a boat instead of actually fixing it. Any suggestions? I'm using google apps script HTML service so I'm not sure if using jquery is possible or if it is whether its going going to be hours and hours of work that are eventually ditched in favor of a quicker solution. Anyways, hope somebody can help.
<h1> example html</h1>
<p>exampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTMLexampleHTML</p>
<h2>example html </h2>
<canvas id='my' width = '640' height = '480' style = 'display: none;'></canvas>
<script>
var paused = false
function PausePlay(){
if (paused === false)
{paused = true;}
else{paused = false;}
}
var canvas = document.getElementById("my");
var ctx = canvas.getContext("2d");
function paddle(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speedModifier = 0;
this.hasCollidedWith = function(ball) {
var paddleLeftWall = this.x;
var paddleRightWall = this.x + this.width;
var paddleTopWall = this.y;
var paddleBottomWall = this.y + this.height;
if (ball.x > paddleLeftWall &&
ball.x < paddleRightWall &&
ball.y > paddleTopWall &&
ball.y < paddleBottomWall) {
return true;
}
return false;
};
this.move = function(keyCode) {
var nextY = this.y;
if (keyCode == 40) {
nextY += 5;
this.speedModifer = 1.5;
} else if (keyCode == 38) {
nextY += -5;
this.speedModifier = 1.5;
} else {
this.speedModifier = 0;
}
nextY = nextY < 0 ? 0 : nextY;
nextY = nextY + this.height > 480 ? 480 - this.height : nextY;
this.y = nextY;
};
}
var player = new paddle(5, 200, 25, 100);
var ai = new paddle(610, 200, 25, 100);
var ball = {
x: 320,
y: 240,
radius: 7,
xSpeed: 2,
ySpeed: 0,
playerscore: 0,
aiscore: 0,
reverseX: function() {
this.xSpeed *= -1;
},
reverseY: function() {
this.ySpeed *= -1;
},
reset: function() {
alert('The score is now ' + this.playerscore + ' to ' + this.aiscore);
this.x = 20;
this.y = 24;
this.xSpeed = 2;
this.ySpeed = 0;
},
isBouncing: function() {
return ball.ySpeed != 0;
},
modifyXSpeedBy: function(modification) {
modification = this.xSpeed < 0 ? modification * -1 : modification;
var nextValue = this.xSpeed + modification;
nextValue = Math.abs(nextValue) > 9 ? 9 : nextValue;
this.xSpeed = nextValue;
},
modifyYSpeedBy: function(modification) {
modification = this.ySpeed < 0 ? modification * -1 : modification;
this.ySpeed += modification;
}
};
function tick() {
updateGame();
draw()
window.setTimeout("tick()", 1000 / 60);
}
function updateGame() {
if (paused === false){
ball.x += ball.xSpeed;
ball.y += ball.ySpeed;
if (ball.x < 0) {
ball.reset();
ball.aiscore = ball.aiscore + 1;
}
if (ball.x > 640) {
ball.reset();
ball.playerscore = ball.playerscore + 1
}
if (ball.y <= 0 || ball.y >= 480) {
ball.reverseY();
}
var collidedWithPlayer = player.hasCollidedWith(ball);
var collidedWithAi = ai.hasCollidedWith(ball);
if (collidedWithPlayer || collidedWithAi) {
ball.reverseX();
ball.modifyXSpeedBy(0.25);
var speedUpValue = collidedWithPlayer ? player.speedModifier : ai.speedModifier;
ball.modifyYSpeedBy(speedUpValue);
}
for (var keyCode in heldDown) {
player.move(keyCode);
}
var aiMiddle = ai.y + (ai.height / 2);
if (aiMiddle < ball.y) {
ai.move(40);
}
if (aiMiddle > ball.y) {
ai.move(38);
}
}
}
function draw() {
if(paused === false){
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 640, 480);
renderPaddle(player);
renderPaddle(ai);
renderBall(ball);
}
}
function renderPaddle(paddle) {
ctx.fillStyle = "blue";
ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
}
function renderBall(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = "pink";
ctx.fill();
}
var heldDown = {};
window.addEventListener("keydown", function(keyInfo) {
heldDown[event.keyCode] = true;
}, false);
window.addEventListener("keyup", function(keyInfo) {
delete heldDown[event.keyCode];
}, false);
function playPong(){
canvas.style.display = 'block';
tick()
}
function show(){
var canvas = document.getElementById('my')
canvas.style.display = 'block';
}
</script>
<div>
<button onclick = 'hide()'> Hide or show the games</button>
<br>
<button onclick = 'PausePlay()'> Pause/play games</button>
<br>
</div>
<br><br><br><br>
<button onclick = 'playPong()'> Play pong </button>
You may use overflow: hidden; CSS property in order to control the ability of scrolling. If you need to prevent vertical/horizontal scrolling only, so you may use overflow-x and overflow-y More about overflow property here.

Html 5 Collision Between Points on an Arc

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>

Collision between ball and paddle in pong game on canvas

The ball seems to bounce off one side of the paddle, but when it comes from the side it glitches through the paddle. I just can't find a way behind it and it really bothers me. I am using some logic gates to define where the ball's direction is need to be invereted
function startGame() {
GameArea.start();
Ball1 = new CircleComp('white' , window.innerWidth - 200 , window.innerHeight - 20);
Ball1.ySpeed = 13.5;
Ball1.xSpeed = 6;
Paddle1 = new PaddleComp( 87, 83, 0, window.innerHeight / 2.5, 10, 70);
Paddle2 = new PaddleComp( 38, 40, window.innerWidth - 10, window.innerHeight / 2.5, 10 , 70);
}
var GameArea = {
canvas : canvas = document.querySelector("canvas"),
start : function (){
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.ctx = this.canvas.getContext('2d');
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
GameArea.keys = (GameArea.keys || []);
GameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
GameArea.keys[e.keyCode] = false;
})
},
clear : function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function CircleComp(color, x , y){
this.x = x;
this.y = y;
this.width = 8;
this.height = 8;
var context1 = GameArea.ctx;
this.update = function(){
context1.beginPath();
context1.fillStyle = color;
context1.fillRect(this.x, this.y, this.width, this.height);
context1.fill();
context1.stroke();
this.updatePosition();
}
this.updatePosition = function(){
this.y += this.ySpeed;
this.x += this.xSpeed;
if(this.x + this.width > GameArea.canvas.width){
this.xSpeed = -this.xSpeed;
}
if(this.y + this.height > GameArea.canvas.height){
this.ySpeed = -this.ySpeed;;
}
if(this.x - this.width < 0){
this.xSpeed = -this.xSpeed;
}
if(this.y - this.height < 0){
this.ySpeed = -this.ySpeed;
}
if(this.y + this.height > Paddle2.y && this.y - this.width < (Paddle2.y + 130) && this.x + this.width > Paddle2.x ){
this.xSpeed = -this.xSpeed;
}
if(this.y + this.height > Paddle1.y && this.y - this.width < (Paddle1.y + 70) && this.x - this.height < Paddle1.x + 10){
this.xSpeed = -this.xSpeed;
}
}
}
function PaddleComp(Upkey, Downkey, x, y, width, height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.ySpeed = 0;
var context2 = GameArea.ctx;
this.update = function(){
context2.fillStyle = 'white';
context2.fillRect(x,this.y,this.width,this.height);
this.updatePosition();
}
this.updatePosition = function() {
this.ySpeed = 0;
if (GameArea.keys && GameArea.keys[Upkey]) {
this.ySpeed = -15; //console.log('Up');
}
if (GameArea.keys && GameArea.keys[Downkey]) {
this.ySpeed = 15; //console.log('Down');
}
if ((GameArea.keys && GameArea.keys[Downkey]) && this.y + 130 > window.innerHeight){
this.ySpeed = this.ySpeed -15 ;
}
if ((GameArea.keys && GameArea.keys[Upkey]) && this.y < 0 ){
this.ySpeed = this.ySpeed +15 ;
}
this.y += this.ySpeed;
}
}
function updateGameArea(){
GameArea.clear();
Paddle1.update();
Paddle2.update();
Ball1.update();
}
<html>
<head>
<meta charset='urf-8'>
<style>
canvas{
border: 0px solid black;
background-color: black;
}
body{
margin: 0;
overflow: hidden;
}
</style>
</head>
<body onload='startGame()'>
<canvas></canvas>
<script src='Pong.js'></script>
</body>
</html>
Could not see directly what the problem was with your code so i just rewrote the code with the ball, bat (paddle) test function in the ball Object and called from the players object. ball.checkPad(player); tests if the ball has hit the players bat. To help picture what is happening I have slowed it all down and made the bats real phat. When the ball hits the bat it will turn yellow and the bat red for a second or so.
There is plenty of comments in the parts you asked about,
Hope it helps
Demo copied from OP question.
const setting = {
speed : 2, // of ball
left : 0,
width : 400,
height : 200,
padWidth : 50,
padHeight : 80,
padSpeed : 4, // double balls
hitPauseCount : 30, // nuber of frames to hold when there is a collisiotn so you
// can check all is good
}
const keys = {
ArrowUp : false,
ArrowDown : false,
ArrowLeft : false,
ArrowRight : false,
keyEvent(e) { // dont use keyCode it has depreciated
if (keys[e.code] !== undefined) {
keys[e.code] = e.type === "keydown";
e.preventDefault();
}
}
}
var ctx;
var ball1, paddle1, paddle2;
var gameArea = {
start() {
canvas.width = setting.width;
canvas.height = setting.height;
ctx = canvas.getContext('2d');
requestAnimationFrame(updateGameArea);
},
clear() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
}
gameArea.start();
ball = new CircleComp('white', window.innerWidth - 200, window.innerHeight - 20);
ball.ySpeed = setting.speed;
ball.xSpeed = setting.speed;
paddle1 = new PaddleComp("ArrowUp", "ArrowDown", setting.left, setting.height / 2, setting.padWidth, setting.padHeight);
paddle2 = new PaddleComp("ArrowLeft", "ArrowRight", setting.width - setting.padWidth, setting.height / 2, setting.padWidth, setting.padHeight);
window.addEventListener('keydown', keys.keyEvent);
window.addEventListener('keyup', keys.keyEvent);
function CircleComp(color, x, y) {
this.x = x;
this.y = y;
this.width = 8;
this.height = 8;
this.xSpeed = setting.speed;
var hit = 0;
var restartCount;
var serveDirection;
this.reset = function(){
this.x = ctx.canvas.width /2;
this.y = ctx.canvas.height / 2;
this.xSpeed = -this.xSpeed
this.ySpeed = setting.speed * Math.sign(Math.random() - 0.5);
restartCount = 60;
}
this.draw = function () {
if(hit > 0){
hit -= 1;
ctx.fillStyle = "yellow";
}else{
ctx.fillStyle = color;
}
ctx.fillRect(this.x, this.y, this.width, this.height);
}
// next funtion is called by the player objects
this.checkPad = function (player) {
if (player.x > canvas.width / 2) { // is player on left or right
if (this.xSpeed > 0) { // player on right only check if ball moving rigth
if (this.x + this.width > player.x) { // ball is in paddles zone
//if not bottom of ball above top of bat or top of ball bellow bottom of bat
if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
// ball and bat in contact
// is ball moving down and the balls top edge above the player
// then ball has hit the top side of the bat
if(this.ySpeed > 0 && this.y <= player.y){
this.y = player.y - this.width;
this.ySpeed = -setting.speed;
}else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
this.y = player.y + player.height;
this.ySpeed = setting.speed;
}else{ // ball hit front of bat
this.x = player.x - this.width;
this.xSpeed = - setting.speed;
}
player.hit = setting.hitPauseCount; // counters to show FX when a hit happens
hit = setting.hitPauseCount;
}
}
}
} else { // player must be left
if (this.xSpeed < 0) { // ball must move left
if (this.x < player.x + player.width) { // ball is in paddles zone
if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
// ball and bat in contact
// ball and bat in contact
// is ball moving down and the balls top edge above the player
// then ball has hit the top side of the bat
if(this.ySpeed > 0 && this.y <= player.y){
this.y = player.y - this.width;
this.ySpeed = -setting.speed;
}else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
this.y = player.y + player.height;
this.ySpeed = setting.speed;
}else{ // ball hit front of bat
this.x = player.x + player.width;
this.xSpeed = setting.speed;
}
player.hit = setting.hitPauseCount; // counters to show FX when a hit happens
hit = setting.hitPauseCount;
}
}
}
}
}
this.update = function () {
if(restartCount > 0){ // wait for restart pause
restartCount -= 1;
}else{
if(hit > 0){ // do nothing if paused
return;
}
this.y += this.ySpeed;
this.x += this.xSpeed;
if (this.x + this.width >= canvas.width) {
this.reset(); // point
} else if (this.x < 0) {
this.reset(); // point
}
if (this.y + this.height >= canvas.height) {
this.y = canvas.height - this.height;
this.ySpeed = -setting.speed;
} else if (this.y < 0) {
this.y = 0;
this.ySpeed = setting.speed;
}
}
}
this.reset();
}
function PaddleComp(upKey, downKey, x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.hit = 0;
this.draw = function () {
if(this.hit > 0){
this.hit -= 1;
ctx.fillStyle = "red";
}else{
ctx.fillStyle = '#9CF';
}
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.update = function () {
if (keys[upKey]) {
this.y -= setting.padSpeed;
};
if (keys[downKey]) {
this.y += setting.padSpeed;
};
if (this.y < 0) {
this.y = 0;
}
if (this.y + this.height >= canvas.height) {
this.y = canvas.height - this.height;
}
ball.checkPad(this);
}
}
function updateGameArea() {
gameArea.clear();
paddle1.update();
paddle2.update();
ball.update();
paddle1.draw();
paddle2.draw();
ball.draw();
requestAnimationFrame(updateGameArea);
}
<canvas id=canvas style='background:#69C;border:2px blue solid'></canvas>

Categories