I'm making a little video game, where the background (platform) moves down with my character (square) jumps. On line 113 I have tried different strategies to implement this thought, and that is the closest it has gotten to work. The issue is that even when the square velocity is 0, the platform velocity isn't. I have been stuck for a week now, and feels like javascript is the problem (even though I know it isn't).
canvasmain.width = window.innerWidth;
canvasmain.height = window.innerHeight;
//CHARACTER:
const square = {
height: 75,
jumping: true,
width: 75,
x: canvasmain.width / 2,
xVelocity: 0,
y: canvasmain.height / 2,
yVelocity: 0
};
//floor
const platform = {
height: 30,
width: 100,
x: square.x,
xVelocity: 0,
y: square.y + square.height,
yVelocity:0
}
//MOVEMENT:
const controller = {
left: false,
right: false,
up: false,
keyListener: function (event) {
let key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 37: // left arrow
controller.left = key_state;
break;
case 38: // up arrow
controller.up = key_state;
break;
case 39: // right arrow
controller.right = key_state;
break;
}
}
};
const loop = function () {
if (controller.up && square.jumping == false) {
square.yVelocity -= 30;
square.jumping = true;
}
if (controller.left) {
square.xVelocity -= 0.5;
}
if (controller.right) {
square.xVelocity += 0.5;
}
square.yVelocity += 1.5;// gravity
square.x += square.xVelocity;
square.y += square.yVelocity;
square.xVelocity *= 0.9;// friction
square.yVelocity *= 0.9;// friction
// if square is falling below floor line
if (square.y > canvasmain.height - 75) {
square.jumping = false;
square.y = canvasmain.height - 75;
square.yVelocity = 0;
}
// if square is going off the left of the screen
if (square.x < 0) {
square.x = 0;
} else if (square.x > canvasmain.width - 75) {// if square goes past right boundary
square.x = canvasmain.width - 75;
}
// Creates the backdrop for each frame
context.fillStyle = "#394129";
context.fillRect(0, 0, canvasmain.width, canvasmain.height); // x, y, width, height
// Creates and fills the cube for each frame
context.fillStyle = "#8DAA9D"; // hex for cube color
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fill();
// Creates the "ground" for each frame
context.fillStyle = "#202020";
context.beginPath();
context.rect(platform.x, platform.y, platform.width, platform.height)
context.fill();
// call update when the browser is ready to draw again
window.requestAnimationFrame(loop);
//platform
platform.y += platform.yVelocity;
console.log(square.yVelocity)
if (square.yVelocity > 0.1 ) {
platform.yVelocity = 1.5
};
if (square.yVelocity < 0 ) {
platform.yVelocity = -1.5
};
}
window.addEventListener("keydown", controller.keyListener)
window.addEventListener("keyup", controller.keyListener);
window.requestAnimationFrame(loop);
You're not reseting the value of yVelocity.
Got it guys, thx #Teemu, I just needed to set it to 0 if it wasn't the if's. Dang, really took a while. if (square.yVelocity > 0 ) {platform.yVelocity = 1.5} else{ platform.yVelocity = 0}; if (square.yVelocity < 0 ) {platform.yVelocity = -1.5} else { platform.yVelocity = 0} }
edit: frick, it only moves the platform when the cube is going up, not down ;-;
Related
ive been trying to flip the arrows when the cars are in different side of the road. The image shows two multi-lane roads where forward on the left side goes up and i want forward on the right to go down, and the same for right and left. ive tried my method but it doesnt seem to work so i think im doing something stupid. please hep with a method that can work, heres the code
class Controls
{
constructor(type,laneIndex)
{
this.laneIndex = laneIndex;
this.forward =false;
this.left = false ;
this.foward = false ;
this.reverse =false;
switch (type)
{
case "KEYS":
this.#addKeyboardListeners();
break;
case "DUMMY":
this.forward =true;
break;
}
}
#addKeyboardListeners()
{
if (this.laneIndex <= 3)
{
document.onkeydown=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.left =true;
break;
case "ArrowRight":
this.right =true;
break;
case "ArrowUp":
this.forward =true;
break;
case "ArrowDown":
this.reverse =true;
break;
}
}
document.onkeyup=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.left = false;
break;
case "ArrowRight":
this.right = false;
break;
case "ArrowUp":
this.forward = false;
break;
case "ArrowDown":
this.reverse =false;
break;
}
}
}
if (this.laneIndex >= 4)
{
document.onkeydown=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.right =true;
break;
case "ArrowRight":
this.left =true;
break;
case "ArrowUp":
this.reverse =true;
break;
case "ArrowDown":
this.forward =true;
break;
}
}
document.onkeyup=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.right =false;
break;
case "ArrowRight":
this.left =false;
break;
case "ArrowUp":
this.reverse =false;
break;
case "ArrowDown":
this.forward =false;
break;
}
}
}
}
}
Basic keyboard input
This answer shows a method for monitoring the ongoing keyboard state.
Keys of interest are flagged as true when down and false when up.
There is a demo (bottom) to show how this method can be used in an animated app interface.
Some pointers
Keep IO (mouse, keyboards, touch, joysticks etc..) and game logic separate as this help keeps the code simple.
Don't add events via the named event property. Eg document.onkeydown = function. As it can easily be overwritten by you or 3rd party code.
Use addEventListener to ensure the event will stay in place
Example of keyboard input
The example creates an object keys that has a property for each of the keys you want to keep track of. The keyboard event listener will set the state to true when a key is down and false if not.
You can add other keys by adding the KeyboardEvent.code name to keys object. Example I have added Space to listen for the space key (I will use it to switch tracks in next example.
const keys = (() => {
const keys = { // only names of keys you are interested in
ArrowUp: false,
ArrowRight: false,
ArrowDown: false,
ArrowLeft: false,
Space: false,
};
function listener(e) {
keys[e.code] !== undefined && (keys[e.code] = e.type === "keydown");
}
addEventListener("keyup", listener);
addEventListener("keydown", listener);
return keys;
})();
Using the input
Once you have the controlling input setup, your app logic need only monitor the state of the input and react as needed.
The example below uses the keys object to move the active car. W moves the car forward, and D moves it in reverse. The function that moves cars is Car.update
To switch cars press the space key. Switching cars can be found in renderLoop
Note Use WASD for control as arrow keys are not safe in stack overflow snippets
Note you need to focus the snippet for the keyboard events to be seen as stack overflow snippets can not automatically focus.
const keys = (() => {
const keys = { // only names of keys you are interested in
KeyW: false,
KeyS: false,
Space: false,
};
function listener(e) {
keys[e.code] !== undefined && (keys[e.code] = e.type === "keydown");
e.preventDefault(); // to stop stack overflow snippet problems
}
addEventListener("keyup", listener);
addEventListener("keydown", listener);
return keys;
})();
const P2 = (x, y) => ({x, y}); // creates 2D point
const Car = { // common properties for a car
on: false,
col: "#888",
/* Function that inspects keyboard state and moves car */
update() {
if (this.on) { // only if active
let mx = 0, my = 0;
if (keys.KeyW) { /* Check forward */
mx += this.dir.x * 3;
my += this.dir.y * 3;
}
if (keys.KeyS) { /* Check reverse */
mx -= this.dir.x;
my -= this.dir.y;
}
// Keep on canvas
if (this.pos.x + mx > W - 40 || this.pos.x + mx < 40) { mx = 0; }
if (this.pos.y + my > H - 40 || this.pos.y + my < 40) { my = 0; }
this.pos.x += mx;
this.pos.y += my;
}
},
draw() {
ctx.fillStyle = this.col;
const sx = this.size.x, sy = this.size.y;
ctx.setTransform(this.dir.y, this.dir.x, -this.dir.x, this.dir.y, this.pos.x, this.pos.y);
ctx.fillRect(sx * -0.5, sy * -0.5, sx, sy);
ctx.fillStyle = "#9AD";
ctx.fillRect(sx * -0.4, sy * -0.4, sx * 0.1, sy * 0.25);
ctx.fillRect(sx * -0.4, sy * -0.1, sx * 0.8, sy * 0.2);
ctx.fillRect(sx * 0.3, sy * -0.4, sx * 0.1, sy * 0.25);
ctx.strokeStyle = "#EA5";
ctx.lineWidth = 2;
ctx.beginPath();
if (this.on) {
ctx.moveTo(sx * -0.4 , sy * 1.5);
ctx.lineTo(sx * -0.25, sy * 0.5);
ctx.lineTo(sx * -0.1 , sy * 1.5);
ctx.moveTo(sx * 0.4 , sy * 1.5);
ctx.lineTo(sx * 0.25, sy * 0.5);
ctx.lineTo(sx * 0.1 , sy * 1.5);
}
ctx.moveTo(sx * -0.1 , sy * 0.5);
ctx.lineTo(sx * -0.4 , sy * 0.5);
ctx.moveTo(sx * 0.1 , sy * 0.5);
ctx.lineTo(sx * 0.4 , sy * 0.5);
ctx.stroke();
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform incase
// you draw stuff not using setTransform
}
}
const cars = [{
dir: P2(0, 1), // forward direction
size: P2(30, 50),
pos: P2(100, 100),
...Car
}, {
dir: P2(0, -1), // forward direction
size: P2(30, 50),
pos: P2(200, 100),
...Car
},
];
requestAnimationFrame(renderLoop);
const ctx = canvas.getContext("2d"), W = canvas.width, H = canvas.height;
var carOnIdx = 0;
cars[carOnIdx].on = true;
function renderLoop(time) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "#555";
ctx.fillRect(10, 10, W - 20, H - 20);
ctx.fillStyle = "#DDD";
ctx.fillRect(70, 10, 2, H - 20);
ctx.fillRect(130, 10, 2, H - 20);
ctx.fillRect(175, 10, 2, H - 20);
ctx.fillRect(225, 10, 2, H - 20);
// If space key press changed cars
if (keys.Space) {
cars[carOnIdx].on = false;
carOnIdx = (carOnIdx + 1) % cars.length;
cars[carOnIdx].on = true;
// Only want the key down for space to flag it as used
keys.Space = false;
}
for (const car of cars) { car.update(); }
for (const car of cars) { car.draw(); }
requestAnimationFrame(renderLoop);
}
* {
font-family: arial;
}
canvas {
background: #4A6;
}
.info {
position: absolute;
left: 340px;
top: 20px;
font-size: large;
}
ul {
position: absolute;
left: 320px;
top: 30px;
}
<canvas id="canvas" width="300" height="300"></canvas>
<div class="info">Using keyboard input</div>
<ul>
<li>To focus keyboard on snippet, click snippet</li>
<li>Uses WASD rather than arrow keys</li>
<li>Space to switch cars</li>
<li>W to drive forward</li>
<li>D to reverse</li>
<li><b>Note</b> cars can not go outside canvas</li>
</ul>
so I have a 2d platformer in the works, and I'd like to add walls and platforms to it, but when I try to make a platform, it doesn't stop the player in front of it if they just walk forward, and instead it makes it sort of like a step/stairs.
Here's what I have so far:
var ctx, controller, rectangle, loop;
ctx = document.querySelector("canvas").getContext("2d");
// Screen size
ctx.canvas.height = 200;
ctx.canvas.width = 400;
// Position of Player
rectangle = {
height: 25,
jumping: true,
width: 25,
x: 10,
x_velocity: 0,
y: 0,
y_velocity: 0
};
controller = {
left: false,
right: false,
up: false,
keyListener: function(event) {
var key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 37: // Left
controller.left = key_state;
break;
case 39: // Right
controller.right = key_state;
break;
case 38: // Up
controller.up = key_state;
break;
};
}
};
loop = function() {
if (controller.up && rectangle.jumping == false) {
rectangle.y_velocity -= 25;
rectangle.jumping = true;
};
if (controller.left) {
rectangle.x_velocity -= 0.75;
};
if (controller.right) {
rectangle.x_velocity += 0.75;
};
// Gravity
rectangle.y_velocity += 1.5;
rectangle.x += rectangle.x_velocity;
rectangle.y += rectangle.y_velocity;
// Friction
rectangle.x_velocity *= 0.75;
rectangle.y_velocity *= 0.75;
// Floor
if (rectangle.y > 150 - 25) {
rectangle.jumping = false;
rectangle.y = 150 - 25;
rectangle.y_velocity = 0;
};
// Platform
if (rectangle.y > 145 - 25 && rectangle.x > 150 - 25) {
rectangle.jumping = false;
rectangle.y = 145 - 25;
rectangle.y_velocity = 0;
};
// Background
var bg = new Image;
bg.src = "https://i.imgur.com/He3uld9.png";
bg.onload = function() {
ctx.drawImage(bg, 0, 0);
};
// Player
var ply = new Image;
ply.src = "https://i.imgur.com/G4UUkIl.png";
ply.onload = function() {
ctx.drawImage(ply, rectangle.x, rectangle.y);
};
// Floor
var fl = new Image;
fl.src = "https://i.imgur.com/OoKP4Mm.png";
fl.onload = function() {
ctx.drawImage(fl, 0, 150);
};
window.requestAnimationFrame(loop);
};
window.addEventListener("keydown", controller.keyListener);
window.addEventListener("keyup", controller.keyListener);
window.requestAnimationFrame(loop);
<canvas style="border: 1px solid black;"></canvas>
The commented part that says Platform under the JS section is where my code for the platform currently is. As of now, it doesn't have an image or object for you to see it, but if you play the game, it is an invisible platform right above the floor.
What if you try to maintain a blockedRight and a blockedLeft property on the rectangle according to the zone you're in ? For instance, I have implemented a blockedRight boolean in the below where for Platform region, I turn it to true and for a Valid Region , I turn it back to false. Also I add this condition check in controller.right check as well.
So for an obstacle region that comes , you can make a condition that if the person is blockedRight and it tries to jump, you will set the blockedRight again to false. I am assuming the obstacles will be always taken care by jumping unless you have those which are greater than your jump height where more checks come in place.
var ctx, controller, rectangle, loop;
ctx = document.querySelector("canvas").getContext("2d");
// Screen size
ctx.canvas.height = 200;
ctx.canvas.width = 400;
// Position of Player
rectangle = {
height: 25,
jumping: true,
width: 25,
x: 10,
x_velocity: 0,
y: 0,
y_velocity: 0,
blockedRight:false
};
controller = {
left: false,
right: false,
up: false,
keyListener: function(event) {
var key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 37: // Left
controller.left = key_state;
break;
case 39: // Right
controller.right = key_state;
break;
case 38: // Up
controller.up = key_state;
break;
};
}
};
loop = function() {
if (controller.up && rectangle.jumping == false) {
rectangle.y_velocity -= 25;
rectangle.jumping = true;
};
if (controller.left) {
rectangle.x_velocity -= 0.75;
};
if (controller.right && !rectangle.blockedRight) {
rectangle.x_velocity += 0.75;
};
// Gravity
rectangle.y_velocity += 1.5;
rectangle.x += rectangle.x_velocity;
rectangle.y += rectangle.y_velocity;
// Friction
rectangle.x_velocity *= 0.75;
rectangle.y_velocity *= 0.75;
// Floor
if (rectangle.y > 150 - 25) {
rectangle.jumping = false;
rectangle.y = 150 - 25;
rectangle.y_velocity = 0;
};
// Valid ground
if(rectangle.x <= 150 - 25){
rectangle.blockedRight = false;
}
// Platform
if (rectangle.y > 145 - 25 && rectangle.x > 150 - 25) {
rectangle.blockedRight = true;
rectangle.jumping = false;
rectangle.y = 145-25;
rectangle.y_velocity = 0;
};
// Background
var bg = new Image;
bg.src = "https://i.imgur.com/He3uld9.png";
bg.onload = function() {
ctx.drawImage(bg, 0, 0);
};
// Player
var ply = new Image;
ply.src = "https://i.imgur.com/G4UUkIl.png";
ply.onload = function() {
ctx.drawImage(ply, rectangle.x, rectangle.y);
};
// Floor
var fl = new Image;
fl.src = "https://i.imgur.com/OoKP4Mm.png";
fl.onload = function() {
ctx.drawImage(fl, 0, 150);
};
window.requestAnimationFrame(loop);
};
window.addEventListener("keydown", controller.keyListener);
window.addEventListener("keyup", controller.keyListener);
window.requestAnimationFrame(loop);
<canvas style="border: 1px solid black;"></canvas>
So I'm making this pretty basic game I would say for a school project. I have all the basic controllers working, jumping, navigating left and right, but I'm struggling to find a way to make the character be able to shoot. I would also like to make it so it's like a break between each shoot, like a bolt action. The collision part shouldn't be a problem, so no need for help there.
(function() {
var requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 640,
height = 480,
player = {
x: width / 2,
y: height - 140,
width: 35,
height: 90,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var hovedkarakterBilde = new Image();
hovedkarakterBilde.src = "mc1.png";
var boxes = [];
// dimensions
boxes.push({
// venstre vegg
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
// gulv
x: 0,
y: height - 68,
width: width,
height: 1
});
boxes.push({
x: 120,
y: 250,
width: 80,
height: 80
});
boxes.push({
x: 170,
y: 275,
width: 80,
height: 80
});
boxes.push({
x: 220,
y: 325,
width: 80,
height: 80
});
boxes.push({
x: 270,
y: 225,
width: 40,
height: 40
});
canvas.width = width;
canvas.height = height;
function update() {
// check keys
if (keys[38]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
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;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if (player.grounded) {
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.fill();
ctx.drawImage(
hovedkarakterBilde,
player.x,
player.y,
player.width,
player.height
);
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = shapeA.x + shapeA.width / 2 - (shapeB.x + shapeB.width / 2),
vY = shapeA.y + shapeA.height / 2 - (shapeB.y + shapeB.height / 2),
// add the half widths and half heights of the objects
hWidths = shapeA.width / 2 + shapeB.width / 2,
hHeights = shapeA.height / 2 + shapeB.height / 2,
colDir = null;
// if the x and y vector are less than the half width or half height, they
we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
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();
});
HTML:
</head>
<body>
<canvas id="canvas" style="background: url('bakgrunn1.png')"></canvas>
</body>
<script src="spillv2.js"></script>
First thing you have to consider is if the bullet is hit-scan or projectile. Hit-scan means when the bullet is shot, the bullet instantly hits the target. This can be done by using a ray-cast to check if it hits an object. Projectile based bullets are when the user points in a direction, the bullet actually "moves". This can be implemented by adding an array of "bullets" to the player. So when the player clicks, a bullet object is added the array. This bullet object will be drawn on it's own in the draw loop and will move from the user to the direction it's pointed at.
Adding a delay is simple, you can have a "cooldown" variable that is a counter that lasts for n milliseconds. When the user fires, the counter is set to n and starts to count down to 0. When it reaches 0, you are able to fire again.
Well, you could make a shoot(e) function, which will be called when user presses (keydown) space for example and then make a new array, lets say ammo[]. Then, inside shoot() you will do something like:
const ammo = [];
let shooting = false;
function shoot(e) {
e = e || event;
const key = e.keyCode;
if(shooting) return; // This will prevent from shooting more bullets while holding space
// So you'd need to press space for each time you want to shoot.
if(key == 32) { // Key code 32 is SPACE
shooting = true;
// You get the coordinates from your player, from which the bullet will shoot
ammo.push({
x: player.x,
y: player.y + (player.height / 2)
// Player.height / 2 is basically setting the ammo at the middle of the character
});
}
}
And then, I presume you do all the updates in the update() function (yea, logically :D), you'll do something like:
function update() {
// Insert it somewhere
for(let i = 0; i < ammo.length; i++) {
// The "theBullet" part refers to either your image for the bullet
ctx.drawImage(theBullet, ammo[i].x, ammo[i].y;
ammo[i].x++ // Or however fast you'd like it to go.
}
}
Hope its somewhat clear, I am working myself on a spaceshooter type of game, almost finished, so shared some of my code here :) Not implying that its the best, but it does the work :)
I am trying to create a simple snake game. My problem is, most of the times when the snake meets the food, the position of the snake is not how it should be.
For a better understanding, please look at this screenshot where the snake (white) meets the food (green):
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 3;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width) - 20;
food_position_y = Math.floor(Math.random() * canvas.height) - 20;
// Drawing
function draw() {
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(x, y, 20, 20);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(food_position_x, food_position_y, 20, 20);
ctx.fillStyle = "lightgreen";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
canvas { background-color:red }
<canvas id="canvas" width="600" height="400"></canvas>
So it seems like I would need a simple grid system but how would I go ahead on this to fix this issue?
I can't see the code for your collision. But I think you have a mistake in your origin. The origin of your squares is not in the middle, it is on the top left corner.
I am making a little game with my friends but i am trying to detect the collision when bumping in the the walls of the canvas, and I made it work but when i hit the wall my caracter gets stuck.. and i dont know how to find out a way to make him move again. Do you think any of you guys could help me out with this one. Thanks for all help!
Javascript / jQuery:
function Player() {
this.w = 50;
this.h = 60;
this.x = (cW / 2) - (this.w / 2);
this.y = (cH / 2) - (this.h / 2);
this.name = username.value;
this.nw = ctx.measureText(this.name).width; // username.clientWidth + 1;
this.src = playerImage;
this.dx = 0;
this.dy = 0;
this.render = function() {
ctx.drawImage(this.src, this.x, this.y, this.w, this.h);
ctx.fillStyle = 'orange';
ctx.font = '15px Arial, sans-serif';
// fixa x-värdet
ctx.fillText(this.name, (this.x + this.w / 2) - (this.nw / 2), (this.y - 6));
}
}
var player = new Player();
function animate() {
if(player.x > 0 && player.y > 0 && player.x + player.w < cW && player.y + player.h < cH) {
player.x += spd * player.dx;
player.y += spd * player.dy;
}
else {
// Need code here to release player from wall
}
ctx.save();
ctx.clearRect(0, 0, cW, cH);
ctx.drawImage(bg, 0, 0);
player.render();
ctx.rotate(-.4);
raining();
ctx.restore();
}
var animateInterval = setInterval(animate, 1000/60);
document.addEventListener('keydown', function(e) {
var key_press = String.fromCharCode(e.keyCode);
switch(key_press) {
case 'W':
player.dy = -1;
break;
case 'A':
player.dx = -1;
break;
case 'S':
player.dy = 1;
break;
case 'D':
player.dx = 1;
break;
default:
break;
}
});
document.addEventListener('keyup', function(e) {
var key_press = String.fromCharCode(e.keyCode);
switch(key_press) {
case 'W':
player.dy = 0;
break;
case 'A':
player.dx = 0;
break;
case 'S':
player.dy = 0;
break;
case 'D':
player.dx = 0;
break;
default:
break;
}
});
The problem you are having is the following:
Suppose your character is moving at the speed of 10 pixels per frame, the character position is currently 595px (the right side of the character) and the canvas width is 600.
On the current frame you are checking if there is a collision: there's none so you add the speed to the current position and you get 605px. Now on the next frame the character is out the bounds and you cannot move him anymore because the player.x + player.width > canvas.width
What you can do:
1: You check for the collision and move the character back inside the viewport:
if (player.x + player.width > canvas.width) {
player.x = canvas.width - player.width;
}
Because the collision check fails now, you can move him wherever you want.
You should do this check for all the sides, but the logic is different for each side, this is sample code for collision with the left wall:
if (player.x < 0) {
player.x = 0;
}
2: In your if statement you should add the speed in your calculations and not move the character if the player.x + player.vx exceeds canvas.width, but I prefer the first method as you can actually be at the side of the viewport
Tip with working with canvas positions: always round off your positions at the render level:
this.render = function() {
ctx.drawImage(this.src, Math.round(this.x), Math.round(this.y), this.w, this.h);
...
}