HTML 5 canvas game objects getting stuck after collision - javascript

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;
}
}

Related

Why is my player moving faster and faster when I use the controls. HTML web game

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);
}

Player Jumping Glitch

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!

Control video playback when mouse in defined zone

I'm trying to control video playback depending on where my mouse is on screen.
I've split the width of the window into 3 areas - left, centre and right. This works fine so far.
When the mouse is in the 'left' I want to specify to jump to a certain time, same for centre and right.
The issue I'm having is that every time the mouse moves the video playback restarts, I want it to change only when it changes from 'left' to 'right' or 'centre'. I've made a current_pos and new_pos variable but can't figure out how to update them properly.
Many thanks!
PS have left out the video code for now, just trying to get the position working.
var viewport_width = document.documentElement.clientWidth;
var viewport_height = document.documentElement.clientHeight;
var current_pos;
var new_pos;
function getMousePos(e) {
return {x:e.clientX,y:e.clientY};
}
document.onmousemove=function(e) {
var mousecoords = getMousePos(e);
//left
if (mousecoords.x < viewport_width/3){
current_pos = 'left';
//centre
}else if (mousecoords.x > viewport_width/3 && mousecoords.x < viewport_width*.66){
current_pos = 'centre';
//right
}else {
current_pos = 'right';
}
console.log(current_pos);
};
You need to check whether current_pos has been changed every time you attempt to change it.
var viewport_width = document.documentElement.clientWidth;
var viewport_height = document.documentElement.clientHeight;
var current_pos;
function getMousePos(e) {
return {
x: e.clientX,
y: e.clientY
};
}
document.onmousemove = function(e) {
var mousecoords = getMousePos(e);
//left
if (mousecoords.x < viewport_width / 3) {
if(current_pos != 'left') {
current_pos = 'left';
// Play your video from the desired point
}
//centre
} else if (mousecoords.x > viewport_width / 3 && mousecoords.x < viewport_width * .66) {
if(current_pos != 'centre') {
current_pos = 'centre';
// Play your video from the desired point
}
//right
} else {
if(current_pos != 'right') {
current_pos = 'right';
// Play your video from the desired point
}
}
console.log(current_pos);
};

Turn player On/Off using Tone.js

I am making a square shape where I can select the square to turn my music on and then select it again to turn my music off. I have it to where the music turns on, but how would I turn my music off?
function mousePressed() {
if(mouseX >= 700 && mouseX <= 1000 && mouseY >= 100 && mouseY <= 400) {
var player = new Tone.Player("media/test.mp3").toMaster();
player.autostart = true;
noLoop();
}
}
You need to use the member .state of the player object. depending on it's state you perform what you need.
var player = new Tone.Player("media/test.mp3").toMaster();
player.autostart = true;
noLoop();
function mousePressed(player){
if(player.state == "started"){
player.stop();
} else if (player.state == "stopped") {
player.start();
}
}

Trouble with logical operators in JS

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

Categories