I'm trying to write a simple 2D platform game and I can't get my player object to double jump - or rather, I can't get him NOT to. When the up arrow or spacebar is pressed once, double jump is triggered no matter what. I am a JS newbie so I assume this has something to do with my use of logical operators, but I could be wrong. Here is the code:
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 200,
player = {
x : width/2,
y : height - 5,
width : 5,
height : 5,
speed : 3,
velX : 0,
velY : 0,
jumping : false,
jumping_twice : false
};
keys = [],
friction = 0.8,
gravity = 0.3;
canvas.width = width;
canvas.height = height;
function update(){
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
console.log("Player is jumping");
}
else if (!player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
}
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;
player.jumping_twice = false;
}
ctx.clearRect(0,0,width,height);
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
window.addEventListener("load", function(){
update();
})
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
#rhino is totally right about the explanation. I have another solution though. After the jump has been processed, reset the information about the jump key being pressed:
keys[32] = keys[38] = false;
requestAnimationFrame(update);
This happens because update() runs multiple times while the jump key is held down; both conditions are met, one after the other, before you release the key. You could do the check and make the character jump in the keydown handler to work around that, but it is a better idea to keep the changes of your character in the main loop (update() in your case). To do so, you need an extra variable which determines whether the player can actually jump, based on the changes of key state - when the key gets released, the player can jump again or perform a double jump. You could give player a new property called, for example, can_jump and initially set it to true. Then you can do as follows:
if (keys[38] || keys[32]) {
// up arrow or space
if (player.can_jump) {
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
player.can_jump = false; // the player can't jump anymore until the key is released
console.log("Player is jumping");
}
else if (!player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
}
And in the keyup handler:
if (e.keyCode == 32 || e.keyCode == 38) player.can_jump = true;
Working demo: http://jsfiddle.net/5JF69/
Also, be aware that the speed of your game depends on how fast the browser performs a redraw, as you are updating your game logic using requestAnimationFrame().
EDIT: In case the state of the spacebar and up keys doesn't need to remain "down" at all times the keys are actually held down (which doesn't in your current code), go for #lordvlad's solution. It's definitely better if you don't perform any other checks on those keys.
Hah I'm actually the author of the tutorial code you're using.
All the answers are good answers, this is how I would personally do it.
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
console.log("Player is jumping");
}
else if(player.jumping && !player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
keys[38] = keys[32] = false;
}
I would just set the keys to false if they are true in the check itself.
#lordvlad makes a good point, there should be an update cycle separate from the rendering, however for the purpose of the tutorial it was really just to get the user up and running to get something on the screen. At some point I'll make a part 3 to break the logic out a bit more. Anyway hope this helps.
Live Demo
Related
I want the movement to be smooth upon pressing a key, the object does an initial movement and then starts moving completely when holding down the button.
//movement speed
var xSpeed = 0.5;
var zSpeed = 0.5;
document.addEventListener("keydown", onDocumentKeyDown, false);
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
car.position.z -= zSpeed;
} else if (keyCode == 83) { //S KEY
car.position.z += zSpeed;
} else if (keyCode == 65) { //A KEY
car.position.x -= xSpeed;
} else if (keyCode == 68) { //D KEY
car.position.x += xSpeed;
} else if (keyCode == 32) {
car.position.set(0, 0, 0);
}
};
Trying to get a GLTF imported model to be controlled on a plane with keyboard controls smoothly.
Tried wrapping the program in a loop and made the state of the keyboard available inside the scope of that loop but couldn't get it working
You could try an approach where the velocity is modified upon keyup/keydown, and the loop just modifies the car's position based on the velocity.
// initial movement speed
var xSpeed = 0;
var zSpeed = 0;
document.addEventListener("keydown", onDocumentKeyDown, false);
document.addEventListener("keydown", onDocumentKeyUp, false);
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
zSpeed = -0.5;
} ... // do so for the rest of the keys
};
function onDocumentKeyUp(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
zSpeed = 0;
} ... // do so for the rest of the keys
};
function loop() {
car.position.z += zSpeed;
car.position.x += xSpeed;
window.requestAnimationFrame(loop);
}
If you are interested in more eased movement, e.g. the car doesn't just start moving at constant velocity but ramps up and slows down, consider having the keyup/keydown modify an acceleration factor, and the loop modifies the velocity.
This is a good in-depth article by Daniel Shiffman about attempting to represent the real world with code:
https://natureofcode.com/book/chapter-1-vectors/
I am making an HTML5 web game and am in the process of making the player movement. I am not using any game engine, just pure HTML, CSS, and JavaScript. My problem is that whenever I load my game, it starts out fine where I can move around at normal speeds but if I move back and forth a few times, the player starts speeding up and if I keep doing this, it speeds up to unbearable speeds. I have no idea what is happening.
How my code works is when the key d is pressed then in the keysPressed object D is set to true instead of false,
let keysPressed = {
'd': false,
'a': false,
'w': false,
's': false, }
Then, it executes a function that moves the player.
function move() {
if (keysPressed['d'] == true) { // check if its right
let player = document.querySelector('.player');
var id = setInterval(frame, 20);
function frame() {
if (keysPressed['d'] == false) {
clearInterval(id);
} else {
player.style.left = player.offsetLeft + 2 + 'px';
}
}
}
if (keysPressed['a'] == true) { // check if its left
let player = document.querySelector('.player');
var id = setInterval(frame, 20);
function frame() {
if (keysPressed['a'] == false) {
clearInterval(id);
} else {
console.log(player.offsetLeft)
player.style.left = player.offsetLeft - 2 + 'px';
}
}
}
}
I know that it isn't the cleanest code but I just wanna fix this bug first before tackling this.
Thanks
You are calling setInterval many times over which is compounding and causing the symptom you're describing. I think you only need to call setInterval once, and then just change the left/right variables depending on the keypress.. something like
let intervalID, player = document.querySelector('.player'),
dir, offset, isMoving = false;
function changeDirection(keysPressed) {
if (!isMoving) move();
if (keysPressed['d']) {
dir = 'left';
offset = 'offsetLeft';
} else if (keysPressed['a']) {
dir = 'right';
offset = 'offsetRight';
}
}
function move() { // called just once
if (isMoving) return;
isMoving = true;
intervalID = setInterval(function() {
player.style[dir] = (+player[offset] + 2) + 'px';
}, 20);
}
this is my first post! With that in mind, if I need to add anything more than what is below, please let me know. Thank you!
I am currently working to make a platformer game in Javascript where a player can move using arrow keys. Currently, my left and right movements, as well as my player gravity, works. However, when I jump, I am unable to provide smooth jumping movements. originally, I tried simply moving my player's y value higher.
if (up) {
this.y -= 100;
}
However, this makes the player "teleport" upwards, rather than look like an actual jump. To fix this, I reused my gravity code to overcome the gravitational force until a certain limit, making the player look like they are smoothly jumping until they reach a certain height. Below is my code.
if (up) { // This if statement is apart of another function, did not include
this.can_jump = false;
this.jumping = true; this.jump();
}
jump() { // Overcome the gravitational force, but jump force slowly lowers
this.y -= (this.gravity * this.velocity) * 3;
this.gravity -= 0.1;
this.velocity -= 0.1;
this.check();
this.check_jump(this.jumping);
}
check_jump(jumping) {
if (jumping) {
if (this.x < 500) { // While player is less than 500, keep jumping
this.jumping = false;
this.gravity = 2;
this.velocity = 2;
this.can_jump = true;
}
}
}
Additionally, here is the code regarding player collisions and gravity.
gravityEffect() {
this.y += (this.gravity * this.velocity);
this.check();
}
check() {
// Too far up
if (this.y <= 70) { this.y = 70; }
// Too far down
if (this.y >= 600) { this.y = 600; }
// Too far left, teleports to other side
if (this.x < 0) { this.x = 1200; }
// Too far right, teleports to other side
if (this.x > 1200) { this.x = 0; }
}
However, when testing this, my player not only keeps jumping upwards, but also does not do so smoothly (it looks like it is glitching). Here is a link to an mp4 file download (screen recording) showcasing the glitch: https://www.mediafire.com/file/jtqh3lca72vj8nz/%25F0%259D%2590%258C%25F0%259D%2590%25B2_%25F0%259D%2590%2586%25F0%259D%2590%25AB%25F0%259D%2590%259A%25F0%259D%2590%25AF%25F0%259D%2590%25A2%25F0%259D%2590%25AD%25F0%259D%2590%25B2_-_Google_Chrome_2021-04-28_19-59-08.mp4/file
Also, here is a copy of my current code (zipped), if running the program helps: https://www.mediafire.com/file/r5ewoxtb4n57htz/game.zip/file
Please let me know what is wrong. Also, if there is a different or more efficient method of simulating player jumping, please make me aware of it. Thank you for your time.
While trying to keep the code mostly the same I made some changes.
First and formost I changed how you had the controller written. Unless your intention was for the up/down/left/right arguments to stay true then you need a method for them to kick back to false. This controller class will do that.
// Apply classes to empty variables
console.log("Creating player...");
player = new Player();
console.log("Creating world...");
world = new World();
console.log("Creating Controller...")
controller = new Controller();
// Draw canvas with set size
console.log("Creating game screen...");
createCanvas(1000, 750);
}
class Controller {
constructor() {
this.up = false;
this.down = false;
this.right = false;
this.left = false;
let keyEvent = (e) => {
if (e.code === 'ArrowUp') { this.up = e.type === 'keydown' }
if (e.code === 'ArrowRight') { this.right = e.type === 'keydown' }
if (e.code === 'ArrowDown') { this.down = e.type === 'keydown' }
if (e.code === 'ArrowLeft') { this.left = e.type === 'keydown' }
}
window.addEventListener('keydown', keyEvent)
window.addEventListener('keyup', keyEvent)
}
}
Since we changed that we'll have to change the Player Class very slightly.
I've set the X and Y velocity to 0 and we'll increment those once a button is pressed. The additional update function will update your X and Y based on that.
Player Class
class Player {
// Setup player attributes
constructor() {
this.x = 100;
this.y = 395;
this.width = 50;
this.height = 50;
this.jumping = false;
this.color = "#ffdb15";
this.gravity = 2;
this.velocityY = 0;
this.velocityX = 0; //changed this from speed
this.points = 0;
}
move() {
// Reverse gravity to upwards, change player's color
if (controller.up && !this.jumping) { this.jumping = true; this.jump(); this.color = this.getRandomColor(true); }
// Reverse gravity to downwards, change player's color
if (controller.down) { this.color = this.getRandomColor(false); }
// Go left
if (controller.left) { this.velocityX -= 1 }
// Go right
if (controller.right) { this.velocityX += 1 }
}
jump() {
this.velocityY -= 35;
}
check() {
// Too far up
if (this.y <= 70) { this.y = 70; }
// Too far down
if (this.y >= 600) { this.y = 600; this.jumping = false } //once collision player can jump again
// Too far left, teleports to other side
if (this.x < 0) { this.x = 1200; }
// Too far right, teleports to other side
if (this.x > 1200) { this.x = 0; }
}
// Get a random player color
getRandomColor(isMoving) {
if ((this.y === 70 || this.y === 600) && isMoving) {
// Explanation: Each color has RGB values from 0 to 255, or 256 total options
// Since colors start from "000000" and go until "FFFFFF", there are ((256^3) - 1) possibilities
// (256^3) - 1 = 16777215
// Use this number, and a random number from Math.Random(), to get a random color
// Idea from: https://css-tricks.com/snippets/javascript/random-hex-color/
this.color = Math.floor(Math.random() * 16777215).toString(16);
return "#" + this.color;
} else { return this.color; }
}
show() {
// Show player
fill(this.color);
strokeWeight(0);
rect(this.x, this.y, this.width, this.height);
}
update() {
this.velocityY += this.gravity;
this.x += this.velocityX;
this.y += this.velocityY;
this.velocityY *= 0.9;
this.velocityX *= 0.9; //provides a sliding slow down once button is released.
this.move();
this.check();
}
}
The draw function is the same but replace gravity with update
function draw() {
world.generate();
player.update();
player.show();
}
This should get you where you want to go with it.
Do you have a variable for y speed? i've found the best way to create a fairly normal looking jump would be to set the y speed to a set number, EG: -4. My personal favorite method for realistic player jumping and gravity would be as follows, but can be easily modified for your uses:
//Initial y position
var y=height/2;
//This is how far the player moves each frame
var ys=0;
//This is how intense the gravity is.
var yss=0.1;
function draw(){
y+=ys;
//yss can be replaced with some arbitrary number if you don't plan on changing it(EG: for collisions)
ys+=yss;
//Then to jump, something like this
if(mouseIsPressed){
ys=-4;
}
//Heck, if you wanted to flip gravity you could do this
//yss*=-1;
//and bouncing would look like this
//ys*=-0.9;
}
Let me know if there is anything I can clarify or help with!
I made a game with HTML canvas in which the user can control the movement of a character.
Links: live website/GitHub repo
My goal is to disable arrow keys while the modal that displays when the game is over is open. I tried this by adding the following to the showModal() function, which is the same as the version of the event listener that is added at the end of the JavaScript (then I would re-add this event listener when the game is reset). It doesn't do anything, though.
document.removeEventListener('keydown', function(e) {
let allowedKeys = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};
player.handleInput(allowedKeys[e.keyCode]);
});
Full JS code from this file (there are two other JS files but I don't think they're relevant):
"use strict"; // Enables strict mode to catch common bloopers
// TODO: Disable player movement when modal opened? Also, set 3 tries before modal opened (change to game over). Restart button.
// TODO: Start game on enter when modal opened
const playAgainButton = document.querySelector('.play-again');
const restartButton = document.querySelector('.restart');
// Calls playAgain() function when user clicks reset icon in sidebar
restartButton.addEventListener('click', playAgain);
// Starts lives at 3
let lives = 3;
let sidebarLives = document.querySelector('.lives-left');
sidebarLives.innerHTML = lives;
// Sets an initial player score of 0.
let score = 0;
// Sets score shown in sidebar
// document.getElementsByClassName('score')[0].innerHTML = score;
let sidebarScore = document.querySelector('.score');
sidebarScore.innerHTML = score;
let modalScore = document.querySelector('.modal-score');
modalScore.innerHTML = score;
// Called when user clicks restart button in sidebar or play again button in modal. Sets modal to display: none, resets lives and score
function playAgain() {
// Hides modal if present (if opened by game ending)
modal.classList.remove('modal-visible');
lives = 3;
sidebarLives.innerHTML = lives;
score = 0;
sidebarScore.innerHTML = score;
}
// Calls playAgain() function (hides modal and restarts game) with user clicks "play again" button in modal
// TODO: remove? just one event listener for both buttons?
// modalPlayAgainButton.addEventListener('click', playAgain);
// Note: In a constructor function "this" does not have a value. It is a substitute for the new object. The value of this will become the new object when a new object is created
// Note commas not used to separate methods and properties in a class
class Player {
// Constructor function, a special function just for initializing new objects, will automatically run when a new object is constructed (with keyword "new") from this class. Contains data needed to create it
constructor(x, y, speed) {
this.sprite = 'images/char-boy.png';
this.x = x;
this.y = y;
this.speed = speed;
}
// Methods that all objects created from class will inherit. Would exist on prototype in pre-class way of writing it, but effect is the same (the following methods still exist on Player prototype [for example would be Player.prototype.update = function(dt)...])
// When player reaches water, moves player back to starting position, and increase score by 1
update(dt) {
if (this.y === 25) {
this.x = 200;
this.y = 400;
score++;
sidebarScore.innerHTML = score;
}
}
// Draws player on screen
render() {
ctx.drawImage(Resources.get(this.sprite), this.x, this.y)
}
// Connects keyboard input to player movement. If statements prevent player movement off screen
handleInput(allowedKeys) {
if (allowedKeys === 'down' && this.y < 425) {
this.y += 25;
}
if (allowedKeys === 'up') {
this.y -= 25;
}
if (allowedKeys === 'left' && this.x > 0) {
this.x -= 25;
}
if (allowedKeys === 'right' && this.x < 400) {
this.x += 25;
}
}
}
class Enemy {
// Sets enemy's initial location
constructor(x, y, speed) {
this.x = x;
this.y = y;
// Sets speed of enemy
this.speed = speed;
// The image/sprite for our enemies
this.sprite = 'images/enemy-bug.png';
}
update(dt) {
// Multiplies enemy's movement by time delta to ensure game runs at same speed for all computers
this.x += this.speed * dt;
// Once enemy finished moving across screen, moves it back so it can cross screen again and randomizes its speed
if (this.x > 500) {
this.x = -75;
// Math.random() function returns random number between 0 (inclusive) and 1 (exclusive). Math.floor() returns the largest integer less than or equal to a given number
this.speed = 70 + Math.floor(Math.random() * 450);
}
// When collission occurs, subtracts a life, updates lives displayed in sidebar and updates score that will be displayed in modal if no lives remaining
if ((player.x < (this.x + 70)) && ((player.x + 17) > this.x) && (player.y < (this.y + 45)) && ((30 + player.y) > this.y)) {
player.x = 200;
player.y = 400;
lives--;
sidebarLives.innerHTML = lives;
modalScore.innerHTML = score;
if (lives === 0) {
// Calls function that adds class that sets modal to display: block
showModal();
}
}
}
// Draws enemy on the screen
render() {
ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
}
};
// ENEMY/PLAYER OBJECT INSTANTIATION
let enemyPosition = [60, 140, 220];
let allEnemies = [];
let player = new Player(200, 400, 50);
enemyPosition.forEach(function(posY) {
let enemy = new Enemy(0, posY, 70 + Math.floor(Math.random() * 450));
allEnemies.push(enemy);
});
// Modal
const modal = document.getElementById('myModal');
const closeIcon = document.querySelector('.close');
// When called, adds class that sets modal to display: block when player reaches water
function showModal() {
modal.classList.add('modal-visible');
// Goal: Disable arrow keys while the modal is open (doesn't work). If I can get this to work, then I'd re-add the arrow key event listener when the game is reset
document.removeEventListener('keydown', function(e) {
let allowedKeys = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};
// Not sure why "player" needs to be lowercase, given the class name is uppercase
player.handleInput(allowedKeys[e.keyCode]);
});
// Calls playAgain() function when user clicks play again button in modal
playAgainButton.addEventListener('click', playAgain);
// If esc is pressed, closes modal and restarts game (note: keydown used instead of keypress because keypress only works for keys that produce a character value)
document.addEventListener('keydown', function(e) {
let keyCode = e.keyCode;
if (keyCode === 27) {
modal.classList.remove('modal-visible');
playAgain()
}
});
// If enter is pressed, closes modal and restarts game
document.addEventListener('keydown', function(e) {
let keyCode = e.keyCode;
if (keyCode === 13) {
modal.classList.remove('modal-visible');
playAgain()
}
});
// If user clicks modal's close icon, closes modal and restarts game
closeIcon.addEventListener('click', function() {
modal.classList.remove('modal-visible');
playAgain();
});
}
// Listens for keydown event (fired when a key is pressed down [regardless of whether it produces a character, unlike keypress]) and sends the keys to Player.handleInput() method
document.addEventListener('keydown', function(e) {
let allowedKeys = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};
// Not sure why "player" needs to be lowercase, given the class name is uppercase
player.handleInput(allowedKeys[e.keyCode]);
});
Instead of removing and/or filtering out the specific key events, when the game state changes (e.g.: when the character dies), for starters, as a simpler solution, use a flag (a boolean value) to indicate, whether your character should be moving or not.
let isDead = false;
When your character dies, set the flag to false:
if (lives === 0) {
isDead = true;
// Calls function that adds class that sets modal to display: block
showModal();
}
And in your input handling function, use the flag to allow/disallow the character movement:
// Connects keyboard input to player movement. If statements prevent player movement off screen
handleInput(allowedKeys) {
if (isDead) {
return;
}
if (allowedKeys === 'down' && this.y < 425) {
this.y += 25;
}
if (allowedKeys === 'up') {
this.y -= 25;
}
if (allowedKeys === 'left' && this.x > 0) {
this.x -= 25;
}
if (allowedKeys === 'right' && this.x < 400) {
this.x += 25;
}
}
Or just outright avoid calling the handleInput(...) function in the event handler:
document.addEventListener('keydown', function(e) {
let allowedKeys = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};
// notice that we only want to call the handleInput function
// when the player is alive, hence !isDead
if (!isDead) {
player.handleInput(allowedKeys[e.keyCode]);
}
});
And when you restart the game, set the flag to its default value:
function playAgain() {
modal.classList.remove('modal-visible');
isDead = false;
lives = 3;
sidebarLives.innerHTML = lives;
score = 0;
sidebarScore.innerHTML = score;
}
Note
Since you're developing a game, even when it's just a simple game, I strongly recommend you to manage your game behavior using game states.
you can try a few different approaches to a problem if one does not work.
Say you have a Boolean variable that is true when the modal is open and false when it is closed. this would work
keyCode = modalIsOpen || e.keyCode
if the modal is open the keycode would be set as true rather than a number.
this way is unorthodox but it works.
Please help i tried a couple of things but whenever i move the small object to the larger one it gets stuck after collision detection. Here is my code its easy enough to understand.
i have also tried to detect collision detection on individual sides of the other object.
// Setup requestAnimationFrame
requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
// Create the canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Game objects
var player = {
width:50,
height:50,
x:50,
y:50,
speed:100,
color:'#3C1BE0'
};
var wall={
width:50,
height:150,
x:300,
y:100,
color:'#E01B5D'
};
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
},false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
},false);
//check collisions
var collisions=function(){
}
// Update game objects
var update = function (modifier) {
//test for collisions
//player collision with wall(red cube)
if(player.x+player.width>wall.x &&
player.x<wall.x+wall.width &&
player.y<wall.y+wall.height &&
player.y+player.height>wall.y
)
{
player.speed=0;
}
//player collission with canvas
if(player.x < 0 )
{
player.x=0;
}
else if(player.x+player.width> canvas.width)
{
player.x=canvas.width-player.width;
}
else if(player.y <0 )
{
player.y=0;
}
else if(player.y+player.width>=canvas.height)
{
player.y=canvas.height-player.height;
}
if (38 in keysDown) { // Player holding up
player.y -= player.speed*modifier;
}
if (40 in keysDown) { // Player holding down
player.y += player.speed*modifier;
}
if (37 in keysDown) { // Player holding left
player.x -= player.speed*modifier;
}
if (39 in keysDown) { // Player holding right
player.x += player.speed*modifier;
}
};
// Draw everything
var render = function () {
ctx.clearRect(0,0,600,400);
ctx.fillStyle=wall.color;
ctx.fillRect(wall.x,wall.y,wall.width,wall.height);
ctx.fillStyle=player.color;
ctx.fillRect(player.x,player.y,player.width,player.height);
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
requestAnimationFrame(main);
};
// Let's play this game!
var then = Date.now();
main();
The issue may be that you are never setting the speed to something above 0 after you have set it to zero on the collision.
if(player.x+player.width>wall.x &&
player.x<wall.x+wall.width &&
player.y<wall.y+wall.height &&
player.y+player.height>wall.y) {
player.speed=0; // this never gets unset
}
You would need to probably figure out where the player wants to go based on the keystroke and calculate a delta. If the delta is allowable (not colliding), then you update the player's position, otherwise you don't apply the delta.
I have found a solution to my problem.I have added the direction of the keyboard to the arguments and created a stand alone collision detection function.if you think i make any improvements to my collision code i would appreciate any useful input.
var collisions=function(sprite1,sprite2){
return sprite1.x < sprite2.x + sprite2.width &&
sprite1.x + sprite1.width > sprite2.x &&
sprite1.y < sprite2.y + sprite2.height &&
sprite1.y + sprite1.height > sprite2.y;
}
if(collisions(player,wall)){
if(player.y+player.height>wall.y &&
40 in keysDown
)
{
player.y=wall.y-player.height;
}
if(player.y<wall.y+wall.height &&
38 in keysDown
)
{
player.y=wall.y+wall.height;
}
if(player.x+player.width>wall.x &&
39 in keysDown
)
{
player.x=wall.x-player.width;
}
if(player.x<wall.x+wall.width &&
37 in keysDown
)
{
player.x=wall.x+wall.width;
}
}