Search code examples
javascriptcollision-detectiongame-development

Javascript function returns undefined when I try and detect collision detection


I am trying to detect if a rectangle collides with a circle but whatever I try it returns undefinded.

Here is the code I am using. The relevant code starts around the RectCircleColliding class.

const canvas = document.getElementById('canvas1');
const c = canvas.getContext('2d');
let playing = true
let mainMenu = false
let cutscenes = 0
let room = "main"
const gravity = 0.5
var onGround = false;
let scrolled = {
  y: 0,
  x: 0
}
let jumpTime = 0
const wjumpTime = 10
let collision = 0;

canvas.width = window.innerWidth
canvas.height = window.innerHeight

function startGame() {
  let element = document.getElementById("start")
  element.setAttribute("hidden", "hidden");
  mainMenu = false
  playing = true
  console.log('start')
  // if (cutscenes == 0) {
  //     player.position.x = 0
  //     player.position.y = 1000
  //     player.velocity.y = 0
  // }
}

class Player {
  constructor() {
    this.position = {
      x: 100,
      y: 888
    }
    this.velocity = {
      x: 0,
      y: 0
    }
    this.width = 64
    this.height = 128
  }

  draw() {
    c.fillStyle = "red"
    c.fillRect(this.position.x, this.position.y, this.width, this.height)
  }

  update() {
    this.draw()
    this.position.y += this.velocity.y
    this.position.x += this.velocity.x

    if (this.position.y + player.height + player.velocity.y <= canvas.height)
      this.velocity.y += gravity
  }
}

class Platform {
  constructor({
    x,
    y,
    w,
    h
  }) {
    this.position = {
      x,
      y
    }

    this.width = w
    this.height = h
  }

  draw(color) {
    c.fillStyle = color
    c.fillRect(this.position.x, this.position.y, this.width, this.height)

  }
}

class Enemy {
  constructor({
    x,
    y,
    w,
    h,
    n
  }) {
    this.position = {
        x,
        y
      },
      this.velocity = {
        x: 0,
        y: 0
      }

    this.width = w
    this.height = h

    this.number = n
  }


  draw(color) {
    c.fillStyle = color
    c.fillRect(this.position.x, this.position.y, this.width, this.height)

  }
  update() {
    this.position.y += this.velocity.y
    this.position.x += this.velocity.x

    if (this.position.y + this.height + this.velocity.y <= canvas.height)
      this.velocity.y += gravity
  }
}
class Circles {
  constructor({
    x,
    y,
    n,
    r
  }) {
    this.position = {
        x,
        y
      },
      this.velocity = {
        x: 0,
        y: 0
      }

    this.radius = r
    this.number = n
  }


  draw(color) {
    c.beginPath();
    c.globalAlpha = 0.2
    c.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI, false);
    c.fillStyle = color;
    c.fill();
    c.globalAlpha = 1
  }
}

const player = new Player()
const platforms = [
  //  new Platform({ x: 200, y: 800, w: 200, h: 20 }), new Platform({ x: 500, y: 700, w: 200, h: 20 }),
]
//     //new Platform({x: 0, y:1016, w:1900, h:150 })
//     , new Platform({ x: 500, y: 400, w: 600, h: 20 }), 
//     //ground
//      ]
let groundPos = 0
const ground = [new Platform({
  x: 0,
  y: 1016,
  w: 64 * 43,
  h: 128
})]

let tree = [
  new Platform({
    x: 1024,
    y: 1016,
    w: 512,
    h: -1280
  })

]

let mutatedgors = [
  // Mutated Gors
  new Enemy({
    x: 888,
    y: 800,
    w: 64,
    h: 64,
    n: 1
  })
]
let circles = [
  new Circles({
    x: 888,
    y: 800,
    r: 750,
    n: 1
  })
]

const keys = {
  right: {
    pressed: false
  },
  left: {
    pressed: false
  },
  up: {
    pressed: false
  }
}

function animate() {
  tree.forEach(tree => {
    if (player.position.x > tree.position.x + 100 && player.position.x < tree.position.x + tree.width - 100) {

      addEventListener('keydown', ({
        keyCode
      }) => {
        // console.log(keyCode)
        switch (keyCode) {
          case 70:
            player.position.y = -2000
            room = "tree1"
            break
        }
      })
    }
  })
  circles.forEach(circles => {
    mutatedgors.forEach(mutatedgors => {
      if (circles.n == mutatedgors.n) {
        circles.position.x = mutatedgors.position.x
        circles.position.y = mutatedgors.position.y
      }
    })
  })



  function RectCircleColliding() {
    circles.forEach(circles => {
      mutatedgors.forEach(mutatedgors => {
        var circle = {
          x: circles.position.x,
          y: circles.position.y,
          r: circles.radius
        };
        var rect = {
          x: player.position.x,
          y: player.position.y,
          w: player.width,
          h: player.height
        };

        var distX = Math.abs(circle.x - rect.x - rect.w / 2);
        var distY = Math.abs(circle.y - rect.y - rect.h / 2);

        if (distX > (rect.w / 2 + circle.r)) {
          return false
        }
        if (distY > (rect.h / 2 + circle.r)) {
          return false
        }

        if (distX <= (rect.w / 2)) {
          return true
        }
        if (distY <= (rect.h / 2)) {
          return true
        }

        var dx = distX - rect.w / 2;
        var dy = distY - rect.h / 2;
        return (dx * dx + dy * dy <= (circle.r * circle.r));

      })
    })
  }
  console.log(RectCircleColliding())

  // console.log(scrolled.x)
  // console.log(player.position.x)
  window.onscroll = function() {
    window.scrollTo(1920, 1080);
  }

  //console.log(keys.up.pressed)
  //console.log(onGround)
  //console.log(jumpTime)
  if (jumpTime >= wjumpTime) {
    keys.up.pressed = false
  }
  if (player.velocity.y > 0) {
    jumpTime = wjumpTime
  }
  requestAnimationFrame(animate)
  c.clearRect(0, 0, canvas.width, canvas.height)
  if (playing == true) {
    platforms.forEach(platform => {
      platform.draw("blue")
    })
    ground.forEach(ground => {
      ground.draw("green")
    })
    tree.forEach(tree => {
      tree.draw("#994a00")
    })
    mutatedgors.forEach(mutatedgors => {
      mutatedgors.draw("blue")
    })
    circles.forEach(circles => {
      circles.draw("red")
    })
    player.update()
    mutatedgors.forEach(mutatedgors => {
      mutatedgors.update()
    })

  }

  if ((keys.right.pressed && player.position.x < 1100)) {
    player.velocity.x = 5
  } else if (((keys.left.pressed && player.position.x > 810)) ||
    (keys.left.pressed && scrolled.x == 0 && player.position.x != -10)) {
    //    console.log(player.position.x)
    player.velocity.x = -5
  } else {
    player.velocity.x = 0

    if (keys.right.pressed && room == "main") {
      scrolled.x -= 5
      platforms.forEach(platform => {
        platform.position.x -= 5
      })
      ground.forEach(ground => {
        ground.position.x -= 5
      })
      tree.forEach(tree => {
        tree.position.x -= 5
      })
      mutatedgors.forEach(mutatedgors => {
        mutatedgors.position.x -= 5
      })
    } else if (keys.left.pressed && room == "main") {
      if (scrolled.x <= 300 && player.position.x != -10) {

        scrolled.x += 5

        platforms.forEach(platform => {
          platform.position.x += 5
        })
        ground.forEach(ground => {
          ground.position.x += 5
        })
        tree.forEach(tree => {
          tree.position.x += 5
        })
        mutatedgors.forEach(mutatedgors => {
          mutatedgors.position.x += 5
        })
      }
    }
  }
  if (keys.up.pressed) {
    onGround = false
    player.velocity.y -= 2
    jumpTime++
  }
  while (player.position.y < 463.5) {
    jumpTime = wjumpTime
    player.position.y += 1
    scrolled.y += 1
    platforms.forEach(platform => {
      platform.position.y += 1
    })
    ground.forEach(ground => {
      ground.position.y += 1
    })

    tree.forEach(tree => {
      tree.position.y += 1
    })
    mutatedgors.forEach(mutatedgors => {
      mutatedgors.position.y += 1
    })

  }
  if (scrolled.y > 0) {
    while (player.position.y > 463.5 && scrolled.y != 0) {
      jumpTime = wjumpTime
      platforms.forEach(platform => {
        platform.position.y -= 1
      })
      ground.forEach(ground => {
        ground.position.y -= 1
      })
      tree.forEach(tree => {
        tree.position.y -= 1
      })
      mutatedgors.forEach(mutatedgors => {
        mutatedgors.position.y -= 1
      })
      player.position.y -= 1
      scrolled.y -= 1
    }

  }
  if (player.position.y > 850 && scrolled.y <= 0) {
    while (player.position.y > 850) {
      jumpTime = wjumpTime
      platforms.forEach(platform => {
        platform.position.y -= 1
      })
      ground.forEach(ground => {
        ground.position.y -= 1
      })
      tree.forEach(tree => {
        tree.position.y -= 1
      })
      mutatedgors.forEach(mutatedgors => {
        mutatedgors.position.y -= 1
      })
      player.position.y -= 1
      scrolled.y -= 1
    }
  }
  platforms.forEach(platform => {
    if (player.position.y + player.height <= platform.position.y + 1 &&
      player.position.y + player.height + player.velocity.y >= platform.position.y + 1 &&
      player.position.x + player.width >= platform.position.x &&
      player.position.x <= platform.position.x + platform.width) {
      player.velocity.y = 0
      onGround = true
      jumpTime = 0
      collision = 0
    } else
    if (player.position.y <= platform.position.y + platform.height + 1 &&
      player.position.y + player.velocity.y >= platform.position.y + platform.height + 1 &&
      player.position.x + player.width >= platform.position.x &&
      player.position.x <= platform.position.x + platform.width
    ) {
      player.velocity.y = 0
      collision = 0

      jumpTime = 0
    }
  })

  ground.forEach(ground => {

    // console.log(collision)
    if (player.position.y + player.height <= ground.position.y + 1 &&
      player.position.y + player.height + player.velocity.y >= ground.position.y + 1 &&
      player.position.x + player.width >= ground.position.x &&
      player.position.x <= ground.position.x + ground.width) {
      player.velocity.y = 0
      onGround = true
      jumpTime = 0
    } else if (player.position.y >= ground.position.y + ground.height - 64 * (1 / 16) &&
      player.position.y + player.velocity.y <= ground.position.y + ground.height - 64 * (1 / 16) &&
      player.position.x + player.width >= ground.position.x &&
      player.position.x <= ground.position.x + ground.width) {
      console.log(player.position.y)
      console.log(ground.position.y + ground.height)
      player.velocity.y = 0
      jumpTime = wjumpTime
    } else if (player.position.x <= ground.width + ground.position.x + 1 &&
      player.position.x + player.width >= ground.position.x - 1 &&
      player.position.y + player.height >= ground.position.y + 1 &&
      player.position.y <= ground.position.y + ground.width - 1) {
      player.velocity.x = 0
    }
  })
  platforms.forEach(platform => {
    mutatedgors.forEach(mutatedgors => {
      if (mutatedgors.position.y + mutatedgors.height <= platform.position.y + 1 &&
        mutatedgors.position.y + mutatedgors.height + mutatedgors.velocity.y >= platform.position.y + 1 &&
        mutatedgors.position.x + mutatedgors.width >= platform.position.x &&
        mutatedgors.position.x <= platform.position.x + platform.width) {

        mutatedgors.velocity.y = 0

      } else
      if (mutatedgors.position.y <= platform.position.y + platform.height + 1 &&
        mutatedgors.position.y + mutatedgors.velocity.y >= platform.position.y + platform.height + 1 &&
        mutatedgors.position.x + mutatedgors.width >= platform.position.x &&
        mutatedgors.position.x <= platform.position.x + platform.width
      ) {

        mutatedgors.velocity.y = 0

      }
    })
  })

  ground.forEach(ground => {
    //console.log(collision)
    mutatedgors.forEach(mutatedgors => {
      if (mutatedgors.position.y + mutatedgors.height <= ground.position.y + 1 &&
        mutatedgors.position.y + mutatedgors.height + mutatedgors.velocity.y >= ground.position.y + 1 &&
        mutatedgors.position.x + mutatedgors.width >= ground.position.x &&
        mutatedgors.position.x <= ground.position.x + ground.width) {

        mutatedgors.velocity.y = 0

      } else if (mutatedgors.position.y >= ground.position.y + ground.height - 64 * (1 / 16) &&
        mutatedgors.position.y + mutatedgors.velocity.y <= ground.position.y + ground.height - 64 * (1 / 16) &&
        mutatedgors.position.x + mutatedgors.width >= ground.position.x &&
        mutatedgors.position.x <= ground.position.x + ground.width) {

        mutatedgors.velocity.y = 0

      } else if (mutatedgors.position.x <= ground.width + ground.position.x + 1 &&
        mutatedgors.position.x + mutatedgors.width >= ground.position.x - 1 &&
        mutatedgors.position.y + mutatedgors.height >= ground.position.y + 1 &&
        mutatedgors.position.y <= ground.position.y + ground.width - 1) {

        mutatedgors.velocity.x = 0

      }
    })
  })

}

animate()

addEventListener('keydown', ({
  keyCode
}) => {

  switch (keyCode) {
    case 65:
      console.log('left')
      keys.left.pressed = true
      break
    case 83:
      console.log('down')
      break
    case 68:
      console.log('right')
      keys.right.pressed = true
      break
    case 32:
      if (onGround == true) {
        keys.up.pressed = true
      } else keys.up.pressed = false
      break
    case 87:
      console.log('jump')
      if (onGround == true) {
        keys.up.pressed = true
      } else keys.up.pressed = false
      break
  }
})

addEventListener('keyup', ({
  keyCode
}) => {

  switch (keyCode) {
    case 65:
      console.log('left')
      keys.left.pressed = false
      break
    case 83:
      console.log('down')
      break
    case 68:
      console.log('right')
      keys.right.pressed = false
      break
    case 32:
      console.log('jump')
      keys.up.pressed = false
      break
    case 87:
      console.log('jump')
      keys.up.pressed = false
      break
  }
})
/* body {
    background: black;
    }
#canvas1 {
    position: absolute;
    border: 3px solid white;
    width: 800px;
    height: 700px;
    transform: translate(-50%, -50%);
    top: 50%;
    left: 50%;
} */

body {
  margin: 0px;
  -ms-overflow-style: none;
  /* for Internet Explorer, Edge */
  scrollbar-width: none;
  /* for Firefox */
  overflow-y: scroll;
}

body::-webkit-scrollbar {
  display: none;
  /* for Chrome, Safari, and Opera */
}

#start {
  position: absolute;
  left: 810px;
  top: 350px;
  font-size: 50px;
  border: 5px solid black;
  color: black;
  text-align: center;
  background-color: white;
}

footer {
  vertical-align: top
}

div {
  margin: 0px;
}

canvas {
  margin: 0px;
}
<canvas id="canvas1"></canvas>
<div id="start-screen" class="screen" style="display:block">
  <button id="start" onclick="startGame()">Start Game</button>
</div>


Solution

  • You are not returning something from the RectCircleColliding function. If you need to return smth then forEach is the wrong looping mechanism to use. You can use a for ... of loop instead:

    function RectCircleColliding() {
     for (let circlesParam of circles) {
        var circle = {
            x: circlesParam.position.x,
            y: circlesParam.position.y,
            r: circlesParam.radius,
        };
        var rect = {
            x: player.position.x,
            y: player.position.y,
            w: player.width,
            h: player.height,
        };
    
        var distX = Math.abs(circle.x - rect.x - rect.w / 2);
        var distY = Math.abs(circle.y - rect.y - rect.h / 2);
    
        if (distX > rect.w / 2 + circle.r) {
            return false;
        }
        if (distY > rect.h / 2 + circle.r) {
            return false;
        }
    
        if (distX <= rect.w / 2) {
            return true;
        }
        if (distY <= rect.h / 2) {
            return true;
        }
    
        var dx = distX - rect.w / 2;
        var dy = distY - rect.h / 2;
        return dx * dx + dy * dy <= circle.r * circle.r;
     }
    }
        console.log(RectCircleColliding());
    

    PS: If you are going to loop over the elements of an array it's better to name the individual element differently, for example:

    circles.forEach((circle) => ...)
    

    MDN docs of forEach for more info: https://mzl.la/3RShywF