Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Membuat game Beat 'Em Up di Game Maker, Bagian 1: Pergerakan pemain, serangan, dan musuh dasar

Scroll to top
Read Time: 26 min

() translation by (you can also view the original English article)

Pada masa permainan Arcade dan awal-awal masa konsol game, game Beat 'Em Up adalah salah satu genre paling populer. Sebagai gabungan dari platformer dan game fighting, Beat 'Em Up adalah game aksi berbasis combo di mana pemain melawan banyak musuh sambil bergerak di lingkungan yang umumnya horizontal.

Di masa modern ini, game Beat 'Em Up klasik seperti Turtles in time dan X-Men digantikan oleh brawler 3D seperti Shadow of Mordor dan Arkham Knight, evolusi AAA dari game klasik tersebut.

Pad seri artikel ini, kita akan mempelajari bagaimana cara membuat game Beat 'Em Up klasik.

Persiapan

Sebelum memulai, kita perlu membahas tentang ilmu yang dibutuhkan untuk tutorial ini. Game yang akan kita buat dibangun dengan Game Maker Studio Pro, yang bisa didapat gratis dari website YoYo Games.

Kamu juga harus memiliki pemahaman dasar GML, bahasa pemrograman bawaan Game Maker. Sembali saya menjelaskan tentang bagaimana kode bekerja, kita akan membicarakan tentang beberapa konsep programming lanjutan, seperti AI, jadi nantinya akan lebih mudah mengerti jika kamu sudah memiliki dasar yang kuat.

Pastikan juga kamu mendownload file zip Asset bagian 1 yang disediakan di artikel ini, karena file tersebut mencakup gambar dan suara yang kamu perlukan untuk menyelesaikan artikel ini. File tersebut juga berisi proyek Game Maker yang sudah selesai untuk bagian tutorial ini, jadi kamu bisa menggunakannya jika menemui masalah.

Sekarang buka Game Maker, dan mari kita mulai.

Mengimpor Gambar

Pada artikel ini kita akan membuat objek pemain dan sebuah objek musuh yang bisa kita kalahkan, dan kita akan berikan kemampuan untuk pemain bergerak dan menyerang. Sebelum kita bisa melakukan semua itu, kita perlu menambahkan beberapa gambar yang bisa kita gunakan untuk pemain dan musuh. Kita mulai dengan animasi Player Idle.

  1. Klik kanan folder Sprites dan pilih Create Sprite.
  2. Beri nama sprite SPR_PlayerIdle.
  3. Gunakank opsi Load Sprite, dan navigasi ke file gambar yang kamu unduh untuk tutorial ini.
  4. Pilih Assets > Images > Player > PlayerIdle.png. Ini adalah satu-satunya frame yang kita butuhkan untuk animasi ini.

Sekarang karena gambar sudah diimpor, kita perlu mengatur titik pusat. Jika kamu lihat semua animasi pemain, kamu akan lihat tidak semua gambar memiliki ukuran yang sama. Ini artinya posisi karakter tidak sama di masing-masing gambar. Jika kita gunakan gambar yang ada apa adanya, bisa menyebabkan karakter berubah posisi saat beranimasi, dan mengacaukan bounding box kita. Pada gambar di bawah, kamu bisa lihat bahwa frame pertama dari tiga animasi pemain, dan bagaimana perbandingan posisi mereka.

The first frame from three of the animations overlaid on top of each other for comparisonThe first frame from three of the animations overlaid on top of each other for comparisonThe first frame from three of the animations overlaid on top of each other for comparison

Jika kita melakukan transisi antar animasi tanpa mengatur titik pusat, posisi pemain akan berubah dari satu animasi ke animasi lainnya. Untuk memecahkan ini, kita bisa mengatur titik pusat secara manual agar kurang lebih berada di posisi yang sama di setiap animasi, dan pemain tidak akan bergeser.

Saat melakukan ini, akan sangat membantu jika kita punya titik referensi pada karakter yang bisa kita gunakan sebagai panduan sehingga kita bisa tahu jika titik pusatnya perlu diatur kembali. Untuk semua gambar karakter, saya akan menggunakan titik besar di dada sebagai titik patokan. Saya akan posisikan titik pusat di bawah gambar dan di sebelah kiri titik tersebut. Saya meningkatkan saturasi gambar di bawah agar kamu bisa malihat titik referensi saya.

An exampleof how the origin should be setup for the images incldued with the tutorialAn exampleof how the origin should be setup for the images incldued with the tutorialAn exampleof how the origin should be setup for the images incldued with the tutorial

Untuk animasi Idle, titik pusatnya akan berada di x = 40, y = 117.

Sekarang kita perlu mengimpor sisa sprite yang akan kita gun akan di tutorial ini. Gunakan tabel di bawah untuk melihat gambar mana yang harus diimpor, nama sprite, dan titik origin yang bersangkutan.

Nama Sprite Gambar Pusat
SPR_PlayerWalking
PlayerWalking1.png,
PlayerWalking2.png,
PlayerWalking3.png,
PlayerWalking4.png,
PlayerWalking5.png,
PlayerWalking6.png
X = 43, Y = 117
SPR_PlayerBasicPunch
PlayerPunchA1.png,
PlayerPunchA2.png,
PlayerPunchA3.png,
PlayerPunchA4.png,
PlayerPunchA5.png
X = 55, Y = 122
SPR_PlayerStrongPunch
PlayerPunchB1.png,
PlayerPunchB2.png,
PlayerPunchB3.png,
PlayerPunchB4.png,
PlayerPunchB5.png
X = 60, Y = 124
SPR_PlayerHit
PlayerHit.png
X = 43, Y = 117

Kita juga perlu mengimpor beberapa gambar Musuh. Kita bisa lakukan dengan cara yang sama. Gambar-gambar ini bisa dilihat di folder Assets > Images > Standard Enemy.

Nama Sprite

Gambar

Titik Pusat

SPR_EnemyIdle

RedEnemyIdle.png

X = 40, Y = 117

SPR_EnemyWalking

RedEnemyWalking1.png, RedEnemyWalking2.png, RedEnemyWalking3.png, RedEnemyWalking4.png, RedEnemyWalking5.png, RedEnemyWalking6.png

X = 45, Y = 117

SPR_EnemyHit

RedEnemyHit.png

X = 46, Y = 117

Membuat Objek Game Pertama Kita

Sekarang kita sudah memiliki gambar yang kita butuhkan, kita mulai membuat game kita dengan membuat objek pemain dan musuh.

  1. Klik kanan folder Objects dan pilih Create/Insert Object.
  2. Beri nama OBJ_Player.
  3. Atur sprite objek menjadi SPR_PlayerIdle.
  4. Pilih Add Event > Create.
  5. Di bawah tab Control, tambahkan aksi Execute Code.
  6. Tambahkan kode berikut:
1
///Create Player

2
Speed = 12;
3
SpeedMod = 1;
4
XSpeed = 0;
5
YSpeed = 0;
6
7
IsAttacking = false;
8
AttackType = 0;
9
MaxHP = 100; 
10
CurrentHP = MaxHP;
11
IsHit = false;
12
13
OnGround = true;
14
GroundY = y;
15
16
image_speed = .75;

Kode di atas mengatur beberapa variabel dasar untuk objek pemain kita. Sepanjang pengembangan game kita akan menambahkan beberapa variabel, tapi kita lihat dulu yang kita miliki saat ini.

Speed adalah kecepatan bergerak pemain, SpeedMod akan mengubah kecepatan pemain berdasarkan powerup yang didapat, dan debuffs.XSpeed dan YSpeed akan digunakan untuk mengatur kecepatan di masing-masing sumbu geraknya. IsAttacking dan IsHit memberi tahu kita apakah pemain menyerang atau mengenai musuh jadi kita bisa menghentikan pemain, dan AttackType memberitahu jenis serangan yang digunakan. Terakhir, MaxHP dan CurrentHP menyimpan informasi kesehatan pemain.

Perhatikan pula variabel OnGround dan GroundY. Variabel ini tidak terlalu penting sekarang, tapi nantinya akan digunakan saat kita menambahkan fitur Knockback.

Bagian terakhir kode ini mengatur image_speed, yang mengatur seberapa cepat animasi kita dijalankan.

Mari buat objek Musuh.

  1. Klik kanan folder Objects dan pilih Create/Insert Object
  2. Beri nama OBJ_Enemy.
  3. Atur sprite objek menjadi SPR_EnemyIdle.
  4. Pilih Add Event > Create.
  5. Di tab Control, tambahkan aksi Execute Code.
  6. Tambahkan kode berikut:
1
Speed = 5;
2
SpeedMod = 1;
3
4
IsHit = false;
5
6
MaxHP = 80;
7
CurrentHP = MaxHP;
8
9
OnGround = true;
10
GroundY = y;
11
12
image_speed = .75;
13
14
SideMod = 1;

Seperti yang bisa kamu lihat, Musuh saat ini sangat mirip dengan pemain dan menggunakan banyak variabel yang sama. Variabel tambahan satu-satunya adalah SideMod, yang nantinya akan kita gunakan untuk AI musuh.

Menambahkan ruangan

Dengan objek musuh sederhana dan pemain sudah disiapkan, kita tambahkan ruangan dalam game agar mereka bisa berlari ke sana kemari.

  1. Klik kanan folder Rooms, pilih Create/Insert Room.
  2. Biarkan ukuran  ruangan saat ini.
  3. Buka tab Objects.
  4. Pilih OBJ_Player dan tambahkan ke sisi kiri ruangan kita.
  5. Pilih OBJ_Enemy dan tambahkan beberapa musuh di sisi kanan.

Di bawah ini kamu bisa melihat ruangan dasar terlihat seperti apa, tapi kamu boleh membuatnya sedikit berbeda dengan contoh ini.

Di akhir seri kita akan membuat level yang lebih menarik, tapi kali ini cukup level yang sederhana.

An example of a possible layout for the roomAn example of a possible layout for the roomAn example of a possible layout for the room

Menambahkan Bayangan

Sebelum kita menambahkan gerakan, kita bisa membuat tampilan game menjadi lebih baik. Saat ini semuanya terlhat datar karena karakter berdiri di depan latar belakang abu-abu. Kita bisa memperbaikinya dengan menambahkan bayangan di bawah karakter untuk menyimulasikan kedalaman dan membuat seakan karakter berdiri di sebuah ruangan, bukan di atas latar belakang abu-abu.

  1. Buka objek Player dan pilih Add Event > Draw > Draw.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
//Set the opacity to 60% and then draw a dark gray oval for the shadow.

2
draw_set_alpha(.6);
3
draw_set_color(c_dkgray);
4
draw_ellipse(x-40,y-8,x+40,y+8,false);
5
6
//Draw my own sprite.

7
draw_set_alpha(1);
8
draw_self();

Kode ini hanya menggambar lingkaran abu-abu gelap yang agak transparan di bawah karakter pemain. Hal ini sangat sederhana, tapi saat kita lihat di dalam game, hal ini membuat karakter terlihat berdiri di atas tanah. Saat kamu masuk ke dalam game, sekarang karakter akan terlihat seperti ini:

The player character with a shadow implementedThe player character with a shadow implementedThe player character with a shadow implemented

Lebih baik!

Sekarang karena pemain sudah terlihat lebih baik, kita perlu lakukan hal yang sama untuk musuh. Ikuti langkah yang sama untuk menambahkan bayangan pada karakter musuh.

Jika sudah, cobalah game kamu, seharusnya akan terlihat seperti ini:

All of the characters with shadows enabled in-gameAll of the characters with shadows enabled in-gameAll of the characters with shadows enabled in-game

Perubahan kecil ini akan membuat game lebih baik dan lebih menarik. Dalam hal ini, bayangan membantu membuat lingkungan lebih 'menjual' dan memberi efek kedalaman, walau tidak sempurna.

Sekarang game kita sudah lebih menarik, kita mulai tambahkan gameplay.

Pergerakan Pemain

Sejauh ini kita sudah mengatur karakter, tapi kita belum memberitahu bagaimana untuk bergerak atau menyerang. Karena pemain tidak bisa menyerang musuh dari ujung ruangan, kita mulai dengan pergerakan pemain. Ini adalah kode yang cukup panjang, jadi kita akan buat secara bertahap. Kita buat bagian pertama.

  1. Buka objek Player.
  2. Gunakan Add Event > Step > Step.
  3. Di tab Control, tambahkan aksi Execute Code.
  4. Tambahkan kode berikut:
1
if(CurrentHP > 0){
2
      
3
}else{
4
    instance_destroy();
5
}

Kode ini memeriksa apakah HP pemain lebih besar dari 0, jika tidak, pemain akan dihancurkan.

Sekarang tambahkan kode ini ke bagian if dari statement:

1
//Checks if either the A or D buttons are pressed to make the player move Left or Right.

2
XSpeed = 0;
3
if(keyboard_check(ord('A'))){
4
    XSpeed = -1*Speed;
5
}else if(keyboard_check(ord('D'))){
6
    XSpeed = Speed;
7
}

Bagian dari kode ini memeriksa apakah tombol A atau D sedang ditekan, dan mengatur XSpeed pemain sesuai kebutuhan. Jika tombol A ditekan, XSpeed pemain negatif, artinya pemain bergerak ke belakang, dan jika D ditekan, nilainya positif, artinya bergerak ke depan.

Tidak cukup hanya bisa bergerak ke depan dan belakang. Kita juga perlu untuk bisa bergerak ke atas dan bawah, mari kita tambahkan kode untuk menangani tombol W dan S.

Tambahkan kode ini ke bagian if dari statement, setelah bagian kode sebelumnya:

1
//Checks if either the W or S buttons are pressed to make the player move Up or Down.

2
YSpeed = 0;
3
if(OnGround == true){
4
    if(keyboard_check(ord('W'))){
5
        YSpeed = -1*Speed;
6
    }else if(keyboard_check(ord('S'))){
7
        YSpeed = Speed;
8
    }
9
}

Kode ini melakukan hal yang sama dengan kode sebelumnya, tapi untuk YSpeed.

Kamu mungkin berpikir, "Bagus, sekarang karakter saya sudah bisa bergerak." Tapi kenyataannya, yang sudah kita lakukan adalah mengatur kecepatannya, kita masih perlu menggerakkan karakter. Karena bagian kode berikutnya lebih panjang, kita akan kembali membaginya menjadi bagian-bagian lebih kecil. Kita mulai dengan menambahkan keterangan agar kamu bisa melihat apa yang akan dilakukan oleh kode tersebut.

Tambahkan potongan kode ini ke bagian if dari statement, setelah bagian sebelumnya.

1
if(IsAttacking == false && IsHit = false){
2
        
3
    //If the player is on the ground move them with XSpeed and YSpeed, otherwise ignore YSpeed

4
    
5
    //Change the direction of the Player's sprite based on the direction they're moving

6
    
7
    //Animate the Player based on what they're doing.

8
}

Seperti yang bisa kamu lihat, kita akan melakukan tiga hal.

Pertama, kita memindahkan pemain menggunakan variabel XSpeed dan YSpeed, tapi kita akan mengabaikan YSpeed jika pemain tidak berada di atas tanah.

Berikutnya, kita akan ubah arah sprite pemain berdasarkan arah gerakan pemain. Dengan begini, jika pemain begerak ke kiri, pemain akan menghadap kiri, dan jika bergerak ke kanan, pemain akan menghadap kanan.

Akhirnya, kita animasikan pemain agar menggunakan sprite Idle saat tidak bergerak, dan sprite walking saat berjalan.

Kita akan ganti komentar satu per satu. Ganti komentar //If the player is on the ground... dengan kode berikut:

1
if(OnGround==true){    
2
    if(XSpeed != 0 && YSpeed != 0){
3
        x+=XSpeed*SpeedMod*.7;
4
        y+=YSpeed*SpeedMod*.7;
5
    }else if(XSpeed != 0 || YSpeed != 0){
6
        x+=XSpeed*SpeedMod;
7
        y+=YSpeed*SpeedMod;
8
    }
9
    
10
}else if(OnGround == false ){
11
    x+=XSpeed*SpeedMod;
12
}

Statement if utama dari kode ini memeriksa apakah pemain ada di atas tanah. Jika iya, maka ada statement if berikutnya yang menentukan apakah pemain bergerak secara diagonal, dan melambatkan mereka untuk mencegah pemain begerak lebih jauh dari seharusnya. Jika pemain tidak di atas tanah, hanya pergerakan di sumbu X yang diperbolehkan.

Lalu, ganti komentar //Change the direction of... menjadi kode berikut:

1
if(XSpeed != 0){
2
    image_xscale = sign(XSpeed*SpeedMod);
3
}

Kode ini lebih sederhana dari bagian sebelumnya. Kode ini mengatur Xscale dari pemain berdasarkan arah geraknya. Alasan kita periksa apakah XSpeed bernilai 0 karena jika tidak kita periksa, lebar pemain akan menjadi 0 piksel jika tidak bergerak.

Akhirnya, menggantikan //Animate pemain... komentar dengan kode berikut:

1
//Animates the Player based on their speed

2
if(XSpeed == 0 && YSpeed == 0 && OnGround == true){
3
    SpeedMod = 1;
4
    sprite_index = SPR_PlayerIdle;
5
}else if((XSpeed!=0 || YSpeed != 0) && sprite_index!=SPR_PlayerWalking && OnGround == true){
6
    sprite_index = SPR_PlayerWalking;
7
}

Ini adalah kode yang cukup sederhana. Jika kecepatan XSpeed dan YSpeed bernilai 0, dan pemain ada di atas tanah, artinya pemain tidak bergerak dan kita atur animasinya menjadi Idle. Sebaliknya, jika XSpeed atau YSpeed tidak bernilai 0, pemain ada di tanah, dan kita belum menggunakan sprite Walking, kita atur animasinya menjadi Walking.

Satu hal yang paling penting dari kode ini adalah kita periksa apakah animasi Walking sudah kita gunakan sebelum kita mengubahnya menjadi animasi Walking. Jika kita tidak lakukan ini, setiap frame saat pemain bergerak, kode ini akan bernilai true dan animasinya akan selalu diulang dari awal. Dengan memastikan animasi tersebut belum digunakan, kita menghindari masalah tersebut dan animasi akan berjalan dengan normal.

Hal terakhir yang perlu kita tambahkan untuk pegerakan akan disimpan di akhir event Step, setelah statement if/else:

1
//If the player is on the ground, this sets their GroundY variable to their current y position

2
if(OnGround == true){
3
    GroundY = y;
4
}
5
6
//Sets the Players' depth based on their GroundY. We're using GroundY instead of y so that even when they're in the air, they will display in fornt of and behind the right objects.

7
depth = -1*GroundY;

Kode ini mengatur GroundY untuk pemain dan mengatur kedalaman di layar berdasarkan GroundY. Nilai GroundY akan digunakan saat pemain terpukul mundur atau terlempar untuk menyimpan di mana bayangan pemain di tanah dan ketinggiannya. Variabel ini juga menyimpan informasi seberapa tinggi pemain dan kapan pemain akan mencapai tanah.

Statement depth setelahnya membuat semakin tinggi pemain, semakin jauh bayangan digambar. Dengan begini, saat pemain berlari melewati musuh dan begerak di dalam level, pemain selalu digambar dengan benar relatif terhadap objek/karakter lain.

Jika kamu masuk ke dalam game mulai menguji game, kamu sudah bisa berlari di dalam area game dengan karakter pemain. Kamu mungkin menemukan beberapa masalah, seperti saat kamu melewati musuh.

An example of bad depth drawingAn example of bad depth drawingAn example of bad depth drawing

Alasan kedalaman tidak bekerja seperti yang saya jelaskan di atas adalah karena kita perlu menambahkan kode yang serupa pada kode musuh agar kedalamannya juga diatur dengan benar.

  1. Buka objek Enemy dan pilih Add Event > Step > Step.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
if(OnGround == true){
2
    GroundY = y;
3
}
4
depth = -1*GroundY;

Sekarang jika kamu masuk dalam game, kamu bisa lihat bahwa kedalaman sudah bekerja dengan benar. Jika kamu bergerak sekitar musuh, kamu akan bisa melewati depan dan belakang musuh dengan benar.

The corrected depth drawingThe corrected depth drawingThe corrected depth drawing

Persiapan untuk serangan: Layer

Sekarang kode untuk pegerakan awal sudha selesai, kita bisa lanjut ke serangan. Sebelum kita bisa mulai menyerang, kita perlu menambahkan dua hal.

Pertama, kita perlu konstanta baru untuk memberitahu kita seberapa dekat karakter agar bisa saling memukul. Dalam game Beat 'Em Up seperti ini, kita mensimulasikan kedalaman 3D. Kita lakukan dengan beberapa cara, dan salah satunya adalah dengan menyimpan informasi kedalaman karakter menggunakan variabel depth yang kita lakukan sebelumnya. Cara lain untuk melakukan ini adalah menentukan seberapa jauh dua objek pada sumbu Y, sebelum mereka tidak bisa berinteraksi. Dengan begini, walau sprite saling menumpuk/tabrakan, tabrakan hanya dianggap jika karakter cukup dengan di dunia permainan dan tampilan perspektif tidak akan membuat masalah.

Jika kamu tidak mengerti, lihat gambar berikut:

A collission that should not be considered valid for an attackA collission that should not be considered valid for an attackA collission that should not be considered valid for an attack

Pada gambar ini, pemain dan musuh sebenarnya bertabrakan, tapi kamu bisa melihat dari perspektif bahwa mereka tidak sedekat itu untuk bisa berinteraksi. Dengan membuat konstanta bernama LayerSize, kita bisa mengatur jarak vertikal maksimum yang diperbolehkan untuk dua objek berinteraksi.

  1. Pada sidebar di bawah Macros, pilih All Configurations.
  2. Pada makro pertama ini, beri nama LayerSize dan atur nilainya menjadi 35.
  3. Tekan Okay.

Ini adalah nilai yang saya rasa cukup benar, tapi kamu bisa mencoba menggunakan nilai lain yang cocok untuk game kamu.

Saat kita melakukan serangan, konstanta ini akan menentukan apakah serangan itu berhasil atau tidak.

Persiapan serangan: Menghentikan Musuh

Hal lain yang perlu kita lakukan sebelum membuat serangan adalah mengatur animasi terpukul pada musuh, agar mereka bereaksi saat kita menyerang mereka. Untuk ini kita akan menggunakan animasi EnemyHit, yang sudah kita impor sebelumnya, dan variabel IsHit.

Pertama, kita perlu masuk ke event step dan mengubah kode agar animasi terpukul digunakan.

  1. Buka OBJ_Enemy.
  2. Pilih event Step, dan buka aksi code.
  3. Tambahkan kode berikut pada awal event:
1
if(IsHit==true){
2
    sprite_index = SPR_EnemyHit;
3
}else{
4
    sprite_index = SPR_EnemyIdle;
5
}

Untuk memastikan kode ini bekerja, masuk ke event pembuatan musuh dan ubah IsHit menjadi true. Masuk ke game, dan lihat animasi musuh. Kamu seharusnya melihat animasi seperti ini.

The Enemy Hit animationThe Enemy Hit animationThe Enemy Hit animation

Walau animasi Hit berjalan, kamu bisa perhatikan bahwa animasinya tidak pernah berhenti. Alasannya karena kita tidak memiliki kode yang mengembalikan status IsHit musuh setelah suatu batas waktu tertentu. Begitu kita atur menjadi True, selamanya akan seperti itu.

Untuk memperbaikinya, kita akan membuat sebuah a larm yang akan mengembalikan variabel IsHit, dan membuat musuh kembali menjadi Idle saat alarm menyala. Lalu, setiap musuh terpukul, setiap serangan akan berisi statement yang memberitahu musuh berapa lama mereka akan berhenti sebelum kembali ke Idle, dan akan memulai alarm dengan rentang waktu tersebut.

  1. Buka OBJ_Enemy dan pilih Add Event > Alarm > Alarm 0.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
IsHit = false;

Kode tersebut mengembalikan nilai IsHit, dan event Step akan menangani sisanya.

Kamu tidak bisa langsung menguji fitur ini, tapi jika kamu tambahkan kode di bawah pada akhir event Create, kamu bisa melihat efek dari yang kita buat saat game pertama dijalankan. Pastikan kamu manghapus kode kamu, dan kembalikan IsHit menjadi false, sebelum melanjutkan membuat fitur berikutnya.

1
alarm[0] = 15;

Membuat objek serangan

Sekarang kita sudah memiliki semua komponen yang dibutuhkan, kita bisa mulai membuat objek serangan.

Pertama, kita perlu membuat objek Attack untuk menyimpan semua status serangan yang bersangkutan, misalnya berapa damage yang dihasilkan, seperti apa hitboxnya, dan efek partikel apa yang perlu digunakan, dan lain-lain. Membuat objek unik untuk masing-masing serangan lebih baik dibanding memaksa objek Pemain atau musuh untuk menyimpan semua informasi yang relevan, dan memiliki parent object bisa membuat proses ini lebih mudah. Hal itu juga membuat kode serangan lebih fleksibel, dan membuat kita bisa membuat kode untuk satu serangan yang bisa digunakan banyak karakter sekaligus.

UNtuk membuat objek serangan pertama, ikuti langkah-langkah berikut:

  1. Klik kanan folder Object dan pilih Create/Insert Object.
  2. Beri nama objek tersebut ATK.
  3. Gunakan Add Event > Create.
  4. Pada tab Control, tambahkan aksi Execute Code.
  5. Tambahkan kode berikut:
1
depth = -1*y;
2
3
Damage = 10;
4
StunLength = 4;
5
Owner = "Player";
6
DMGFrame = 3;

Baris kode pertama mengatur kedalaman objek Attack sama seperti kita mengatur kedalaman untuk Player. Sisa dari kode tersebut digunakan untuk menyiapkan variabel penting untuk Attack. Kita lihat apa saja fungsi dari variabel tersebut. Damage adalah seberapa besar kerusakan yang disebabkan oleh suatu serangan. StunLength adalah jumlah frame di mana musuh akan berhenti sesuai dengan variabel IsHit. Owner adalah yang melakukan serangan. Ini bisa pemain atau musuh, dan mencegah musuh menyerang sesamanya. DMGFrame membuat kita menentukan kapan sebuah serangan menghasilkan damage.

Pada game Beat 'Em Up, timing itu sangat penting, dan serangan hanya bisa menghasilkan damage jika dilakukan di waktu yang tepat. Lihat serangan berikut:

An example attack from an Enemy we will implement in a later tutorialAn example attack from an Enemy we will implement in a later tutorialAn example attack from an Enemy we will implement in a later tutorial

Jika kamu menerima damage sebelum tangan musuh turun, kamu akan merasa dicurangi, karena terlihat seperti seharusnya kamu belum terluka. Variabel DMGFrame memberitahu objek serangan, frame mana yang memberikan damage, jadi tabrakan pada frame lain akan diabaikan. Hal seperti ini menjadi dasar dari semua permainan berbasis timing, mulai dari Turtles in Time sampai Dark Souls. Hal ini membuat kita bisa 'membaca' serangan musuh dan menghindarinya sebelum mengenai kita.

Mari tambahkan kode tabrakan pada serangan agar menghasilkan damage saat mengenai target.

  1. Pad objek Atk, buka Add Event > Collision > OBJ_Enemy.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
if(image_index == DMGFrame && abs(depth - other.depth) <= LayerSize && abs(y - other.y) <= LayerSize && Owner == "Player"){
2
    
3
    other.CurrentHP -= Damage;
4
    other.IsHit = true;
5
    other.alarm[0] = StunLength;
6
    
7
}

Kode di atas dijalankan setiap serangan bertabrakan dengan objek musuh, dan menggunakan statement if untuk menentukan apakah serangan itu berhasil mengenai target atau tidak. Statement if menguji empat hal:

  1. Apakah frame saat ini adalah damage frame?
  2. Apakah perbedaan antar depth serangan dan musuh lebih kecil dari LayerSize?
  3. Apakah serangan dan musuh memiliki nilai Y dan dekat? Dengan kata lain, apakah mereka sama-sama di tanah, atau keduanya dekat tapi berada di udara?
  4. Apakah serangan dibuat oleh pemain? Karena event ini berlaku untuk musuh, kita perlu memastikan pemain lah yang membuat serangan. Kamu bisa menghilangkan pemeriksaan ini jika kamu ingin musuh bisa saling melukai.

Jika semua kondisi tersebut bernilai true, maka serangan dianggap sukses, musuh menerima serangan, dan berhenti sesaat.

Kita juga perlu melakukan hal yang sama untuk tabrakan dengan pemain.

  1. Pada objek Atk, buka Add Event > Collision > OBJ_Player.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
if(image_index == DMGFrame && abs(depth - other.depth) <= LayerSize && abs(y - other.y) <= LayerSize && Owner == "Enemy"){
2
    
3
    other.CurrentHP -= Damage;
4
    other.IsHit = true;
5
    other.alarm[3] = StunLength;
6
    
7
}

Ini adalah kode yang sama dengan tabrakan musuh, tapi memeriksa apakah serangan dilakukan oleh musuh, sehingga mencegah pemain terluka karena serangan mereka sendiri.

Sekarang kita perlu membuat hitbox untuk serangan. Hitbox adalah bagian dari sprite yang dianggap bisa bertabrakan, dan digunakan untuk memastikan hanya sebagian dari sprite yang menyebabkan tabrakan dan membuat karakter bisa terluka. Contohnya, jika saya kembali ke serangan karakter Kuning, saya hanya ingin sebagian kecil yang ditandai merah yang bisa digunakan untuk melakukan serangan.

The portion of the Enemys attack which should damage the PlayerThe portion of the Enemys attack which should damage the PlayerThe portion of the Enemys attack which should damage the Player

Jika bagian lain selain tangan tnersebut membuat pemain terluka, game akan terasa tidak adil. Untuk memecahkan masalah ini, saya bisa menggunakan hitbox yang hanya memeriksa bagian dari sprite dan mengabaikan sisanya.

Kamu bisa mengimpor hitbox dari serangan kita dengan tabel di bawah. Setelah selesai, lalu pasangkan hitbox ke sprit eobjek ATK .

Nama Sprite

Gambar

Posisi awal

SPR_BasicPunch_Hitbox

BasicPunchHitbox1.png,

BasicPunchHitbox2.png,

BasicPunchHitbox3.png,

BasicPunchHitbox4.png,

BasicPunchHitbox5.png

X = 55, Y = 122

Ketika pemain menyerang, pemain perlu mengatur sprite sesuai kebutuhan, tapi menggunakan sprite hitbox untuk sprite ATK memastikan hanya bagian tersiebut yang mendata tabrakan.

Hal lain yang perlu kita lakukan adalah memastikan bahwa menghancurkan objek serangan. Jika kita tidak menghancurkannya, serangan akan terus berjalan dan akan membunuh musuh kita dalam sekejap. Untuk memastikan hal ini tidak terjadi, kita akan menggunakan event Animation End.

  1. Buka objek ATK dan pilih Add Event > Other > Animation End.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
instance_destory();

Dengan event ini, objek serangan akan segera menghancurkan dirinya sendiri setelah selesai berjalan, dan tidak akan ada di layar dan menyebabkan masalah lain.

Sekarang kamu harus mematikan checkbox Visible pada objek ATK agar hitbox tidak bisa dilihat.

Dasar objek serangan kita sudah selesai, tapi kita masih perlu membuat serangan pertama kita dengan mengembangkan objek dasar tersebut. Menggunakan objek ATK dengan dasar untuk serangan lain akan memudahkan kita untuk membuat banyak serangan yang berbeda.

  1. Buat objek baru bernama ATK_BasicPunch.
  2. Atur Parent-nya menjadi objek ATK.
  3. Atur Sprite menjadi SPT_BasicPunch_Hitbox.
  4. Gunakan Add Event > Create.
  5. Pada tab Control, tambahkan aksi Execute Code.
  6. Tambahkan kode berikut:
1
event_inherited();

Serangan Basic Punch sekarang sudah selesai karena mengembangkan dari objek ATK dan menurutkan semua properti yang ada di event Create. Jika kamu ingin basic punch lebih kuat atau menghentikan lawan untuk waktu lebih lamam kamu bisa mengubah properti dengan mengaturnya di sini.

Contohnya, kamu bisa menggunakan:

1
event_inherited();
2
Damage = 15;
3
StunLength = 2;

Ini akan membuat serangan memberikan lebih banyak damage, tapi menghentikan musuh lebih sebentar.

Kamu juga bisa menggunakan:

1
event_inherited();
2
Damage = 8;
3
StunLength = 7;

Kode ini memberikan damage lebih kecil, tapi menghentikan lawan lebih lama.

Cobalah modifikasi Damage, StunLength, dan DMGFrame (pastikan nilainya tidak lebih dari 5 karena serangan kita hanya 5 frame) sesuai keinginan kamu, dan buatlah variasi yang berbeda dari jenis serangan tersebut. Apapun yang kamu lakukan, pastikan objek ATK diatur sebagai parent dari objek serangan baru, dan terdapat event_inherited() di awal setiap event yang dimiliki kelas Parent.

Membuat pemain menyerang

Karena serangan kita sudah selesai, pemain harus bisa menggunakannya di dalam permainan. Untuk sistem pertarungan kita, kita akan menggunakan tiga skema kontrol untuk mengakomodasi banyak jenis pemain.

Kita akan membolehkan pemain menggunakan IJKL, tombol 4856 pada numpad, dan tombol panah untuk menjadi tombol-tombol serangan. Ini akan memberikan pemain kesempatan untuk mengatur tombol sesuai dengan ukuran atau susunan keyboard mereka. Terlebih lagi, karena ketiga set itu memiliki susunan dasar yang sama, mudah untuk membuat semuanya bekerja. J, 4, dan panah kiri akan menjadi serangan ringan, I, 8, dan panah atas akan menjadi serangan kuat, K, 5, dan panah bawah akan menjadi bantingan, dan L, 6, dan panah kanan akan menjadi jurus spesial.

  1. Dalam objek Player, pilih Add Event > Key Press > Any Key.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
AttackType = "";
2
3
if(keyboard_check(vk_numpad4) || keyboard_check(ord('J')) || keyboard_check(vk_left)){
4
    AttackType = "Basic Punch";
5
}
6
7
if(OnGround == true){
8
    event_user(2);
9
}

Pertama, kode ini memeriksa jika pemain menekan tombol serangan ringan yang sudah disebutkan sebelumnya, panah kiri, tombol numpad 4, dan tombol J. Jika iya, kita atur AttackType Player menjadi Basic Punch. Setelah menentukan AttacKType, kode kemudian memeriksa pemain ada di tanah, dan memanggil event Attack.

Event Attack akan membuat objek serangan tergantung dari jenis serangan yang digunakan. Mungkin terlihat aneh karena kita membuat ini sebagai event yang terpisah, ini karena kode kita masih sederhana. Tapi jika kita tambahkan jauh lebih banyak serangan, dan mengimplementasi combo, akan lebih baik jika elemen-elemen ini dipisahkan.

  1. Pada objek Player, pilih Add Event > Other > User Defined > User 2.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
var MyAttack = 0;
2
3
if(IsHit == false && CurrentHP > 0){
4
    if(AttackType == "Basic Punch"){
5
         sprite_index = SPR_PlayerBasicPunch;
6
        MyAttack = instance_create(x,y,ATK_BasicPunch);
7
    }
8
}
9
10
if(MyAttack != 0){
11
    SpeedMod = 0;
12
    IsAttacking = true;
13
    MyAttack.image_xscale = image_xscale;
14
    MyAttack.image_speed = image_speed;
15
    MyAttack.Owner = "Player";
16
}

Kode ini cukup sederhana, walau awalnya mungkin terlihat rumit.

Pertama, kita membuat objek sementara untuk menyimpan serangan. Lalu, selama pemain belum terpukul, dan pemain tidak mati, kita tentukan serangan apa yang digunakan, atur animasinya, dan buat objek serangan dengan tipe yang tepat. Akhirnya, jika objek serangan dibuat, kode mengatur pemain untuk menyerang, mengatur arah dan kecepatan serangan mengikuti pemain, dan mengatur nilai Owner dari serangan.

Sekarang kita bisa masuk ke game dan menguji serangannya. Jika kamu mendekati musuh dan menggunakan satu serangan ringan, kamu akan lihat pemain menyerang dan musuh terkena serangan.

Kamu akan melihat suatu masalah. Berapa lama kamu tunggu, animasi pemain tidak akan berganti dari animasi serangan, walau musuh sudah tidak menerima damage. Kamu juga tidak akan bisa bergerak.

Ini masalah yang sama dengan musuh dan animasi hit. Seperti kejadian tersebut, kita perlu mengatur sistem yang mengatur ulang variabel IsAttacking saat serangan selesai. Kita akan lakukan ini dengan event Animation End.

  1. Buka OBJ_Player dan pilih Create Event > Other > Animation End.
  2. Pada tab Control, tambahkan aksi Execute Code.
  3. Tambahkan kode berikut:
1
if(IsAttacking == true){
2
    IsAttacking = false;
3
    SpeedMod = 1;
4
}

Sekarang saat kamu masuk ke game, serangan akan bekerja sesuai harapan, dan animasi akan berakhir pada waktunya.

Menambahkan suara

Serangan kita bekerja dengan baik dalam game, tapi belum bisa menarik perhatian pemain. Bagian dari masalahnya adalah kita tidak punya efek suara untuk memberi feedback untuk pemain saat serangan berhasil atau gagal. Kita selesaikan masalah ini untuk bisa melengkapi objek serangan.

Kita perlu mengimpor dua suara untuk serangan, suara Hit dan Miss. Ikuti langkah-langkah berikut untuk mengimpor suara pertama.

  1. Klik kanan folder sound, dan pilih Create Sound.
  2. Atur nama menjadi SND_BasicPunch1.
  3. Import file suara LightPunch1.wav dari asset proyek.
  4. Atur Sample Rate menjadi 48000.
  5. Atur Bit Rate menjadi 320.
  6. Tekan Ok untuk menyimpan suara.

Kerja bagus! Kamu sekarang sudah mengimpor efek suara pertamamu.

Sekarang kita akan lakukan hal yang sama untuk suara Miss (meleset).

  1. Klik kanan folder Sounds, dan pilih Create Sound.
  2. Atur nama menjadi SND_MissedPunch.
  3. Import file suara Miss.wav dari asset proyek.
  4. Atur Sample Rate menjadi 48000.
  5. Atur Bit Rate menjadi 320.
  6. Tekan Ok untuk menyimpan suara.

Setelah mengimpor suara, kita perlu menambahkan variabel ke objek serangan agar bisa menggunakan suara dengan benar.

  1. Buka OBJ_Attack dan Create Event.
  2. Tambahkan kode berikut ke bagian akhir aksi Execute Code:
1
HitSound = SND_BasicPunch1;
2
MissSound = SND_PunchMiss;
3
4
Hit = false;

Tiga variabel ini cukup sederhana. Variabel HitSound dan MissSound membuat kita bisa mengubah suara hit dan miss dari setiap serangan di create event masing-masing, dengan cara yang sama seperti kita mengatur properti tiap serangan yang kita buat. Variabel Hit membuat kita bisa memeriksa apakah serangan itu berhasil atau gagal sebelum menjalankan suara Miss.

Sekarang kita perlu mengimplementasi variabel tersebut. Pertama, kita implementasi suara Hit.

  1. Pada OBJ_Attack, buka Collision with OBJ_Enemy.
  2. Tambahkan kode berikut ke bagian akhir dari statement if yang menunjukkan bahwa tabrakan itu valid:
1
audio_play_sound(HitSound,10,false);
2
3
Hit = true;

Kode ini menjalankan HitSound dan mengatur variabel Hit menjadi true saat attack bertabrakan dengan enemy.

Kita bisa gunakan kode yang sama untuk event tabrakan pemain.

  1. Pada OBJ_Attack, buka Collision with OBJ_Player.
  2. Tambahkan kode berikut di akhir statement if yang menunjukkan tabrakan valid:
1
audio_play_sound(HitSound,10,false);
2
3
Hit = true;

Terakhir kita perlu menambahkan suara miss jika serangan tidak mengenai apapun. Berbeda dengan suara Hit, yang dimainkan saat terjadi tabrakan, suara Miss hanya dijalankan jika objek serangan hancur tanpa mengenai apapun, jadi suara ini akan dimainkan di sebuah event Destroy.

  1. Pada OBJ_Attack, pilih Add Event > Destroy.
  2. Pada tab Control, tambahkan aksi Execute Code:
  3. Tambahkan kode berikut:
1
if(Hit == false){
2
3
    audio_play_sound(MissSound, 10, false);
4
5
}

Seperti yang bisa kamu lihat, kode hanya menjalankan MissSound jika Hit bernilai false.

Kamu sekarang bisa mencoba game dan menguji serangan sekali lagi, dan efek suara akan berjalan dengan benar.

Membuat serangan kuat

Karena serangan dasar sudah selesai, mari buat satu serangan lain, serangan kuat (Strong Attack). Untuk serangan ini, gunakan tabel di bawah untuk mengatur hitbox:

Nama Sprite

Gambar

Posisi Pusat

SPR_StrongPunch_Hitbox

StrongPunchHitbox1.png,

StrongPunchHitbox2.png,

StrongPunchHitbox3.png,

StrongPunchHitbox4.png,

StrongPunchHitbox5.png

X = 60, Y = 124

Kita juga perlu mengimpor HitSound yang berbeda untuk serangan ini karena seharusnya lebih kuat daripada serangan biasa.

  1. Klik kanan folder Sounds, dan pilih Create Sound.
  2. Atur namanya menjadi SND_StrongPunch1.
  3. Impor file suara HeavyPunch1.wav dari aset proyek.
  4. Atur Sample Rate menjadi 48000.
  5. Atur Bit Rate menjadi 320.
  6. Tekan Ok untuk menyimpan suara.

Sekarang semua aset sudah siap, saatnya membuat objek serangan sebenarnya.

  1. Buat objek baru bernama ATK_StrongPunch.
  2. Atur Parent menajdi  objek ATK.
  3. Hilangkan centang pada checkbox Visible.
  4. Atur Sprite menjadi SPR_StrongPunch_Hitbox.
  5. Gunakan Add Event > Create.
  6. Pada tab Control, tambahkan aksi Execute Code.
  7. Tambahkan kode berikut:
1
event_inherited();
2
Damage = 20;
3
StunLength = 10;
4
HitSound = SND_StrongPunch1;

Sekarang kembali ke objek Player, dan  tambahkan kode berikut ke event Keyboard Press > Any Key setelah Light Attack, jadi kode akan bisa mendeteksi saat pemain menggunakan serangan kuat.

1
if(keyboard_check(vk_numpad8) || keyboard_check(ord('I’)) || keyboard_check(vk_up)){

2
    AttackType = “Strong Punch”;

3
}

Lalu, buka User Defined 2 dan tambahkan kode berikut di akhir statemtnt if yang membuat objek Light Attack, agar bisa juga membuat objek Strong Attack. Pastikan kode tersimpan dalam kode if yang memeriksa apakah pemain mati:

1
else if(AttackType == "Strong Punch”){

2
    sprite_index = SPR_PlayerStrongPunch;

3
    MyAttack = instance_create(x,y,ATK_StrongPunch);

4
}

Kodemu akan terlihat seperti ini:

The updated attack code for the PlayerThe updated attack code for the PlayerThe updated attack code for the Player

Sekarang jika kamu masuk ke game, kamu akan bisa mengginakan serangan ringan dan serangan kuat pada musuh. Seperti yang kamu lihat, kedua serangan itu sangat mirip, hanya berbeda dari animasi yang digunakan, hitbox, dan properti dasarnya.

Kesimpulan

Kamu sekarang bisa mengedit dan mengatur serangan sesuatu seleramu. Pada artikel berikutnya kita akan membuat musuh bisa melawan, dan satu fitur lanjutan untuk kamera.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.