• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Prosty system wykrywania kolizji dla obiektów 2d

Object Storage Arubacloud
0 głosów
289 wizyt
pytanie zadane 9 lutego 2018 w Nasze projekty przez thryndl Nałogowiec (30,470 p.)
edycja 9 lutego 2018 przez thryndl

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);

});

 

1 odpowiedź

+1 głos
odpowiedź 9 lutego 2018 przez Patrycjerz Mędrzec (192,320 p.)
W kod się nie wgłębiałem, ale samo demo jest bardzo nieresponsywne, a sprawdzanie kolizji mocno pobieżne. Czasami prostokąt przechodzi przez wiele większą od siebie przeszkodę, a czasami blokuje się w dużej odległości od niej.
komentarz 9 lutego 2018 przez thryndl Nałogowiec (30,470 p.)

demo jest bardzo nieresponsywne 

Racja, ale nie przykładałem większej uwagi do responsywności. Wolałem skupić się na samym JS.

Czasami prostokąt przechodzi przez wiele większą od siebie przeszkodę, a czasami blokuje się w dużej odległości od niej.

Właśnie to jest do poprawy. Fajnie by było jakby podrzucił ktoś jakiś pomysł jak to rozwiązać. Generalnie cały warunek opiera się na sprawdzaniu czy główny obiekt nie przekracza krawędzi przeszkody i wywoływany jest razem z eventem kliknięcia klawisza. Dlatego możliwe jest "wejście" w przeszkodę, a następne kliknięcie powoduje już reset, bo warunek zwraca true, czyli nastąpiła kolizja.

Natomiast

czasami blokuje się w dużej odległości od niej.

bug wizualny, przez transition w CSS ;)

Także reasumując. Jakby ktoś miał pomysł na sprawdzanie warunku, niezależnie od kliknięcia, to chętnie posłucham jakiś podpowiedzi ;)

 

Dzięki za komentarz!

komentarz 9 lutego 2018 przez Patrycjerz Mędrzec (192,320 p.)
A sprawdzasz kolizję po przesunięciu czy przed? Wygląda to tak, jakby była sprawdzana przed, a od razu po kliknięciu.
komentarz 9 lutego 2018 przez thryndl Nałogowiec (30,470 p.)
Zmieniłem trochę warunek wykrywania kolizji i dodałem kolejny do sprawdzania zderzenia przed ruchem Teoretycznie jest lepiej, aczkolwiek nie jest idealnie.

Jutro siądę na spokojnie i przebuduje trochę kod.

Podobne pytania

0 głosów
1 odpowiedź 761 wizyt
pytanie zadane 28 grudnia 2016 w C i C++ przez prownnie Początkujący (280 p.)
0 głosów
1 odpowiedź 961 wizyt
pytanie zadane 22 października 2019 w C# przez niezalogowany
0 głosów
1 odpowiedź 456 wizyt
pytanie zadane 19 października 2018 w Java przez DuduśToJa Początkujący (290 p.)

92,596 zapytań

141,445 odpowiedzi

319,717 komentarzy

61,980 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...