I'm fairly new to game programming, and made a simple platformer game with JS.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
player = {
x: 0,
y: canvas.height - 25,
velX: 0,
velY: 0,
speed: 5,
width: 25,
height: 25,
friction: 0.9,
gravity: 0.2,
jumping: false
},
keys = [];
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
function rect(x, y, width, height, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
ctx.fillStyle = 'black';
}
function update() {
if (keys[87]) {
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed * 2;
}
}
if (keys[68]) {
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[65]) {
if (player.velX > -player.speed) {
player.velX--;
}
}
if (player.x >= canvas.width - player.width) {
player.x = canvas.width - player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= canvas.height - player.height) {
player.y = canvas.height - player.height;
player.jumping = false;
}
player.x += player.velX;
player.y += player.velY;
player.velX *= player.friction;
player.velY += player.gravity;
ctx.clearRect(0, 0, canvas.width, canvas.height);
rect(player.x, player.y, player.width, player.height, 'black');
requestAnimationFrame(update);
}
requestAnimationFrame(update);
<!doctype html>
<html>
<head>
<title>Platformy stuff</title>
</head>
<body>
<canvas id="canvas" style="border:1px solid #000" width=1339 height=619></canvas>
<script src='game.js'></script>
</body>
</html>
This is the problem. I made this condition:
if (player.y >= canvas.height - player.height) {
player.y -= canvas.height - player.height;
player.jumping = false;
}
So as you can see, this was suppose to prevent the player from falling out of the canvas. So If the player got push out by the gravity player.y += gravity, the condition would set it back to the bottom of the canvas. However, It doesn't really work out. I would be glad if someone could help me with this, thanks.
I cant seem to edit or do not see an edit link/button so here is another answer:
To fix this just put your check code for the payer below canvas above your check for the keypress of key 87 and set velocity to 0.
In other words put the test for the "player is below canvas" as first check in update function. This will work and is tested. Although you may want to gradually nudge the player back up instead of abruptly moving to the edge. And set the velocity to 0. Now to nudge him you could gradually set to 0 based on how far down the payer is. Ill leave that to you.
function update() {
if (player.y >= canvas.height - player.height) {
player.jumping = false;
player.y = canvas.height - player.height;
player.velY = 0;
}
if (keys[87]) {...
}
Looks like you subtracting the canvas height combined with the player height and you want it to be set to it instead to keep it at the edge. Simply remove the - from -=.
player.y = canvas.height - player.height;
Related
I am working on a little platformer game. The player is a circle, and I am going to implement the obstacles as rectangles. Does anyone know how to make sure the player can't go through the obstacle? I have tried some methods, but they come out glitchy.
Here is what I have so far (It is a bit long, so the method that I need is inside the resolveCollision function):
var canvas = document.createElement("CANVAS");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.id = "CANVAS";
document.body.appendChild(canvas);
document.body.style.margin = "0px 0px 0px 0px";
document.body.style.overflow = "hidden";
document.body.style.backgroundColor = "#202020";
var ctx = canvas.getContext("2d");
var objects = [];
var player = {
x: window.innerWidth / 2 - 25,
y: 0,
height: 25,
width: 25,
old: {
x: 0,
y: 0,
},
velocity: {
x: 0,
y: 0,
},
jumping: true,
color: "#ff0000",
};
var obstacle = {
x: 50,
y: 300,
width: 50,
height: 50
}
var control = {
left: false,
right: false,
up: false,
keyListener: function (event) {
var keyState;
if (event.type == "keydown") {
keyState = true;
} else {
keyState = false;
}
switch (event.keyCode) {
case 37:
control.left = keyState;
break;
case 38:
control.up = keyState;
break;
case 39:
control.right = keyState;
break;
}
}
};
var checkCollision = function (object) {
var distX = Math.abs(player.x - object.x - object.width / 2);
var distY = Math.abs(player.y - object.y - object.height / 2);
if (distX > (object.width / 2 + (player.width + player.height) / 2)) { return false; }
if (distY > (object.height / 2 + (player.width + player.height) / 2)) { return false; }
if (distX <= (object.width / 2)) { return true; }
if (distY <= (object.height / 2)) { return true; }
var dx = distX - object.width / 2;
var dy = distY - object.height / 2;
return (dx * dx + dy * dy <= ((player.width + player.height) / 2 * (player.width + player.height) / 2));
}
var resolveCollision = function (object) {
// Add Resolve Collision Code
if (checkCollision(object)) {
throw new SyntaxError("Couldn't resolve collision between player and object!");
}
}
var renderFrame = function () {
if (control.up && player.jumping == false) {
player.velocity.y -= 20;
player.jumping = true;
}
if (control.left) {
player.velocity.x -= 0.5;
}
if (control.right) {
player.velocity.x += 0.5;
}
player.velocity.y += 1.5;
player.x += player.velocity.x;
player.y += player.velocity.y;
player.velocity.x *= 0.95;
player.velocity.y *= 0.95;
player.old.x = player.x - player.velocity.x * 1.2;
player.old.y = player.y - player.velocity.y * 1.2;
if (player.y > window.innerHeight - 25) {
player.jumping = false;
player.y = window.innerHeight - 25;
player.velocity.y = 0;
}
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
ctx.fillStyle = player.color;
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.ellipse(player.old.x, player.old.y, player.width, player.height, Math.PI / 4, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.globalAlpha = 1;
ctx.ellipse(player.x, player.y, player.width, player.height, Math.PI / 4, 0, 2 * Math.PI);
ctx.fill();
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
if (checkCollision(obstacle)) {
resolveCollision(obstacle)
}
window.requestAnimationFrame(renderFrame);
};
renderFrame();
window.addEventListener("keydown", control.keyListener);
window.addEventListener("keyup", control.keyListener);
Thanks in advance!
EDIT: I didn't make it clear enough before, but I need a way to resolve collision once they are detected. I have a method to detect collisions already.
You're talking about bounding box and bounding circle calculations.
Here is a real simple explanation of the algorithms for each type of geometry:
https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
Of course if they're all the same shape that may simplify it, one solution would be to convert the circles to boxes:
https://math.stackexchange.com/questions/2360970/how-to-calculate-a-bounding-box-of-a-circle
Then just use bounding box collision detection.
But I think if you want to support both then the general strategy will be to attempt to detect if the Circle intersects with the box.
Here is a description of that algorithm:
https://www.lazyfoo.net/tutorials/SDL/29_circular_collision_detection/index.php
To check if a box and circle collided we need to find the closest point on the box...
Here we find the closest y position much like we did the x position. If the distance squared between the closest point on the box and the center of the circle is less than the circle's radius squared, then there is a collision.
I am trying to make a game with collision detection and resolution. For some reason, when I move the player to the right of the 'enemy blocks', the player moves to the left of the 'enemy'. How can I solve this problem? I have been working on this for hours and cannot find any solution. I am not sure if it is a small problem or if I have to change the whole enemy object.
//declare variables
var body = document.getElementById("body");
var canvas = document.getElementById("canvas");
var iwidth = window.innerWidth;
var iheight = window.innerHeight;
//variable for drawing
var draw = canvas.getContext("2d");
//variables for character paramaters
var playerwidth = 20;
var playerheight = 20;
var playerx = iwidth / 2 - playerwidth / 2;
var playery = iheight / 2 - playerheight / 2;
var playerspeed = 20;
//mouse co-ordinates
var mousex;
var mousey;
//enemy's parameters
var enemyxpositions = [43, 94, 200];
var enemyypositions = [41, 120, 83];
var enemywidths = [12, 43, 45];
var enemyheights = [43, 11, 87];
var i = 0;
var collision = false;
///////////////////////////////////////////////////////////////////////////////////
/////// separating variables and rest of the code ///////
///////////////////////////////////////////////////////////////////////////////////
//puts canvas in top right corner
body.style.margin = "0";
//changes the canvas's style namely color, margin, width and height
canvas.style.backgroundColor = "black";
canvas.style.margin = "0";
canvas.width = iwidth;
canvas.height = iheight;
//the function that the player is drawn in
function drawplayer() {
//allows animation
requestAnimationFrame(drawplayer);
//clears the canvas every time the function runs so that the image doesn't leave a mark
draw.clearRect(0, 0, iwidth, iheight);
//drawing the player
draw.fillStyle = "#ffff00";
draw.fillRect(playerx, playery, playerwidth, playerheight);
draw.fill();
//checking where the mouse is and letting the player follow it
if (mousex > playerx + playerwidth / 2) {
playerx += (mousex - playerx + playerwidth) / playerspeed;
}
if (mousex < playerx + playerwidth / 2) {
playerx -= (playerx - mousex + playerwidth) / playerspeed;
}
if (mousey > playery + playerheight / 2) {
playery += (mousey - playery + playerheight) / playerspeed;
}
if (mousey < playery + playerheight / 2) {
playery -= (playery - mousey + playerheight) / playerspeed;
}
//the obstacles' object
function Enemy(enemyx, enemyy, enemywidth, enemyheight) {
this.enemyx = enemyx;
this.enemyy = enemyy;
this.enemywidth = enemywidth;
this.enemyheight = enemyheight;
this.enemies = function() {
draw.fillStyle = "#0000ff";
draw.fillRect(enemyx, enemyy, enemywidth, enemyheight);
draw.fill();
}
//collision detection
if (mousex + playerwidth / 2 > this.enemyx &&
mousex - playerwidth / 2 < this.enemyx + this.enemywidth &&
mousey + playerheight / 2 > this.enemyy &&
mousey - playerheight / 2 < this.enemyy + this.enemyheight) {
collision = true;
}
else {
collision = false;
}
//collision implementation
//left collision
if (collision == true && mousex + playerwidth / 2 > this.enemyx) {
playerx = this.enemyx - playerwidth;
}
//right collision
else if (collision == true && mousex - playerwidth / 2 < this.enemyx + this.enemywidth) {
playerx = this.enemyx + this.enemywidth + 50;
}
}
//draws all the obstacles
for (i = 0; i < enemyxpositions.length; i++) {
new Enemy( enemyxpositions[i],
enemyypositions[i],
enemywidths[i],
enemyheights[i]).enemies();
}
}
drawplayer();
//gets the mouse co-ordinates
window.onmousemove = function mousepos(event) {
mousex = event.clientX;
mousey = event.clientY;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DUNGE</title>
<style>
::-webkit-scrollbar {
display: none;
}
canvas {
display: block;
}
#obstacles {
opacity: 1;
margin-top: -100vh;
}
</style>
</head>
<body id="body">
<canvas id="canvas"></canvas>
<script src="script.js"></script>
</body>
</html>
Collision resolution is a pretty tricky domain and there are a many approaches you can take. For the purposes of squares with mouse control as in your case, a naive approach might be as follows:
If a collision is detected between a player and an immobile obstacle (enemy, wall, whatever), we can resolve the collision by gradually "undoing" the player's motion until it's no longer colliding with the obstacle.
For example, if on the current frame, the player is moving with a y velocity of 5 and an x velocity of 2 and we detect a collision, then we can avoid the collision by undoing the move. However, this would create an unrealistic air gap between the obstacle and the player that can result in a bouncing effect. Instead, we can slowly move the obstacle's x and y positions by a small value like -0.5 until no collision is detected. However, undoing the move on both axes might be incorrect if only one axis experienced a collision.
Here's an initial attempt at separating the x and y axes into distinct steps:
const canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 180;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
const mouse = {x: 0, y: 0};
const enemy = {x: 130, y: 70, width: 40, height: 40};
const player = {
x: 0, y: 0, width: 20, height: 20, vx: 0, vy: 0,
velocityDamp: 0.06, collisionDamp: 0.3
};
const collides = (a, b) =>
a.x + a.width >= b.x && a.x <= b.x + b.width &&
a.y + a.height >= b.y && a.y <= b.y + b.height
;
(function render() {
player.vx = (mouse.x - player.x) * player.velocityDamp;
player.vy = (mouse.y - player.y) * player.velocityDamp;
player.x += player.vx;
player.y += player.vy;
while (collides(player, enemy)) {
player.y -= Math.sign(player.vy) * player.collisionDamp;
}
while (collides(player, enemy)) {
player.x -= Math.sign(player.vx) * player.collisionDamp;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "blue";
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
ctx.fillStyle = "yellow";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(render);
})();
onmousemove = e => {
mouse.x = e.clientX;
mouse.y = e.clientY;
};
body {margin: 0;}
canvas {background: #000;}
This works fine when the collision is on the y-axis, but collisions on the x-axis cause the player to "pop" out of the obstacle. Ordering the adjustments so that the least offending velocity adjustment is handled first should fix the problem. We do this by "undoing" the last move on one axis, checking if this single-axis move resolved the collision, and adjusting accordingly.
Putting it all together, here's a proof-of-concept:
const canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 180;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
const mouse = {x: 0, y: 0};
const enemy = {x: 130, y: 70, width: 40, height: 40};
const player = {
x: 0, y: 0, width: 20, height: 20, vx: 0, vy: 0,
velocityDamp: 0.06, collisionDamp: 0.3
};
const collides = (a, b) =>
a.x + a.width >= b.x && a.x <= b.x + b.width &&
a.y + a.height >= b.y && a.y <= b.y + b.height
;
const resolveOnAxis = (player, enemy, axis) => {
while (collides(player, enemy)) {
player[axis] -= Math.sign(player["v"+axis]) * player.collisionDamp;
}
};
const resolveCollision = (player, enemy) => {
player.x -= player.vx;
if (collides(player, enemy)) {
player.x += player.vx;
resolveOnAxis(player, enemy, "y");
resolveOnAxis(player, enemy, "x");
}
else {
player.x += player.vx;
resolveOnAxis(player, enemy, "x");
resolveOnAxis(player, enemy, "y");
}
};
(function render() {
player.vx = (mouse.x - player.x) * player.velocityDamp;
player.vy = (mouse.y - player.y) * player.velocityDamp;
player.x += player.vx;
player.y += player.vy;
if (collides(player, enemy)) {
resolveCollision(player, enemy);
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "blue";
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
ctx.fillStyle = "yellow";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(render);
})();
onmousemove = e => {
mouse.x = e.clientX;
mouse.y = e.clientY;
};
body {margin: 0;}
canvas {background: #000;}
This isn't perfect collision resolution by any means, but it introduces a few fundamental concepts and should be sufficient for simple games.
Note that I'm only handling one enemy; it's left to the reader to create an array of enemies and loop over them to detect and resolve collisions. Problems can arise if multiple enemies are close together; resolving one collision could push the player into another collision. It gets worse if the obstacles are also moving. If you're making a platformer, a collision grid might be worth looking into to circumvent some of these issues.
If dealing with collision becomes increasingly complicated and overwhelming, there's no shame in using a library like matter.js.
Be careful when using while to resolve these collisions as an infinite loop can easily occur. Consider adding a tries counter to these loops and bail if they exceed more than 20 or 30 iterations (this is a bit unsatisfactory and reveals that this solution is not industrial-strength; this prevents infinite loops but may result in incorrect behavior).
Capping the player's maximum velocity is another important preventative measure: it can avoid situations where the velocity becomes so high the player clips right through obstacles. Explore other ad-hoc solutions to problems as they arise.
Beyond collision detection, I have a few other suggestions:
Use objects to encapsulate all properties associated with a game entity. This makes the code much easier to manage than loose variables like playerwidth, playerheight, playerspeed, etc.
Avoid pointless and noisy comments that reiterate what the code clearly does.
Instead of adding comments to delimit logical parts of a function, create helper functions with the appropriate names. My POC above is not great in this regard--as the game expands, objects, functions and overall design become increasingly important; inlining everything in the update loop makes for a painful coding experience as soon as you want to add features or run into bugs.
Put Enemy's constructor function outside of the game loop. Create enemies one time in an initialization function and scope constructors appropriately.
Use camelCased variables instead of everythinginlowercase.
I'm currently working on a small game, and I'm trying to implement a "game over" function when I hit the obstacle. But every time I add all of the code to implement that feature it destroys everything. I would gladly appreciate if someone could help me. I'm not sure what the problem is.
Here is the entire code (only the js part):
var myGamePiece;
var myObstacle;
function startGame() {
myGamePiece = new component(30, 30, "red", 225, 225);
myObstacle = new component(40, 40, "green", 300, 120);
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 1000;
this.canvas.height = 890;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
e.preventDefault();
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
stop : function() {
clearInterval(this.interval);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speed = 0;
this.angle = 0;
this.moveAngle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
this.newPos = function() {
this.angle += this.moveAngle * Math.PI / 180;
this.x += this.speed * Math.sin(this.angle);
this.y -= this.speed * Math.cos(this.angle);
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.moveAngle = 0;
myGamePiece.speed = 0;
myObstacle.update();
if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.moveAngle = -2; }
if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.moveAngle = 2; }
if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.speed= 2; }
if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.speed= -2; }
myGamePiece.newPos();
myGamePiece.update();
}
startGame();
Try fixing this:
You have missing semicolons on line 14 and 17
Let's see...
What you're asking for is called 2D Collision detection. If you're going to use squares, it's rather simple. Basically, compare the two squares with the following:
if (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y) {
// collision detected!
}
Taken from: https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
This code only works with squares without any rotations. For rotation, you would have then have to break out the trigonometry functions of sin/cos/tan based on the angle of rotation.
There are multiple solutions to 2D collision. One method, based on having personally used this for geofencing, is to take every point of Object 1 and compare it against every side of Object 2. If there are an odd number of sides in one direction of a point (for example, to the right) then that makes it's inside the object. You would iterate this for every point and return true if any return odd. You should then repeat process inverse process with Object 2 points.
This is called a Point-in-Polygon approach:
https://en.wikipedia.org/wiki/Point_in_polygon
This works with polygon shapes, but once you use curves, it gets harder. But, generally, gaming uses "hitboxes" because of the simplistic nature.
Edit: To note, this Point-in-Polygon works if the hitboxes are the same size, but if you can overlap two rectangles against each other, then you would have to compare the intersection points of each side of Object1 with sides in Object2.
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>
i am working on a simple game but i am stuck i have created 2 squares one that you can move and the other is supposed to be impassable but i cant find the code to make it a solid object. i need this as the second square will be a shelf on which the 1st square (the player) will jump on. this is just the start that i came across this problem and this game is no where near finished as i can not figure out how to do this many thanks.
<!DOCTYPE HTML>
<head>
<title>Something fancy</title>
</head>
<body>
<h3>Arrow keys to move, and space to jump</h3>
<canvas id="canvas"></canvas>
<style>
canvas{border:1px solid black;}
</style>
<script>
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 800,
height = 500,
shelf = {
x : width/20,
y : height - 50,
width : 60,
height : 50
};
player = {
x : width/2,
y : height - 5,
width : 50,
height : 50,
speed: 5,
velX: 0,
velY: 0,
jumping: false
},
keys = [],
friction = 0.8,
gravity = 0.8;
canvas.width = width;
canvas.height = height;
function update(){
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if(!player.jumping){
player.jumping = true;
player.velY = -player.speed*2;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width-player.width) {
player.x = width-player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if(player.y >= height-player.height){
player.y = height - player.height;
player.jumping = false;
}
ctx.clearRect(0,0,width,height);
ctx.fillStyle = " #BA004B";
ctx.fillRect(player.x, player.y, player.width, player.height);
if(createjs.Bitmap.prototype.getBoundingRect == null){
createjs.Bitmap.prototype.getBoundingRect = function(){
return new createjs.Rectangle(
this.x - this.image.width/2,
this.y - this.image.height/2,
this.image.width,
this.image.height);
}
}
if(createjs.Rectangle.prototype.intersects == null){
createjs.Rectangle.prototype.intersects = function(rect){
return (this.x <= rect.x + rect.width &&
rect.x <= this.x + this.width &&
this.y <= rect.y + rect.height &&
rect.y <= this.y + this.height);
}
}
// draw a small red box, which will eventually become our block.
ctx.fillStyle = "red";
ctx.fillRect(shelf.x, shelf.y, shelf.width, shelf.height);
requestAnimationFrame(update);
}
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
window.addEventListener("load",function(){
update();
});
</script>
</body>
The code you are talking about implementing is Collision Detection code. There are different ways to implement collisions, and the "right" implementation will depend on your game's needs.
Here is a good resource that will get you over your current hurdle, and will let you continue forward. Just know that you'll want to build out some kind of collision detecting and resolving functions that will run over all of your "collidable" objects as you introduce more.
http://www.gamefromscratch.com/post/2012/11/26/GameDev-math-recipes-Collision-detection-using-an-axis-aligned-bounding-box.aspx
To completely oversimplify basic collision detection:
Give your entities a shape and position
On each update/render loop:
a. check if any of your entity shapes overlap
b. Adjust the entities back to their previous position if they should not be overlapping.