Cześć!
Wrzucam prosty system wykrywania kolizji dla obiektów dwuwymiarowych (w przykładzie dla prostokątów) w czystym JS.
Sama funkcja detekcji oraz sprawdzania może komuś się przyda, bądź kogoś zainspiruje.
Sam chętnie posłucham o optymalizacji.
Live demo na codepen.io
Kod:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Collision detection</title>
<style>
.collision-alert {
position: relative;
top: 25px;
left: 50px;
height: 75px;
width: 450px;
background-color: rgb(255, 0, 0);
font-size: 18px;
font-weight: bold;
font-family: Verdana, Geneva, Tahoma, sans-serif;
color: white;
text-align: center;
text-transform: uppercase;
line-height: 75px;
display: none;
}
.rect {
position: absolute;
}
</style>
</head>
<body>
<div class="collision-alert"></div>
<script src="engine.js"></script>
</body>
</html>
// main rectangle object
const character = {
posX: 150,
posY: 150,
width: 50,
height: 50,
color: "blue",
};
// object containing obstacles
const obstacles = {
obst1 : {
posX: 300, // expressed in pixels
posY: 300,
width: 100,
height: 100,
color: "green" // you may use name of color
},
obst2 : {
posX: 80,
posY: 500,
width: 150,
height: 150,
color: "#c1c1c1" // hex of color
},
obst3 : {
posX: 580,
posY: 330,
width: 70,
height: 70,
color: "rgb(144,200,83)" // or rgb of color
},
obst4 : {
posX: 540,
posY: 70,
width: 130,
height: 130,
color: "orange"
},
}
const speed = 20; // set here speed for "Hero", its expressed in pixels
// @@ Attention @@ //
// if you create new object to obstacles, remember to add it to array below !!
// create array list with obstacles
const obstaclesArray = [obstacles.obst1, obstacles.obst2, obstacles.obst3, obstacles.obst4] // <<--- add new obstacles here
// function for creating objects, e.g obstacles
const createRect = function (posX,posY,height,width,color) {
var rect = document.createElement('div');
rect.className = "rect";
rect.style.left = posX + 'px';
rect.style.top = posY + 'px';
rect.style.height = height + 'px';
rect.style.width = width + 'px';
rect.style.backgroundColor = color;
document.body.appendChild(rect);
}
// variables contains edges position for character rectangle
let leftEdge, rightEdge, topEdge, bottomEdge;
// using keyboard up,down,left,righ keys to move
const move = function (el, key) {
var axisX = mainRect.style.left.length;
axisY = mainRect.style.top.length;
axisX = Number(mainRect.style.left.slice(0,axisX-2)); // remove "px" from left style position and convert it to Number
axisY = Number(mainRect.style.top.slice(0,axisY-2)); // remove "px" from top style position and convert it to Number
leftEdge = axisX;
rightEdge = Number(el.style.width.slice(0,el.style.width.length-2));
rightEdge = axisX + rightEdge,
topEdge = axisY;
bottomEdge = Number(el.style.height.slice(0,el.style.height.length-2));
bottomEdge = axisY + bottomEdge;
switch(key) {
// key left
case 37:
if(collision(obstaclesArray.length - 1)) {
reset();
} else {
el.style.left = axisX - speed + "px";
}
break;
// key up
case 38:
if(collision(obstaclesArray.length - 1)) {
reset();
} else {
el.style.top = axisY - speed + "px";
}
break;
// key right
case 39:
if(collision(obstaclesArray.length - 1)) {
reset();
} else {
el.style.left = axisX + speed + "px";
}
break;
// key down
case 40:
if(collision(obstaclesArray.length - 1)) {
reset();
} else {
el.style.top = axisY + speed + "px";
}
break;
}
}
// main collision function return true if collision with other obstacles
const collisionStatus = function (obj) { // param == object to check collision between it and main rectangle
if(rightEdge >= obj.posX && bottomEdge >= obj.posY && leftEdge <= obj.posX + obj.width && topEdge <= obj.posY + obj.height) {
return true;
} else {
return false; // false if not
}
}
// recursion by all obstacles, displays "collision-alert" and reset characterect to start position
const collision = function(value) { // value == length of array which has obstacles
if(collisionStatus(obstaclesArray[value])) {
// what to do when collision
// write in this block
document.querySelector(".collision-alert").textContent = "! COLLISION !"; // text for info in info-block
document.querySelector(".collision-alert").style.display = "block";
return true;
//
} else {
if(value >= 1) {
document.querySelector(".collision-alert").style.display = "none"; // you may delete this line on deploy
return collision(value - 1);
}
} return false;
}
// reset function, set characterect to starting positions
const reset = function () {
mainRect.style.left = character.posX + "px";
mainRect.style.top = character.posY + "px";
return true;
}
// create ** characterect ** with index number = 0
createRect(character.posX, character.posY, character.height, character.width, character.color);
const mainRect = document.querySelectorAll(".rect")[0]; // assigning characterect to ** mainRect ** variable
// creating others obstacles to deal with it :P
createRect(obstacles.obst1.posX, obstacles.obst1.posY, obstacles.obst1.height, obstacles.obst1.width, obstacles.obst1.color);
createRect(obstacles.obst2.posX, obstacles.obst2.posY, obstacles.obst2.height, obstacles.obst2.width, obstacles.obst2.color);
createRect(obstacles.obst3.posX, obstacles.obst3.posY, obstacles.obst3.height, obstacles.obst3.width, obstacles.obst3.color);
createRect(obstacles.obst4.posX, obstacles.obst4.posY, obstacles.obst4.height, obstacles.obst4.width, obstacles.obst4.color);
// main eventListener, working with document and "keydown"
document.addEventListener("keydown", function(e) {
move(mainRect, e.keyCode);
});