2

How do you create a rectangle-to-rectangle collision system that stops the player from moving in that direction? e.g. making the player not able to move up if an object is in the way. I know how to make the player not able to go off the edge, but I don't know how to make a collision for a solid object. e.g. A box or cube that you can't go through and stops player movement on that side of the cube.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cWidth = 400;
var cHeight = 250;
var keyboardKeys = [];
var friction = 0.8;

var solidObjs = [];

class Player {
  constructor(x, y, width, height, color) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.color = color;
    this.velX = 0;
    this.velY = 0;
    this.speed = 5;
  }
}

function createObj(x, y, width, height, color) {
  solidObjs.push({
    x: x,
    y: y,
    width: width,
    height: height,
    color: color
  });
}

var player1 = new Player(cWidth / 2, cHeight / 2, 25, 25, "#0080ff");

canvas.width = cWidth;
canvas.height = cHeight;

createObj(0, 0, 10, cHeight, "#808080");
createObj(cWidth - 10, 0, 10, cHeight, "#808080");
createObj(0, 0, cWidth, 10, "#808080");
createObj(0, cHeight - 10, cWidth, 10, "#808080");
createObj(50, 50, 100, 100, "#808080");

function drawFrame() {
  ctx.clearRect(0, 0, cWidth, cHeight);
  ctx.fillStyle = "#000000";
  ctx.fillRect(0, 0, cWidth, cHeight);

  if (keyboardKeys["w"] || keyboardKeys["ArrowUp"]) {
    if (player1.velY > player1.speed * -1) {
      player1.velY--;
    }
  }

  if (keyboardKeys["s"] || keyboardKeys["ArrowDown"]) {
    if (player1.velY < player1.speed) {
      player1.velY++;
    }
  }

  if (keyboardKeys["a"] || keyboardKeys["ArrowLeft"]) {
    if (player1.velX > player1.speed * -1) {
      player1.velX--;
    }
  }

  if (keyboardKeys["d"] || keyboardKeys["ArrowRight"]) {
    if (player1.velX < player1.speed) {
      player1.velX++;
    }
  }

  player1.velX *= friction;
  player1.velY *= friction;

  player1.x += player1.velX;
  player1.y += player1.velY;

  ctx.fillStyle = player1.color;
  ctx.fillRect(player1.x, player1.y, player1.width, player1.height);

  for (i = 0; i < solidObjs.length; i++) {
    ctx.fillStyle = solidObjs[i].color;
    ctx.fillRect(solidObjs[i].x, solidObjs[i].y, solidObjs[i].width, solidObjs[i].height);

    advancedCollisionCheck(player1, solidObjs[i]);
  }

  ctx.fillStyle = "white";
  ctx.font = "16px arial";
  ctx.fillText("Add collision to this box.", 50, 66);
}

function simpleCollisionCheck(obj1, obj2) {
  if (obj1.x < obj2.x + obj2.width && obj1.x + obj1.width > obj2.x &&
    obj1.y < obj2.y + obj2.height && obj1.y + obj1.height > obj2.y) {
    return true;
  }
}

function advancedCollisionCheck(obj1, obj2) {
    //looking for an answer for this
}

setInterval(() => {
  drawFrame();
}, 1000 / 60);

document.body.addEventListener("keydown", (e) => {
  keyboardKeys[e.key] = true;
});

document.body.addEventListener("keyup", (e) => {
  keyboardKeys[e.key] = false;
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    * {
      padding: 0px 0px;
      margin: 0px 0px;
      box-sizing: border-box;
    }
  </style>
  <title>Document</title>
</head>

<body>
  <canvas id="canvas"></canvas>
  <script src="pg2d.js"></script>
</body>

</html>

I've tried but it seems to disable the player from moving even if they aren't touching any objects.

Pete21
  • 102
  • 11
  • https://stackoverflow.com/questions/2440377/javascript-collision-detection – Konrad Dec 30 '22 at 19:05
  • 1
    [This answer](https://stackoverflow.com/a/60252977/6243352) is for mouse, but the collision resolution is the same for keyboard. – ggorlen Dec 30 '22 at 19:09
  • I need an answer that detects what side the player hit e.g. the player ran into the left side of an object, so they now can't go left because they ran into that side of the object. – Pete21 Dec 30 '22 at 19:12
  • Yup, isn't that what my link above shows? Did you read the whole post? – ggorlen Dec 30 '22 at 19:12

2 Answers2

1

So I figured this out on my own now, and it is simpler than I thought.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cWidth = 400;
var cHeight = 250;
var keyboardKeys = [];
var friction = 0.8;
var fps = 60;
var gameLoop;

var solidObjs = [];

class Player {
  constructor(x, y, width, height, color) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.color = color;
    this.velX = 0;
    this.velY = 0;
    this.speed = 5;
  }
}

function createObj(x, y, width, height, color) {
  solidObjs.push({
    x: x,
    y: y,
    width: width,
    height: height,
    color: color
  });
}

var player1 = new Player(cWidth / 2, cHeight / 2, 25, 25, "#0080ff");

canvas.width = cWidth;
canvas.height = cHeight;

createObj(0, 0, 10, cHeight, "#808080");
createObj(cWidth - 10, 0, 10, cHeight, "#808080");
createObj(0, 0, cWidth, 10, "#808080");
createObj(0, cHeight - 10, cWidth, 10, "#808080");
createObj(50, 50, 100, 100, "#808080");

function drawFrame() {
  ctx.clearRect(0, 0, cWidth, cHeight);
  ctx.fillStyle = "#000000";
  ctx.fillRect(0, 0, cWidth, cHeight);

  if (keyboardKeys["w"] || keyboardKeys["ArrowUp"]) {
    if (player1.velY > player1.speed * -1) {
      player1.velY--;
    }
  }

  if (keyboardKeys["s"] || keyboardKeys["ArrowDown"]) {
    if (player1.velY < player1.speed) {
      player1.velY++;
    }
  }

  if (keyboardKeys["a"] || keyboardKeys["ArrowLeft"]) {
    if (player1.velX > player1.speed * -1) {
      player1.velX--;
    }
  }

  if (keyboardKeys["d"] || keyboardKeys["ArrowRight"]) {
    if (player1.velX < player1.speed) {
      player1.velX++;
    }
  }

  player1.velX *= friction;
  player1.velY *= friction;

  player1.x += player1.velX;
  player1.y += player1.velY;

  for (i = 0; i < solidObjs.length; i++) {
    ctx.fillStyle = solidObjs[i].color;
    ctx.fillRect(solidObjs[i].x, solidObjs[i].y, solidObjs[i].width, solidObjs[i].height);

    if (simpleCollisionCheck(player1, solidObjs[i])) {
      advancedCollisionCheck(player1, solidObjs[i]);
    }
  }

  ctx.fillStyle = player1.color;
  ctx.fillRect(player1.x, player1.y, player1.width, player1.height);
}

function simpleCollisionCheck(obj1, obj2) {
  if (obj1.x < obj2.x + obj2.width && obj1.x + obj1.width > obj2.x &&
    obj1.y < obj2.y + obj2.height && obj1.y + obj1.height > obj2.y) {
    return true;
  }
}

function advancedCollisionCheck(obj1, obj2) {
  var vx = (obj1.x + obj1.width / 2) - (obj2.x + obj2.width / 2);
  var vy = (obj1.y + obj1.height / 2) - (obj2.y + obj2.height / 2);

  if (Math.abs(vx / obj2.width) > Math.abs(vy / obj2.height)) {
    if (vx < 0) {
      obj1.x = obj2.x - obj1.width;
    } else {
      obj1.x = obj2.x + obj2.width;
    }
  } else {
    if (vy < 0) {
      obj1.y = obj2.y - obj1.height;
    } else {
      obj1.y = obj2.y + obj2.height;
    }
  }
}

window.onload = function() {
  gameLoop = setInterval(() => {
    drawFrame();
  }, 1000 / fps);
}

document.body.addEventListener("keydown", (e) => {
  keyboardKeys[e.key] = true;
});

document.body.addEventListener("keyup", (e) => {
  keyboardKeys[e.key] = false;
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    * {
      padding: 0px 0px;
      margin: 0px 0px;
      box-sizing: border-box;
    }
  </style>
  <title>Document</title>
</head>

<body>
  <canvas id="canvas"></canvas>
</body>

</html>
Pete21
  • 102
  • 11
0

<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        * {
            padding: 0%;
            margin: 0%;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <canvas></canvas>
    <script>
        const c = document.querySelector("canvas");
        const gs = 1;
        const x = c.getContext('2d');
        c.style = "background-color: aqua;z-index:0;position:absolute;width:100%;height:100%;";
        function rect(rect1, rect2) {
                return (rect1.x < rect2.x + rect2.w &&
                    rect1.x + rect1.w > rect2.x &&
                    rect1.y < rect2.y + rect2.h &&
                    rect1.h + rect1.y > rect2.y)
        }
        var player = {x:100,y:50,w:10,h:10,spX:0,spY:0,draw:function(){x.clearRect(0,0,c.width,c.height);this.x+=this.spX;this.y+=this.spY;
            if (this.x <= 0) {
                this.x = 0;
            }
            else if (this.y <= 0) {
                this.y = 0;
            }
            else if (this.x + this.w >= c.width) {
                this.x = c.width - this.w
            }
            else if (this.y + this.h >= c.height) {
                this.y = c.height - this.h
            }
            
            x.fillStyle = 'red';x.fillRect(this.x, this.y, this.w, this.h)}}
        class pm {
            constructor(hlc,vlc) {
                this.x=hlc;
                this.y=vlc;
                this.w=10;
                this.h=10;
                this.d=false;
            }
            r() {
                this.x-=gs;
                if ((this.x+this.w) < 0) {
                    this.d=true;
                }
                x.fillStyle='green';
                x.fillRect(this.x,this.y,this.w,this.h);
            }
        }
        class l {
            constructor(hlc,vlc) {
                this.x=hlc;
                this.y=vlc;
                this.w=10;
                this.h=10;
            }
            r() {
                this.x+=gs+gs/2;
                if (this.x>c.width) {
                    this.d=true;
                }
                x.fillStyle='yellow';
                x.fillRect(this.x,this.y-1,this.w,this.h);
            }
        }
        let tr=0;
        let il=90;
        class gag {
            constructor() {
                this.pms=[];
                this.z=[];
                this.r=function () {
                    this.pms=pms.filter(pm=>pm.d);
                    this.z=z.filter(l=>l.d);
                }
            }
        }
        const ag=new gag();
        function a() {
            requestAnimationFrame(a);
            player.draw();
            if (tr<il) {
                tr += 1;
            }
            else if (tr>=il) {
                ag.pms.push(new pm(c.width,Math.random()*(c.height/2)));
                tr=0;
            }
            for (let i=0;i<ag.pms.length;i++) {
                const m=ag.pms[i];
                m.r();
            }
            for (let i=0;i<ag.z.length;i++) {
                const t=ag.z[i];
                t.r();
            }
            ag.z.forEach(lazer=>{
                for (let i = 0; i < ag.pms.length; i++) {
                    const rect2 = ag.pms[i];
                    if (rect(lazer, rect2)) {
                        lazer.d = true;
                        rect2.d = true;
                    }
                }
            });
                
        }
        function Shoot(){
            ag.z.push(new l(player.x+player.w,player.y));
        }
        function move(dir) {
            switch (dir) {
                case "up":
                    player.spY=-1;
                break;
                case "down":
                    player.spY=1;
                break;
                case "left":
                    player.spX=-1;
                break;
                case "right":
                    player.spX=1;
                break;
            }
        }
        function clearmove() {
            player.spX = 0;
            player.spY = 0;
        }
        a();
    </script>
    <button onmousedown="move('up')" onmouseup="clearmove()" ontouchend="clearmove()"ontouchstart="move('up')"style="position:absolute;top:70%;right:10%;left:80%;bottom:20%;z-index:1;">UP</button>
    <button onmousedown="move('left')" onmouseup="clearmove()" ontouchend="clearmove()"ontouchstart="move('left')"style="position:absolute;top:80%;right:20%;left:70%;bottom:10%;z-index:1;">LEFT</button>
    <button onmousedown="Shoot()" ontouchstart="Shoot()"style="position:absolute;top:80%;right:10%;left:80%;bottom:10%;z-index:1;">FIRE</button>
    <button onmousedown="move('right')"onmouseup="clearmove()" ontouchend="clearmove()" ontouchstart="move('right')"style="position:absolute;top:80%;right:0%;left:90%;bottom:10%;z-index:1;">RIGHT</button>
    <button onmousedown="move('down')" onmouseup="clearmove()" ontouchend="clearmove()"ontouchstart="move('down')"style="position:absolute;top:90%;right:10%;left:80%;bottom:0%;z-index:1;">DOWN</button>
    <script src="./index.js">
</body>
</html>
Herby
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 17 '23 at 10:06