I am new to coding, and especially new to trying to make a game. This is for a class project. Using JavaScript, HTML, and CSS, I am trying to make a game in which, with limited visibility, the user must search for the exit (a white rectangle on the edges of the screen) while avoiding ghosts and interior walls (for the sake of ease of use, the canvas is completely visible so you can see what I am referring to). I am having trouble creating collision detection between the randomly generated interior walls and the player so that the player is unable to pass through these walls.
To be honest I am quite new to all of this, so I do not have a lot of trial and error experience since it is built off of guesses. I was trying to use if statements to detect collision before moving and repeat it for each side (see javascript lines of code 174-199). So essentially using an if statement for each side of the array shape, and if the circle is moving in the direction of collision, they won’t be able to move. This hasn’t worked though obviously, and I am feeling quite lost as to the correct step to accomplish the desired effect. My code is posted here:
var canvas;
var ctx;
var w = window.innerWidth;
var h = window.innerHeight;
var startScreen = document.querySelector("#startScreen");
var allGhosts = []
var allWalls = []
var oneDegree = 2 * Math.PI / 360;
var generate = true;
var win = false;
var lose = false;
var o1 = {
x: w / 2,
y: h / 2,
w: w * 2,
h: h * 2,
r: w / 6,
c: 200,
a: 1,
distance: 4,
angle: rand(360),
changeX: randn(5),
changeY: randn(5),
}
var o2 = {
x: rand(w),
y: rand(h),
w: rand(50) + 10,
h: rand(50) + 10,
r: w / 6,
c: 200,
a: 0.75,
distance: rand(10),
angle: rand(360),
}
var o3 = {
x: w / 2,
y: h / 2,
r: 10,
a: 1,
speed: 7,
}
var o4 = {
x: w / 2,
y: h / 2,
w: w * 2,
h: h * 2,
r: w / 1.90,
c: 200,
a: 1,
}
var exitLoc = {
x: parseInt(Math.random() * 2) ? 0 : 1500,
y: rand(680),
w: 10,
h: 50,
}
if (win != true) {
winScreen.style.display = 'none';
}
if (lose != true) {
loseScreen.style.display = 'none';
}
window.addEventListener("keydown", ev => {
if (ev.keyCode === 32 && generate === true) {
startScreen.style.display = 'none';
generate = false;
createGhosts(30, allGhosts);
createGhosts(50, allWalls);
setUpCanvas();
animationLoop();
document.onkeydown = move;
function animationLoop() {
clear();
extWalls();
collisionStop(o3);
collisionStop(o4);
exit(exitLoc);
for (var i = 0; i < allGhosts.length; i++) {
ghosts(allGhosts[i]);
bounce(allGhosts[i]);
forward(allGhosts[i]);
updateData(o1);
}
for (var i = 0; i < allWalls.length; i++) {
walls(allWalls[i]);
}
// circle(o4);
player(o3);
collisionWin(exitLoc, o3);
collisionLose(o3, allGhosts);
if (lose != true && win != true) {
requestAnimationFrame(animationLoop);
}
}
}
})
function collisionWin(obj1, obj2) {
var differencex = Math.abs(obj1.x - obj2.x);
var differencey = Math.abs(obj1.y - obj2.y);
var hdif = Math.sqrt((differencex * differencex) + (differencey * differencey));
if (hdif < obj1.w + obj2.r) {
clear();
rect();
win = true;
}
if (win === true) {
winScreen.style.display = 'block';
loseScreen.style.display = 'none'
}
}
function rect() {
x = 0;
y = 0;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x, y + h);
ctx.closePath();
ctx.fillStyle = "black";
ctx.fill();
}
function collisionLose(obj, array) {
for (var i = 0; i < array.length; i++) {
if (obj != array[i]) {
collisionGhost(obj, array[i]);
}
}
}
function collisionGhost(obj, array) {
var differencex = Math.abs(obj.x - array.x);
var differencey = Math.abs(obj.y - array.y);
var hd = Math.sqrt((differencex * differencex) + (differencey * differencey));
if (hd < obj.r + array.r) {
clear();
rect();
lose = true;
}
if (lose === true) {
loseScreen.style.display = 'block'
}
}
function collisionStop(o) {
if (o.x > w - 50) {
o.x = w - 50;
}
// right of screen
if (o.x < 15) {
o.x = 15;
}
// left of screen
if (o.y > h - 50) {
o.y = h - 50;
}
// bottom of screen
if (o.y < 15) {
o.y = 15;
}
// top of screen
}
function collisionWall(obj, array) {
for (var i = 0; i < array.length; i++) {
if (obj != array[i]) {
collisionIntWall(obj, array[i]);
}
}
}
function collisionIntWall(obj, array) {
if (obj.x + obj.r > array.x - array.w / 2 && move.keyCode == 37) {
obj.speed = 0
}
// right side of obj1 > left side of array AND
// if(obj.x - obj.r < array.x + array.w/2 && move() == 39){
// obj.speed = 0
// }
// // left side of obj1 < right side of array AND
// if(obj.y + obj.r > array.y - array.h/2 && move() == 40){
// obj.speed = 0
// }
// // bottom of obj1 > top of array AND
// if(obj.y - obj.r < array.y + array.h/2 && move() == 38){
// obj.speed = 0
// }
// top of obj1 < bottom of array
}
function createGhosts(num, array) {
for (var i = 0; i < num; i++) {
array.push({
x: rand(w),
y: rand(h),
w: rand(50) + 10,
h: rand(50) + 10,
r: 10,
c: 0,
a: 1,
distance: rand(1) + 0.5,
angle: rand(360),
})
}
}
function bounce(o) {
if (o.x > w) {
o.x = w - 5;
o.angle += 180 - 2 * o.angle;
}
if (o.x < 0) {
o.x = 5;
o.angle += 180 - 2 * o.angle;
}
if (o.y > h) {
o.y = h - 5;
o.angle += 360 - 2 * o.angle;
}
if (o.y < 0) {
o.y = 5;
o.angle += 360 - 2 * o.angle;
}
}
function updateData(o) {
o.x += o.changeX;
o.y += o.changeY;
}
function forward(o) {
var cx;
var cy;
cx = o.distance * Math.cos(o.angle * oneDegree);
cy = o.distance * Math.sin(o.angle * oneDegree);
o.x += cx;
o.y += cy;
}
function circle(o) {
ctx.beginPath();
ctx.arc(o.x, o.y, o.r, 0, 2 * Math.PI);
ctx.strokeStyle = "black";
ctx.lineWidth = 2000;
ctx.stroke();
}
function player(o) {
ctx.beginPath();
ctx.arc(o.x, o.y, o.r, 0, 2 * Math.PI);
ctx.fillStyle = "white";
ctx.fill();
}
function ghosts(o) {
ctx.beginPath();
ctx.arc(o.x, o.y, o.r, 0, 2 * Math.PI);
ctx.fillStyle = "rgb(189, 9, 9)";
ctx.fill();
}
function walls(o) {
o.x = o.x - o.w / 2;
o.y = o.y - o.h / 2;
ctx.beginPath();
ctx.moveTo(o.x, o.y);
ctx.lineTo(o.x + o.w, o.y);
ctx.lineTo(o.x + o.w, o.y + o.h);
ctx.lineTo(o.x, o.y + o.h);
ctx.closePath();
ctx.fillStyle = "grey";
ctx.fill();
o.x = o.x + o.w / 2;
o.y = o.y + o.h / 2;
}
function exit(o) {
o.x = o.x - o.w / 2;
o.y = o.y - o.h / 2;
ctx.beginPath();
ctx.moveTo(o.x, o.y);
ctx.lineTo(o.x + o.w, o.y);
ctx.lineTo(o.x + o.w, o.y + o.h);
ctx.lineTo(o.x, o.y + o.h);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
o.x = o.x + o.w / 2;
o.y = o.y + o.h / 2;
}
function extWalls() {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, 680);
ctx.lineTo(1500, 680);
ctx.lineTo(1500, 0);
ctx.closePath();
ctx.strokeStyle = "grey";
ctx.lineWidth = 10;
ctx.stroke();
}
function clear() {
ctx.clearRect(0, 0, w, h);
}
function randn(r) {
var result = Math.random() * r - r / 2;
return result;
}
function randi(r) {
var result = Math.floor(Math.random() * r);
return result;
}
function rand(r) {
var result = Math.random() * r;
return result;
}
function setUpCanvas() {
canvas = document.querySelector("#myCanvas");
ctx = canvas.getContext("2d");
canvas.width = 1500;
canvas.height = 680;
}
function move(e) {
if (e.keyCode == 37) {
o3.x -= o3.speed;
o4.x -= o3.speed;
}
if (e.keyCode == 39) {
o3.x += o3.speed;
o4.x += o3.speed;
}
if (e.keyCode == 40) {
o3.y += o3.speed;
o4.y += o3.speed;
}
if (e.keyCode == 38) {
o3.y -= o3.speed;
o4.y -= o3.speed;
}
}
#myCanvas {
background-color: rgb(76, 76, 76);
}
h1 {
color: rgb(189, 9, 9);
text-align: center;
font-family: Creepster, monospace;
}
h6 {
color: rgb(189, 9, 9);
text-align: center;
font-family: Creepster, monospace;
}
p {
color: rgb(189, 9, 9);
text-align: center;
font-family: Creepster, monospace;
}
body {
display: flex;
justify-content: center;
background-color: black;
}
#startBox {
position: fixed;
width: 600px;
height: 600px;
box-shadow: 0 1px 64px rgb(189, 9, 9);
background-color: black;
left: 50%;
transform: translateX(-50%);
}
#startBox h1 {
font-size: 100px;
}
#startBox p {
width: 90%;
margin: auto;
font-size: 25px;
}
#winBox {
position: fixed;
width: 600px;
height: 600px;
box-shadow: 0 1px 64px rgb(189, 9, 9);
background-color: black;
left: 50%;
transform: translateX(-50%);
}
#winBox h1 {
font-size: 85px;
}
#winBox p {
width: 90%;
margin: auto;
font-size: 25px;
}
#loseBox {
position: fixed;
width: 600px;
height: 600px;
box-shadow: 0 1px 64px rgb(189, 9, 9);
background-color: black;
left: 50%;
transform: translateX(-50%);
}
#loseBox h1 {
font-size: 100px;
}
#loseBox p {
width: 90%;
margin: auto;
font-size: 25px;
}
<!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">
<title>ghost house</title>
<link rel="stylesheet" type="text/css" href="test.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Creepster&display=swap" rel="stylesheet">
</head>
<body>
<div id="startScreen">
<div id="startBox">
<h1>ghost house</h1>
<p>The lights went out… <br> Your flashlight can only last so long. <br> Find your way out of the haunted house but beware, ghosts haunt these halls. <br><br> They do not take kindly to visitors... <br><br> use the arrow keys to control the player
and search for a way out. the exit looks like a white rectangle somewhere along the exterior walls of the home. press the spacebar to start</p>
</div>
</div>
<div id="winScreen">
<div id="winBox">
<h1>congratulations</h1>
<p>you found your way out of the ghost house <br> refresh the page and try to escape again <br><br><br><br> if you dare</p>
</div>
</div>
<div id="loseScreen">
<div id="loseBox">
<h1>game over</h1>
<p>looks like there will be another ghost haunting this house <br> refresh the page and try to escape again <br><br><br><br> if you dare</p>
</div>
</div>
<div id="canvasContainer">
<canvas id="myCanvas"></canvas>
</div>
<script src="test.js"></script>
</body>
</html>
The issue code in question starts from lines 174-199. Thank you for taking the time to read through this and help me out! I really appreciate it 🙂