lifelong learner — urip iku urup, currently working on accenture.

canvas 2d – mendeteksi object bertabrakan (collision)

0
Degananda.com -

Collision dalam sebuah game adalah hal dasar yang sangat penting dikarenakan banyak genre game yang membutuhkan mekanisme collision ini.

Pada canvas kita dapat memberikan object berupa lingkaran, persegi, tulisan , gambar(png/jpg) dan lain sebagainnya.  Salah satu hal mendasar dari suatu game adalah tabrakan atau collision antar object. Misalkan kita memiliki dua buah object dalam satu canvas. Object tersebut dapat bergerak dengan cara menekan keypad arrow (up/down/left/right) pada keyboard. Ketika satu object bertabrakan dengan object lainnya akan mentrigger suatu event tertentu. Event ini biasannya berupa penambahan poin ataupun object berpindah ke posisi lainnya.

Collision pada canvas

Logika yang digunakan untuk mendeteksi apakah ada object yang bertabrakan adalah dengan melihat posisi dari object tersebut. Setiap object yang berada pada canvas memiliki posisi x dan y. Maka ketika terdapat dua object kita dapat membandingkan posisi x dan y object – object tersebut. Misalkan object A berada di x=10px dan y=10px , object B berada di x=20px dan y=20px. Kemudian kita akan baut mekanisme untuk menggerakan object A yang dapat berpindah sebanyak 10px.

Ketika object A memiliki posisi x=20px dan y=20px maka secara otomatis posisinnya akan sama dengan object B. inilah yang dapat kita sebut sebagai collision. Hal yang harus diperhatikan adalah pergeseran dari object A harus sesuai dengan posisi object B. Jika pergeseran tidak sama dengan 10px (misal 5px) maka posisi object A dan object B tidak akan pernah sama artinnya tidak ada terjadi collision.

Advanced

Itulah logika sederhananya, namun ada versi yang lebih advanced. Seharusnya meski posisi tidak sama tetapi object A bersentuhan dengan object B akan terjadi collision. Namun hal ini tidak sederhana karena harus membandingkan lebar object dan bukan menjadi pokok pembahasan dari ulasan ini.  Kita hanya akan mendeteksi dua object bertabrakan secara sederhana yakni dengan membandingkan posisinya. Implementasinnya seperti game snake yang mengejar mangsannya (food).

Demo online

silahkan akses pada jsfiddle dibawah ini untuk melihat demo secara online

https://jsfiddle.net/7zd0hhwk/

Pre requisites

Sebelum melakukan coding untuk mendeteksi tabrakan dari dua object sangat disarankan untuk mengetahui bagaimana cara membuat canvas , membuat object pada canvas dan yang terpenting mengetahui cara bagaimana menggerakan object dalam canvas. Jika anda belum mengetahui ketiga hal tersebut silahkan membaca ulasan-ulasan sebelum ini.

Implementasi

1. Buat canvas.

kita akan membuat canvas dengan ukuran 900(width) dan 450(height). Canvas akan dibuat dengan menggunakan javascript. Kemudian buat variabel yang menyimpan context yang(context) akan digunakan untuk membuat object pada canvas. Berikut adalah kode untuk membuat canvas.

// membuat canvas
var canvas = document.createElement('canvas');
canvas.width = 900;
canvas.height = 450;
canvas.className = 'myCanvas';
document.body.appendChild(canvas);

var contex = canvas.getContext("2d");

2. Buat variabel menyimpan posisi

karena kita memiliki dua buah object yaitu object A dan object B(nantinnya akan disebut dengan nama object Food) maka akan terdapat dua buah variabel yang akan menyimpan posisi awal masing-masing object tersebut. Posisi harus disimpan di variabel karena untuk menggerakan suatu object kita membutuhkan posisi sebelum bergerak dan posisi setelah bergerak

var pos = {
    x : 30,
    y : 30
}

var posFood = {
    x : 150,
    y : 150
}

3. Membuat fungsi membuat object

kita akan dipisahkan fungsi membuat object A(object yang bergerak) dan object food(yang akan kita “makan” atau tabrak).  Kedua fungsi tersebut tidak dapat perintah untuk menghapus canvas karena proses penghapusan canvas akan dilakukan pada event listener. Canvas akan dihapus jika sudah memenuhi kondisi-kondisi tertentu.

function drawFood(){
    contex.beginPath();
    contex.arc(posFood.x,posFood.y,30,0,7);
    contex.stroke();
    contex.fillStyle = 'red';
    contex.fill();
    contex.closePath();
}

function drawCircle(){
    contex.beginPath();
    contex.arc(pos.x,pos.y,30,0,7);
    contex.stroke();
    contex.fillStyle = 'green';
    contex.fill();
    contex.closePath();
}

// membuat object pertama kali
drawFood();
drawCircle();

4. Membuat fungsi render

ini adalah fungsi yang mengakomodasi fungsi membuat object A dan food beserta logika collisionnya. Object food yang tertabrak tidak akan hilang melainkan akan berganti posisi. Setiap fungsi render dieksekusi canvas akan dihapus (seluruhnya). Disinilah kita akan menghandle proses collision atau tabrakan tersebut. Ketika posisi object A dan object food sama maka kita akan membuat / menggambar object A dan kemudian merubah posisi object food secara random (dengan memanfaatkan math.random).

posisi random ini sangat krusial pastikan inline dengan pergerakan dari object. Jika posisi tidak inline maka tabrakan tidak akan terjadi karena posisi object A dan object food tidak akan pernah sama.

Jika posisi object A dan object food tidak sama maka kita tidak akan merubah posisi dari object food karena benturan belum terjadi. Berikut ini adalah potongan kodenya

function doRender(){
    if(pos.x == posFood.x && pos.y == posFood.y){
    // clear canvas
        contex.clearRect(0,0,canvas.width,canvas.height);
        drawCircle();
        posFood.x = 90+(Math.floor(Math.random() * 5)+1)*60;
        posFood.y = 90+(Math.floor(Math.random() * 5)+1)*60;
    } else {
        contex.clearRect(0,0,canvas.width,canvas.height);
        drawCircle();
    }
    drawFood();
}

5. Event listener

yakni kode yang akan mengakomodasi user input berupa keypress pada keypad arrow left/up/right/bottom. Pergeseran akan bertambah sebanyak 60px. Sesuaikan nilai pergerseran ini agar object dapat inline satu dengan lainnya. Jika object tidak inline maka collision tidak akan terjadi. Berikut adalah potongan kode untuk event listener dari keypress.

addEventListener("keydown", function(res){

    if(res.key == "ArrowRight"){
        pos.x += 60;
        doRender();
    } else if(res.key == "ArrowLeft"){
        pos.x -= 60;
        doRender();
    } else if(res.key == "ArrowDown"){
        pos.y += 60;
        doRender();
    } else if(res.key == "ArrowUp"){
        pos.y -= 60;
        doRender();
    }
    

});