Di artikel pertama saya, kita membuat pesawat kita bergerak sesuai tombol yang ditekan. Di artikel kedua, pesawat kita sudah bisa menembakkan peluru di arah mouse. Sekarang kita akan menambahkan musuh untuk kita lawan. Langsung saja, tambahkan sprite berikut ke folder asset
![]()
sprite seperti ini disebt spritesheet, yaitu satu file gambar / image terdapat beberapa sprite yang nantinya bisa dianimasikan oleh engine, dalam hal ini flashpunk. Buatlah class enemy yang meng-inherit class Entity.
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Spritemap;
import net.flashpunk.FP;
/**
* ...
* @author Aryadi Perwira Subagio
*/
public class Enemy extends Entity
{
private var img:Spritemap;
private var logic:EnemyAI;
public function Enemy(sprite:*, AI:EnemyAI)
{
img = new Spritemap(sprite, 32, 32);
img.add("fly", [0, 1, 2], 10);
graphic = img;
img.play("fly");
logic = AI;
logic.actor = this;
}
override public function update():void
{
logic.update(FP.elapsed);
}
}
}
class Enemy ini mirip dengan class Character, bedanya adalah bukannya memakai class Image, class Enemy memakai class Spritemap, ini karena Spritemap lebih berguna untuk animasi menggunakan spritesheet. Kode di baris 18 membuat frame-frame animasi berdasarkan spritesheet yang kita masukkan di parameter pertama, parameter kedua dan ketiga adalah lebar dan tinggi satu sprite di dalam spritesheet, dalam hal ini 32 x 32. Di baris 19 kita menambahkan animasi bernama “fly” dengan frame ke 0, ke 1, dan ke 2. Urutan frame dimulai dari frame ke 0, yaitu sprite pertama dalam jarak 32 x 32 dari titik 0, 0. Frame ke 1 adalah frame di sebelah kanannya, dan seterusnya hingga sampai ujung spritesheet. Jika tinggi spritesheet lebih dari 32, misalkan kita punya spritesheet 3 sprite mendatar dan 2 sprite menurun, maka frame ke 3 adalah sprite terkiri dari baris kedua, begitu seterusnya untuk baris ketiga. Parameter ketiga adalah frame per second, yang kita buat 10 FPS, tapi bisa diubah sesuai keinginan programmer.
Baris ke 21 membuat spritesheet menjalankan animasi sesuai dengan nama animasi yang kita panggil. Di sini kita menjalankan animasi “fly” tapi dalam class dengan spritesheet lebih besar dan lebih banyak animasi, kita bisa menentukan animasi mana yang ingin kita jalankan. Baris ke 23 mengatur logic alias AI musuh yang akan berjalan tiap update, dan baris ke 24 memberitahu class AI bahwa ia di-assign ke entity ini.
Dalam fungsi update kita memanggil fungsi update dari logic agar AI bisa menggerakkan Enemy. FP.Elapsed adalah berapa lama waktu telah berlalu semenjak frame sebelumnya, idealnya fungsi update mengetahui waktu ini agar pergerakan semua Entity dalam game sama cepat walaupun dimainkan di komputer dengan spesifikasi berbeda.
Berikutnya kita akan membuat class EnemyAI sebagai AI untuk musuh, buat kelas baru seperti ini:
package
{
/**
* ...
* @author Aryadi Perwira Subagio
*/
public class EnemyAI
{
protected var player:Character;
public var actor:Enemy;
public function EnemyAI()
{
}
public function update(elapsedTime:Number):void
{
}
}
}
variabel player adalah supaya musuh mengetahui posisi pemain agar bisa menembakkan peluru dengan tepat, variabel actor menentukan Enemy mana yang menggunakan AI ini. Class kosong, atau disebut juga abstract class, ini sudah cukup untuk bisa kita gunakan karena pengimplementasiannya adalah di child class, mari kita buat contoh child class dari EnemyAI.
package
{
/**
* ...
* @author Aryadi Perwira Subagio
*/
public class BasicAI extends EnemyAI
{
private var moveSpeed:int = 50;
private var deltaShot:Number = 1;
private var timeToDeltaShot:Number = 0;
public function BasicAI(player:Character)
{
this.player = player;
}
override public function update(elapsedTime:Number):void
{
actor.y += moveSpeed * elapsedTime;
timeToDeltaShot += elapsedTime;
if (timeToDeltaShot >= deltaShot)
{
shoot(player);
timeToDeltaShot -= deltaShot;
}
if (actor.y > 480)
{
actor.world.remove(actor);
}
}
private function shoot(target:Character):void
{
var peluru:Bullet = new Bullet(actor.x, actor.y, target.x, target.y);
actor.world.add(peluru);
}
}
}
Baris 9 sampai 11 adalah variabel-variabel yang kita butuhkan untuk class ini. Variabel moveSpeed adalah kecepatan gerak musuh, di sini kita buat sama dengan player, dan dua variabel sisanya adalah untuk memberikan jeda tembakan musuh, di sini kita buat jeda tembakan satu detik. Di constructor kita berikan player sebagai parameter agar musuh bisa mengetahui posisi player. Fungsi update memiliki parameter elapsedTime untuk mengetahui berapa lama waktu telah berlalu sejak frame sebelumnya.
Baris ke 20 menggerakkan Enemy ke bawah sesuai dengan kecepatan gerak. Baris ke 22 menambahkan waktu ke jeda waktu antar tembakan sesuai dengan waktu yang telah berlalu sejak frame sebelumnya, jika jeda waktu sudah melewati jeda antar tembakan yang sudah kita tentukan, Enemy akan menembak target yang dalam hal ini adalah player, setelah itu jeda waktu antar tembakan akan direset untuk perhitungan jeda tembakan berikutnya. Untuk mereset, timeToDeltaShot tidak kita kembalikan ke 0 tapi kita kurangi dengan deltaShot. Ini karena ketika menembak, besar kemungkinannya bahwa timeToDeltaShot lebih dari deltaShot, kalau kita kembalikan ke 0 maka akan ada perbedaan waktu antara tembakan sekarang dengan tembakan berikut. Untuk waktu tembakan yang sempurna, kita kurangi timeToDeltaShot dengan deltaShot.
Conditional if di baris 29 mencek apakah Enemy sudah keluar dari layar, jika sudah maka Enemy akan dikeluarkan dari world agar tidak di-update lagi. Kalau masih di-update setelah keluar dari layar akan ada tembakan dari luar layar. Fungsi shoot di AI ini kurang lebih sama dengan fungsi Shoot milih class Character, bedanya adalah fungsi ini menarget pemain.
Itu adalah class-class baru yang kita buat di tulisan ini, sekarang sebelum men-test hasil akhir game kita kita akan memperbarui dua class lama, yang pertama adalah class Character. Ubahlah fungsi update agar pesawat pemain menembak bukan ketika mouse ditekan, tapi ditahan, dengan kode berikut:
if (Input.mouseDown)
{
timeToDeltaShot += FP.elapsed;
if (timeToDeltaShot > deltaShot)
{
shoot(Input.mouseX, Input.mouseY);
timeToDeltaShot -= deltaShot;
}
}
logika kode ini sama dengan logika kode BasicAI, karena itu tambahkan variabel ini di class Character:
private var deltaShot:Number = 0.5; private var timeToDeltaShot:Number = 0;
Berikutnya kita akan mengubah class MapOne, pertama-tama embed sprite musuh
[Embed(source = "../assets/enemy-1.png")] private const ENEMY1:Class;
lalu tambahkan variabel untuk membuat musuh dan juga Ainya
private var AI1:BasicAI = new BasicAI(airship); private var enemy:Enemy = new Enemy(ENEMY1, AI1);
kemudian ubahlah constructor untuk mengubah posisi awal pemain dan musuh, dan juga menambahkan musuh
public function MapOne()
{
airship.x = 300;
airship.y = 400;
enemy.x = 200;
enemy.y = 10;
add(airship);
add(enemy);
}
kalau sudah, tekan F5 dan lihatlah game kita sudah memiliki musuh.
Di bawah ini adalah hasil jadinya.
