Wall collision detection, clitches though walls - javascript

I'm doing an app in React/html5/canvas. In the canvas, you as the user can move around in different rooms with mouseclicks. That works, and I have made the collision detection for all the walls for the rooms (the view is 2d like a RTS game).
Now to the problem: When I hit a wall I set user.collision = true; And the next mouseclick will set user.collision = false;and this will make my character move again. Problem is that I now can clip through walls if I click some more times (it clitches through).
Have thought about the logical around this and I can't figure it out, and my research did not help me.
Here is my collision detection function: (All the walls are in the this.props.data)
collision: function(){
for (var i = 0; i < this.props.data.length; i++){
if (user.posX > this.props.data[i].x2 && user.posX < this.props.data[i].x1 &&
user.posY < this.props.data[i].y2 && user.posY > this.props.data[i].y1){
user.collision = true;
}
}
},
Here is my handleMouseClick function:
handleMouseClick: function(event){
var rect = game.getBoundingClientRect();
mouseClick.y = event.nativeEvent.clientY - rect.top;
mouseClick.x = event.nativeEvent.clientX - rect.left;
distance = Math.sqrt(Math.pow(mouseClick.x - user.posX, 2) + Math.pow(mouseClick.y - user.posY,2));
user.directionX = (mouseClick.x - user.posX) / distance;
user.directionY = (mouseClick.y - user.posY) / distance;
if (user.collision = true){
user.collision = false;
}
},
Here is my update function:
update: function(){
context.canvas.height);
if (!user.collision){
if(user.moving === true){
user.posX += user.directionX * user.speed * elapsed;
user.posY += user.directionY * user.speed * elapsed;
this.collision();
if(user.posX >= mouseClick.x -5 && user.posX <= mouseClick.x + 5 && user.posY >= mouseClick.y -5 && user.posY <= mouseClick.y + 5){
user.moving = false;
}
}
}
this.drawUser();
this.drawWalls();
},

How about just reverting to the previous pos if the collision test fails ?
update: function(){
context.canvas.height);
var prevPosX = user.posX;
var prevPosY = user.posY;
if (!user.collision){
if(user.moving === true){
user.posX += user.directionX * user.speed * elapsed;
user.posY += user.directionY * user.speed * elapsed;
this.collision();
if( user.collision ) { // ooops !
user.posX = prevPosX;
user.posY = prevPosY;
}
if(user.posX >= mouseClick.x -5 && user.posX <= mouseClick.x + 5 && user.posY >= mouseClick.y -5 && user.posY <= mouseClick.y + 5){
user.moving = false;
}
}
}
this.drawUser();
this.drawWalls();
},
NB: typo here
if (user.collision = true){

Related

how to calculate percisely the character movement in a tiles

So, i have started building a game 2d just a few day so its make me so confuse with some reason of the movement character in the tilemap.In my tilemap, every per tiles2 is have the width and height 16px and the whole map is 800 x 1250, every movement of my character will add/sub 1 in per step, when I calculating detection collisions, the position became wrong position specifically when character move a step then the position return to far though i try to divide 16 px in every movement of character.
This is my movement:
this.setting_walking_speed = 3 ;
if (this.player.control_direction[0] == 1) {
this.player.x -= this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 0;
} else if (this.player.control_direction[1] == 1) {
this.player.y -= this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 2;
} else if (this.player.control_direction[2] == 1) {
this.player.x += this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 1;
} else if (this.player.control_direction[3] == 1) {
this.player.y += this.setting_walking_speed;
this.player.walking = 1;
this.player.direction = 3;
}
var posf = {
x:Math.floor( this.player.y /16 ) ,
y:Math.floor( this.player.x /16 )
};
this.collide(posf);
console.log(posf.x , posf.y);
}
And the collision function is:
The this.setting_minblocksize\[k\] = 16;
this.bound = this.draw_collision();
function rectangularCollision({rect1, rect2 }) {
return (
rect1.x >= rect2.x &&
rect1.x <= rect2.x &&
rect1.y <= rect2.y &&
rect1.y >= rect2.y
)
}
this.collide = function(player){
// console.log(this.bound);
this.bound.forEach((boundaries) => {
if(
rectangularCollision({,
rect1: player,
rect2: boundaries
})
){
console.log('collide');
}
})
}
this.draw_collision = function () {
var obj = [];
this.ctxt.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < canvas.height; i++) {
for (var j = 0; j < canvas.width; j++) {
var data = 0;
if (i >= 0 && j >= 0 && i < this.map.layers[1].height && j < this.map.layers[1].width) {
var data = this.map.layers[1].data[i * this.map.layers[1].width + j];
for (var k = 0; k < 1; k++) {
this.ctxt.fillStyle = 'red';
if (data != 0) {
obj.push({
x: j ,
y: i
});
this.ctxt.fillRect(
(j * this.setting_minblocksize[k]) ,
(i * this.setting_minblocksize[k]) ,
this.setting_minblocksize[k],
this.setting_minblocksize[k]
);
}
}
}
}
}
return obj;
}
My codepen link is right here
Thank you all for helping me!

I am having an issue redrawing some circles onto my html canvas

I am using a basic html canvas to create a simple game using javascript, but I am having an issue while trying to redraw my window. I have created a redraw_window function that I call whenever i want a new frame to show on the screen, but when I try to call the redraw_window function from this location on line 151, it does not work. The screen does not update. Any ideas why?
const c = canvas.getContext("2d")
canvas.width = innerWidth
canvas.height = innerHeight
const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;
class Light {
constructor(pos,vel){
this.pos = pos
this.vel = vel
}
move(){
if (this.pos == 0){
this.vel = 1
}
if(this.pos == 9){
this.vel = -1
}
this.pos += this.vel
}
}
function is_not_in(val,list){
for (var i = 0; i < list.length; i++){
if (list[i] == val){
return false
}
}
return true
}
function clear_window(){
c.clearRect(0,0,canvas.width,canvas.height)
}
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
function redraw_window(pos){
c.font = "80px serif"
//let board = [1,1,1,1,1,1,1,1,1,1]
positions = [canvas.width/2-450,canvas.width/2-350,canvas.width/2-250,canvas.width/2-150,canvas.width/2-50,canvas.width/2+50,canvas.width/2+150,canvas.width/2+250,canvas.width/2+350,canvas.width/2+450,]
//board[light.pos] = 0
clear_window()
c.fillStyle = "black"
//c.fillText(board.toString(),canvas.width/2-c.measureText(board.toString()).width/2,canvas.height/2)
//c.fillText("Troy likes big hairy black balls",canvas.width/2-c.measureText("Troy likes big hairy black balls").width/2,canvas.height/2+80)
for (var i = 0; i < positions.length; i++) {
let radius = 20
if (pos != i){
c.beginPath()
c.arc(positions[i],canvas.height/2,radius,0,Math.PI * 2,false)
c.fillStyle = "black"
c.fill()
}
if (pos == i){
c.beginPath()
c.arc(positions[i],canvas.height/2,radius,0,Math.PI * 2,false)
c.fillStyle = "green"
c.fill()
}
}
}
function choose(choices) {
var index = Math.floor(Math.random() * choices.length);
return choices[index];
}
function win_animation(){
redraw_window(null)
sleep(300)
redraw_window(light.pos)
sleep(300)
redraw_window(null)
sleep(300)
redraw_window(light.pos)
}
var light = new Light(random(0,9),choose([-1,1]))
function main(){
var FPS = 60
var SPEED = 0.5
var COOLDOWN = FPS * 0.25
var SCORE_TO_WIN = 5
var right_player_points = 0
var left_player_points = 0
var frame = 0
var right_player_cooldown = 0
var left_player_cooldown = 0
var keys_pressed = []
var right_player_key = "ShiftRight"
var left_player_key = "ShiftLeft"
var right_player_cooldown = 0
var left_player_cooldown = 0
var playing = true
//handles cooldown and keys pressed list
window.addEventListener("keydown",(event)=>{
if (event.code == right_player_key && is_not_in(right_player_key,keys_pressed)){
if (right_player_cooldown == 0){
right_player_cooldown = COOLDOWN
keys_pressed.push(event.code)
}
}
if (event.code == left_player_key && is_not_in(left_player_key,keys_pressed)){
if (left_player_cooldown == 0){
left_player_cooldown = COOLDOWN
keys_pressed.push(event.code)
}
}
})
//runs fps times per second
var run = setInterval(run,1000 / FPS)
function run(){
frame += 1
if (left_player_cooldown > 0){
left_player_cooldown -= 1
}
if (right_player_cooldown > 0){
right_player_cooldown -= 1
}
//runs SPEED times per second
if (frame >= FPS * SPEED){
frame = 0
if (!is_not_in(right_player_key,keys_pressed) && light.pos == 9){
right_player_points += 1
**VVV THIS IS WHERE I AM HAVING MY ISSUE VVV**
redraw_window(null);
alert("right player:" + right_player_points.toString())
if (right_player_points >= SCORE_TO_WIN){
alert("right player Wins")
right_player_points = 0
left_player_points = 0
light = new Light(random(0,9),choose([-1,1]))
}
}
if (!is_not_in(left_player_key,keys_pressed) && light.pos == 0){
left_player_points += 1
light = new Light(random(0,9),choose([-1,1]))
alert("left player:" + left_player_points.toString())
if (left_player_points >= SCORE_TO_WIN){
alert("left player wins")
left_player_points = 0
right_player_points = 0
}
}
light.move()
redraw_window(light.pos)
keys_pressed = []
}
}
}
main() ```
The main issue I can see here is that you have a variable and a function both named run. The setInterval call is being overwritten with the function definition. I recommend you rename the variable run to runInterval.
Change
var run = setInterval(run, 1000 / FPS)
to
var runInterval = setInterval(run, 1000 / FPS)
See if that helps.

player movement diagonally - too fast || NodeJS

If I move the player right, left, up or down I move 5px in that direction.
But if I press down and right for example player is moving 5px right and 5px down which is around 7 pixels from the previous position instead 5px.
I can add next IF statement: if (up and down) then spdX and spdY = (maxSpd - maxSpd√2) / or simple -25% ?.
But I think already my code is bit messy...
Any nice solutions which are fast and looks simple? :)
That is my code:
self.updateSpd = function(){
if(self.pressingRight){
self.spdX = self.maxSpd;
if(self.pressingShift && self.stamina > 0){
self.spdX += self.maxRun;
self.stamina --;
}
}
else if(self.pressingLeft){
self.spdX = -self.maxSpd;
if(self.pressingShift && self.stamina > 0){
self.spdX -= self.maxRun;
self.stamina --;
}
}
else{
self.spdX = 0;
}
if(self.pressingUp){
self.spdY = -self.maxSpd;
if(self.pressingShift && self.stamina > 0){
self.spdY -= self.maxRun;
self.stamina --;
}
}
else if(self.pressingDown){
self.spdY = self.maxSpd;
if(self.pressingShift && self.stamina > 0){
self.spdY += self.maxRun;
self.stamina --;
}
}
else{
self.spdY = 0;
}
}
You could make variables for X and Y direction with values -1, 0, 1:
var dirX = -self.pressingLeft + self.pressingRight;
var dirY = -self.pressingUp + self.pressingDown;
Then adjust when moving diagonally:
if (dirX !== 0 && dirY !== 0) {
dirX *= Math.SQRT1_2;
dirY *= Math.SQRT1_2;
}
Then apply the rest:
var speed = self.maxSpd;
if (self.pressingShift && self.stamina > 0 && (dirX !== 0 || dirY !== 0)) {
speed += self.maxRun;
self.stamina--;
}
self.spdX = speed * dirX;
self.spdY = speed * dirY;
All told:
self.updateSpd = function () {
var dirX = -self.pressingLeft + self.pressingRight;
var dirY = -self.pressingUp + self.pressingDown;
if (dirX !== 0 && dirY !== 0) {
dirX *= Math.SQRT1_2;
dirY *= Math.SQRT1_2;
}
var speed = self.maxSpd;
if (self.pressingShift && self.stamina > 0 && (dirX !== 0 || dirY !== 0)) {
speed += self.maxRun;
self.stamina--;
}
self.spdX = speed * dirX;
self.spdY = speed * dirY;
};
Or maybe:
self.updateSpd = function () {
var dirX = -self.pressingLeft + self.pressingRight;
var dirY = -self.pressingUp + self.pressingDown;
var speed = self.maxSpd;
if (self.pressingShift && self.stamina > 0 && (dirX !== 0 || dirY !== 0)) {
speed += self.maxRun;
self.stamina--;
}
if (dirX !== 0 && dirY !== 0) {
speed *= Math.SQRT1_2;
}
self.spdX = speed * dirX;
self.spdY = speed * dirY;
};
Note that this does behave differently from your original when both left and right are pressed (no movement, rather than moving right) or when both up and down are pressed (no movement, rather than moving up).

Why isn't my condition working?

In javascript, I'm making an HTML canvas game, and in that game I have an object type/constructor called gamePiece. gamePiece has a function called checkCollision:
this.checkCollision = function(piece){
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y <= this.y && piece.y <= (this.y - this.height);
if(collisionX || collisionY){
return true;
} else {
return false;
}
}
which is called by update()
function update(){
context.clearRect(0, 0, game.width, game.height);
for(var i = 0; i < gamePieces.length; i++){
gamePieces[i].update();
for(var mi = 0; mi < gamePieces.length; mi++){
gamePieces[i].checkCollision(gamePieces[mi]);
if(gamePieces[i].checkCollision(gamePieces[mi]) == true){
gamePieces[i].collisionFunction();
}
}
}
}
setInterval(function(){update();}, 1);
I have another object that is supposed to give a speed boost upon colliding with another game piece, and it logs every time it gives a speed boost.
var speedBooster = new gamePiece(25,25,"red",300,300,0);
speedBooster.collisionFunction = function(){
for(var whichpiece = 0; whichpiece < gamePieces.length; whichpiece++){
if(speedBooster.checkCollision(gamePieces[whichpiece]) == true && gamePieces[whichpiece] != this){
gamePieces[whichpiece].speed += 10;
console.log("gamePieces[" + whichpiece + "] has been given a speed boost.");
}
}
}
But it gives a speed boost whenever a piece is behind it, and I put the "piece.x >= this.x &&" there for a reason. Why is JavaScript ignoring the condition I gave it?
Try
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y >= this.y && piece.y <= (this.y + this.height);
if(collisionX && collisionY){
return true;
} else {
return false;
}
To test if two objects overlap. Where the object has x,y as the top left and w,h as width and height
//Returns true if any part of box1 touches box2
function areaTouching(box1,box2){
return ! (box1.x > box2.x + box2.w ||
box1.x + box1.w < box2.x ||
box1.y > box2.y + box2.h ||
box1.y + box1.h < box2.y)
}

More JS AI causes slower AI movement in HTML Canvas

I have a simple little game with one character as the player and four enemy characters. I created a very basic AI, that moves towards the player when the player is nearby. That all worked fine, but when I added AI-AI collision (using a bounding box model), it slowed it down tremendously, and exponentially the more AI there are. With four AI, they move quite slowly. 3 AI is a bit better. 2 is just perfect, and 1 is too fast.
I have the following function to calculate the AI movement when near a player.
function updateAI() {
for (i = 0; i < aiCount; i++) {
if (aiCounterAI >= aiCount) {
aiCounterAI = 0;
}
checkArmyAIcol = armyAI[aiCounterAI][1];
checkArmyAIrow = armyAI[aiCounterAI][2];
enemySpeed = enemies[armyAI[aiCounterAI][0][0]][3];
enemyPlayerCollision = false;
if (playerBattle.xCoord - 6 <= checkArmyAIcol && playerBattle.xCoord + 6 >= checkArmyAIcol) {
if (playerBattle.yCoord - 6 <= checkArmyAIrow && playerBattle.yCoord + 6 >= checkArmyAIrow) {
if (playerBattle.x < armyAI[aiCounterAI][3] - 48) {
armyAI[aiCounterAI][3] = armyAI[aiCounterAI][3] - enemySpeed;
aiDirection = 'left';
}
if (playerBattle.x > armyAI[aiCounterAI][3] + 48) {
armyAI[aiCounterAI][3] = armyAI[aiCounterAI][3] + enemySpeed;
aiDirection = 'right';
}
if (playerBattle.y < armyAI[aiCounterAI][4] - 48) {
armyAI[aiCounterAI][4] = armyAI[aiCounterAI][4] - enemySpeed;
aiDirection = 'up';
}
if (playerBattle.y > armyAI[aiCounterAI][4] + 48) {
armyAI[aiCounterAI][4] = armyAI[aiCounterAI][4] + enemySpeed;
aiDirection = 'down';
}
checkBattleCollision('ai',aiCounterAI);
armyAI[aiCounterAI][1] = Math.ceil(armyAI[aiCounterAI][3] / 48);
armyAI[aiCounterAI][2] = Math.ceil(armyAI[aiCounterAI][4] / 48);
}
}
aiCounterAI++;
}
}
And finally I have this function to calculate the AI collision.
if (type == 'ai') {
enemyEnemyCollision = false;
if (aiCount > 1) {
checkArmyAIcol1 = armyAI[ai][1];
checkArmyAIrow1 = armyAI[ai][2];
checkArmyAIx1 = armyAI[ai][3];
checkArmyAIy1 = armyAI[ai][4];
var aiCounter2 = 0;
for (i = 0; i < aiCount; i++) {
if (aiCounter2 != ai) {
checkArmyAIcol2 = armyAI[aiCounter2][1];
checkArmyAIrow2 = armyAI[aiCounter2][2];
checkArmyAIx2 = armyAI[aiCounter2][3];
checkArmyAIy2 = armyAI[aiCounter2][4];
// Check if the AI is near the other AI before checking if collision is true
if (checkArmyAIcol1 - 1 <= checkArmyAIcol2 && checkArmyAIcol1 + 1 >= checkArmyAIcol2) {
if (checkArmyAIrow1 - 1 <= checkArmyAIrow2 && checkArmyAIrow1 + 1 >= checkArmyAIrow2) {
if (checkArmyAIx1 < checkArmyAIx2 + 48 &&
checkArmyAIx1 + 48 > checkArmyAIx2 &&
checkArmyAIy1 < checkArmyAIy2 + 48 &&
checkArmyAIy1 + 48 > checkArmyAIy2) {
enemyEnemyCollision = true;
checkEnemyEnemyCollision(ai,aiCounter2);
}
}
}
}
aiCounter2++;
}
}
}
function checkEnemyEnemyCollision(enemy1,enemy2) {
enemySpeed = enemies[armyAI[enemy1][0][0]][3];
if (enemyEnemyCollision == true) {
if (aiDirection == 'left') {
armyAI[enemy1][3] = armyAI[enemy1][3] + enemySpeed;}
if (aiDirection == 'right') {
armyAI[enemy1][3] = armyAI[enemy1][3] - enemySpeed;}
if (aiDirection == 'up') {
armyAI[enemy1][4] = armyAI[enemy1][4] + enemySpeed;}
if (aiDirection == 'down') {
armyAI[enemy1][4]= armyAI[enemy1][4] - enemySpeed;}
console.log("ya'll collided ya clumsy potatoes");
}
}
The updateAI function is fast and runs great. Adding the collision (using a bounding box model) as said before slows it down a lot. These functions are called sixty times a second, through requestAnimationFrame in my gameloop. My guess is that it can't keep up fast enough in the collision with the frame rate so they just can't move much as they could otherwise. Yet, I don't know how to fix this. Does anyone have any suggestions? Bounding box collision and multiple moving items is new territory for me so I wouldn't mind suggestions on improving my code.

Categories

Resources