0

I am trying making a collecting game. It's still in a work in progress. What I am trying to accomplish is add collision detection to the rectangle on the canvas so the sprite won't be able to phase through it. I know how to add collision so my sprite won't leave the canvas. My rectangles are on different points of the canvas and they do vary by size. I am wondering how I should go about doing that?

Also, totally optional, how should I go about having it so the player has to collect all the collectibles before talking to the dog. kinda like a quest.

I am new to this so apologies if what I described didn't make any sense.

Thank you!

Here's the live site: https://yewtreedesign.github.io/441_HW/HW11/index.html

I have tried to use ctx.rect as a value within the "if"

function moveCharacter(deltaX, deltaY, direction) {
  if (positionX + deltaX > 0 && positionX  + SCALED_WIDTH + deltaX < canvas.width) {
    positionX += deltaX;
  }
  if (positionY + deltaY > 0 && positionY + SCALED_HEIGHT + deltaY < canvas.height) {
    positionY += deltaY;
  }

but sprite gets stuck in place.

<script>
const SCALE = 1;
const WIDTH = 18;
const HEIGHT = 31;
const SCALED_WIDTH = SCALE * WIDTH;
const SCALED_HEIGHT = SCALE * HEIGHT;
const CYCLE_LOOP = [0, 1, 0, 2];
const FACING_DOWN = 0;
const FACING_UP = 1;
const FACING_LEFT = 2;
const FACING_RIGHT = 3;
const FRAME_LIMIT = 12;
const MOVEMENT_SPEED = 1;

let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
let keyPresses = {};
let currentDirection = FACING_DOWN;
let currentLoopIndex = 0;
let frameCount = 0;
let positionX = 0;
let positionY = 0;
let img = new Image();
let shiba = new Image();
let rays = new Image();
let doritos = new Image();
let walls= new Image();



window.addEventListener('keydown', keyDownListener);
function keyDownListener(event) {
    keyPresses[event.key] = true;
}

window.addEventListener('keyup', keyUpListener);
function keyUpListener(event) {
    keyPresses[event.key] = false;
}

function loadImage() {
  walls.src='image/walls.png'
  img.src = 'atlus/mainsprite.png';
  shiba.src = 'image/shiba.gif';
  rays.src='image/shades.png';
  doritos.src='image/dorit.png';
  img.onload = function() {
    window.requestAnimationFrame(gameLoop);

  };

}

function drawFrame(frameX, frameY, canvasX, canvasY) {
  ctx.beginPath();
  ctx.drawImage(shiba, 225,20);
  ctx.closePath();

  ctx.beginPath();
  ctx.drawImage(rays, 400,20);
  ctx.drawImage(doritos, 420,250);
  ctx.drawImage(img,
                frameX * WIDTH, frameY * HEIGHT, WIDTH, HEIGHT,
                canvasX, canvasY, SCALED_WIDTH, SCALED_HEIGHT);
  ctx.drawImage(walls,0,0);
  ctx.closePath();
}
function drawWalls(){
  ctx.beginPath();
  ctx.rect(105.3, -1, 14.1, 73.5);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.rect(366.5, -1, 14.1, 73.5);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.rect(367, 173.2, 120, 14.1);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.rect(-1, 173.2, 120, 14.1);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.rect(105.3, 267.5, 14.1, 73.5);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.rect(366.5, 267.5, 14.1, 73.5);
  ctx.stroke();
  ctx.closePath();

}


loadImage();

function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  let hasMoved = false;

  if (keyPresses.ArrowUp) {
    moveCharacter(0, -MOVEMENT_SPEED, FACING_UP);
    hasMoved = true;
  } else if (keyPresses.ArrowDown) {
    moveCharacter(0, MOVEMENT_SPEED, FACING_DOWN);
    hasMoved = true;
  }

  if (keyPresses.ArrowLeft) {
    moveCharacter(-MOVEMENT_SPEED, 0, FACING_LEFT);
    hasMoved = true;
  } else if (keyPresses.ArrowRight) {
    moveCharacter(MOVEMENT_SPEED, 0, FACING_RIGHT);
    hasMoved = true;
  }

  if (hasMoved) {
    frameCount++;
    if (frameCount >= FRAME_LIMIT) {
      frameCount = 0;
      currentLoopIndex++;
      if (currentLoopIndex >= CYCLE_LOOP.length) {
        currentLoopIndex = 0;
      }
    }
  }

  if (!hasMoved) {
    currentLoopIndex = 0;
  }

  drawFrame(CYCLE_LOOP[currentLoopIndex], currentDirection, positionX, positionY);
  window.requestAnimationFrame(gameLoop);
}

function moveCharacter(deltaX, deltaY, direction) {
  if (positionX + deltaX > 0 && positionX  + SCALED_WIDTH + deltaX < canvas.width) {
    positionX += deltaX;
  }
  if (positionY + deltaY > 0 && positionY + SCALED_HEIGHT + deltaY < canvas.height) {
    positionY += deltaY;
  }
  currentDirection = direction;
}

</script>

Right now the code is showing up stuff as it should, just there is no collision detection between objects, aside from the borders of the canvas with the sprite.

UPDATE: Thanks to ellertsmari, I am able to get collision detection to register and read on my console. There is collision detection. I am trying to get it so my character would stop on detection so the sprite won't walk over it. I am currently working on it. If anyone knows how to get that working, that'll be great. If I am able to find it on my own I'll update the code on here for others to look at :].

Updated code: (the link is also updated)

const SCALE = 1;
const WIDTH = 18;
const HEIGHT = 31;
const SCALED_WIDTH = SCALE * WIDTH;
const SCALED_HEIGHT = SCALE * HEIGHT;
const CYCLE_LOOP = [0, 1, 0, 2];
const FACING_DOWN = 0;
const FACING_UP = 1;
const FACING_LEFT = 2;
const FACING_RIGHT = 3;
const FRAME_LIMIT = 12;
const MOVEMENT_SPEED = 1;
let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
let keyPresses = {};
let currentDirection = FACING_DOWN;
let currentLoopIndex = 0;
let frameCount = 0;
let positionX = 0;
let positionY = 0;
let img = new Image();
let shiba = new Image();
let rays = new Image();
let doritos = new Image();
let walls=     [{"id": "wall1", "x": 105.3, "y": -1,    "width": 14.1, "height": 73.5},
                {"id": "wall2", "x": 366.5, "y": -1,    "width": 14.1, "height": 73.5},
                {"id": "wall3", "x": 367,   "y": 173.2, "width": 120,  "height": 14.1},
                {"id": "wall4", "x": -1,    "y": 173.2, "width": 120,  "height": 14.1},
                {"id": "wall5", "x": 105.3, "y": 267.5, "width": 14.1, "height": 73.5},
                {"id": "wall6", "x": 366.5, "y": 267.5, "width": 14.1, "height": 73.5}
              ];
              function drawWalls(){
                for(var i=0; i< walls.length; i++){
                  ctx.fillStyle="white";
                  ctx.fillRect(walls[i].x, walls[i].y, walls[i].width,walls[i].height);
                }
            }
            function collidingWith(walls){
              console.log("you are colliding with:", walls.id);

}
window.addEventListener('keydown', keyDownListener);
function keyDownListener(event) {
    keyPresses[event.key] = true;
}
window.addEventListener('keyup', keyUpListener);
function keyUpListener(event) {
    keyPresses[event.key] = false;
}
function loadImage() {
    img.src = 'atlus/mainsprite.png';
  shiba.src = 'image/shiba.gif';
  rays.src='image/shades.png';
  doritos.src='image/dorit.png';
  img.onload = function() {
    window.requestAnimationFrame(gameLoop);
  };
}
function drawFrame(frameX, frameY, canvasX, canvasY) {
  ctx.beginPath();
  ctx.drawImage(shiba, 225,20);
  ctx.closePath();
  ctx.beginPath();
  ctx.drawImage(rays, 400,20);
  ctx.drawImage(doritos, 420,250);
  ctx.drawImage(img,
                frameX * WIDTH, frameY * HEIGHT, WIDTH, HEIGHT,
                canvasX, canvasY, SCALED_WIDTH, SCALED_HEIGHT);
  ctx.closePath();
}

loadImage();
function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawWalls();

  let hasMoved = false;
  if (keyPresses.ArrowUp) {
    moveCharacter(0, -MOVEMENT_SPEED, FACING_UP);
    hasMoved = true;
  } else if (keyPresses.ArrowDown) {
    moveCharacter(0, MOVEMENT_SPEED, FACING_DOWN);
    hasMoved = true;
  }
  if (keyPresses.ArrowLeft) {
    moveCharacter(-MOVEMENT_SPEED, 0, FACING_LEFT);
    hasMoved = true;
  } else if (keyPresses.ArrowRight) {
    moveCharacter(MOVEMENT_SPEED, 0, FACING_RIGHT);
    hasMoved = true;
  }
  if (hasMoved) {
    frameCount++;
    if (frameCount >= FRAME_LIMIT) {
      frameCount = 0;
      currentLoopIndex++;
      if (currentLoopIndex >= CYCLE_LOOP.length) {
        currentLoopIndex = 0;
      }
    }
  }
  if (!hasMoved) {
    currentLoopIndex = 0;
  }
  drawFrame(CYCLE_LOOP[currentLoopIndex], currentDirection, positionX, positionY);
  window.requestAnimationFrame(gameLoop);
}
function moveCharacter(deltaX, deltaY, direction) {
  walls.forEach(walls=>{
  if( positionX + deltaX + SCALED_WIDTH > walls.x && positionX + deltaX < walls.x + walls.width
    && positionY + deltaY + SCALED_HEIGHT > walls.y && positionY + deltaY < walls.y + walls.height
  ){
    collidingWith(walls);
  }
})

if (positionX + deltaX > 0 && positionX + SCALED_WIDTH + deltaX < canvas.width) {positionX += deltaX;}
if (positionY + deltaY > 0 && positionY + SCALED_HEIGHT + deltaY < canvas.height) {positionY += deltaY;}
  currentDirection = direction;
}
CharLav
  • 5
  • 2
  • https://stackoverflow.com/questions/55660668/how-to-stop-sprite-on-collision-keep-it-from-walking-on-walls part2 – CharLav Apr 12 '19 at 23:38

1 Answers1

0

The only thing you are missing is to save the coordinates of your rectangles somewhere. A good place for this would be an array. I see that you have created a function to draw all the rectangles under the image but as you can read here that canvas will not remember where the rectangles are.

So What you can do is to create a new array (lets call it wallsArr) and inside your drawWalls function you can just push your coordinates to that array so after all your drawWalls function will look something like this:

function drawWalls(){
  wallsArr.push({ name: "wall1", x: 105.3, y: -1,    width: 14.1, height: 73.5});
  wallsArr.push({ name: "wall2", x: 366.5, y: -1,    width: 14.1, height: 73.5});
  wallsArr.push({ name: "wall3", x: 367,   y: 173.2, width: 120,  height: 14.1});
  wallsArr.push({ name: "wall4", x: -1,    y: 173.2, width: 120,  height: 14.1});
  wallsArr.push({ name: "wall5", x: 105.3, y: 267.5, width: 14.1, height: 73.5})
  wallsArr.push({ name: "wall6", x: 366.5, y: 267.5, width: 14.1, height: 73.5});
}

you might want to rename the function to something else since it is not actually drawing anything and don't forget to call the function once like so: drawWalls()

To simulate a collision you might want to do a collision function like this one:

function collidingWith(object){
  console.log("you are colliding with:", object.name);
}

And then to detect the collition you would need to loop through the walls (or all the object you want to be able to collide with) on each move. So for example inside the moveCharacter function you could do:

wallsArr.forEach(wall=>{
  if( positionX + deltaX + SCALED_WIDTH > wall.x
    && positionX + deltaX < wall.x+wall.width
    && positionY + deltaY + SCALED_HEIGHT > wall.y
    && positionY + deltaY < wall.y+wall.height
  ){
    collidingWith(wall);
  }
})

Then you should be able to see what wall your character is colliding with at any time. Of course you can do this much more general if you want to be able to collide with the other objects there but hopefully you get the idea and can continue from here.

Good luck with the rest!

Community
  • 1
  • 1
ellertsmari
  • 131
  • 5
  • 1
    Thank you! I'll try this out. I'll let you know how it turns out. I figured that I could do something similar to what was done in The Legend Zelda Ocarina of Time's Castle town. Where there are shapes beneath the image. – CharLav Apr 11 '19 at 14:53
  • 1
    Hey, I got the walls to sense if they have collided! Just to get the character to stop from walking over it is another thing. I went ahead and made an array. and made a function. This is a good step in the right direction. it should be updated in the link. – CharLav Apr 12 '19 at 17:41