Advertisement
  1. Game Development
  2. Artificial Intelligence

Membuat AI Game Hoki Menggunakan Steering Behaviors: Menyerang

Scroll to top
Read Time: 19 min
This post is part of a series called Create AI for a Hockey Game Using Steering Behaviors.
Create a Hockey Game AI Using Steering Behaviors: Foundation
Create a Hockey Game AI Using Steering Behaviors: Defense

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

Dalam tutorial ini, kami melanjutkan pengkodean kecerdasan buatan untuk permainan hoki dengan menggunakan mesin steering behaviors and finite state. Di bagian seri ini, Anda akan belajar tentang AI (Kecerdasan Buatan) yang dibutuhkan oleh entitas permainan untuk mengkoordinasikan sebuah serangan, yang melibatkan penghadangan dan membawa puck (bola Hoki) ke gawang lawan.

Beberapa Kata Tentang Menyerang

Mengkoordinasikan dan melakukan serangan dalam permainan olahraga kooperatif adalah tugas yang sangat kompleks. Di dunia nyata, saat manusia bermain game hoki, mereka membuat beberapa keputusan berdasarkan banyak variabel.

Keputusan tersebut melibatkan perhitungan dan pemahaman tentang apa yang sedang terjadi. Seorang manusia bisa tahu mengapa lawan bergerak berdasarkan tindakan lawan lawan lainnya, misalnya, "dia bergerak untuk berada dalam posisi strategis yang lebih baik." Tidaklah mudah untuk menerapkannya dalam sebuah komputer.

Sebagai konsekuensinya, jika kita mencoba kode AI untuk mengikuti semua nuansa dan persepsi manusia, hasilnya akan menjadi tumpukan kode yang besar dan menyeramkan. Selain itu, hasilnya mungkin tidak tepat atau mudah dimodifikasi.

Itulah alasan mengapa serangan AI kita akan mencoba meniru hasil sekelompok manusia yang bermain, bukan persepsi manusia itu sendiri.  Pendekatan itu akan mengarah pada aproksimasi, namun kodenya akan lebih mudah dipahami dan di-tweak. Hasilnya cukup baik untuk beberapa kasus penggunaan.

Mengorganisir Serangan Dengan Kedudukan

Kami akan membagi prose penyerangan menjda beberapa-bagian, dengan masing-masing melakukan tindakan yang sangat spesifik. Bagiam-bagian itu adalah kedudukan dari mesin stack-based finite state.  Seperti yang dijelaskan sebelumnya, masing-masing kedudukan akan menghasilkan tenaga kemudi yang akan membuat atlit melakukan hal yang benar.

Orkestrasi kedudukan-kedudukan tersebut dan kondisi pertukaran di antara mereka akan menentukan serangan tersebut. Gambar di bawah menyajikan FSM lengkap yang digunakan dalam proses ini:

Sebuah mesin berbasis data setel stack yang mewakili proses penyerangan. 

Seperti yang terlihat pada gambar, kondisi untuk peralihan di antara kedudukan akan didasarkan pada jarak dan kepemilikan puck. Misalnya, ketika  tim memiliki puck atau puck yang berada terlalu jauh.

Proses penyerangan akan terdiri dari empat kedudukan idle (siaga)attack (menyerang)stealPuck (merebut Puck), and pursuePuck (Mengejar ). Kedudukan idle sudah diimplementasikan pada tutorial sebelumnya, dan ini adalah titik awal dari prosesnya.  Dari sana, seorang atlet akan beralih untuk attack jika tim memiliki puck, dan menyerang jika tim lawan memiliki puck, atau akan memburu. puck jika tidak seorangpun memiliki puck-nya dan cukup dekat untuk diraih.

kedudukan attack merupakan gerakan ofensif. Ketika berada pada kedudukan tersebut itu, atlet yang membawa puck (disebut leader) akan berusaha mencapai gawang lawan. Rekan tim akan bergerak, mencoba mendukung aksi tersebut.

Kedudukan stealPuck mewakili suatu berakan antara gerakan defensif dan ofensif.  Pada kedudukan ini, seorang atlet akan fokus mengejar lawan yang membawa puck-nya. Tujuannya adalah untuk mengembalikan puck-nya, sehingga tim bisa mulai menyerang lagi.

Pada akhirnya, kedudukan persuePuck itu tidak terkait dengan serangan atau pertahanan; itu hanya akan membimbing para atlet saat puck tidak memiliki pemilik. Sementara pada kedudukan itu, seorang atlet akan mencoba untuk mendapatkan puck yang bebas bergerak di arena (misalnya, setelah dipukul oleh tongkat seseorang).

Memperbarui Kedudukan Idle (siaga)

Kedudukan idle yang sebelumnya diimplementasikan tidak memiliki transisi. Karena keadaan ini adalah titik awal bagi keseluruhan AI, marilah kita mperbarui dan membuatnya dapat beralih ke kedudukan lainnya. 

Kedudukan idle memiliki tiga transisi:

Status idle dan transisinya dalam FSM menggambarkan proses penyerangan. 

Jika tim atlet memiliki puck, idle harus muncul dari otak dan serangan harus dilakukan. Begitu pula jika tim lawan memiliki puck, idle harus diganti dengan stealPuck (merebut puck).  Transisi yang tersisa terjadi ketika tidak ada yang memiliki puck dan dekat dengan atlet; Dalam hal ini, persuePuck usahakan agar bisa didorong masuk ke otak. 

Versi terbaru dari idle adalah sebagai berikut (kedudukan lainnya akan diimplementasikan nanti):

1
class Athlete {
2
    // (...)

3
    private function idle() :void {
4
        var aPuck :Puck = getPuck();
5
      
6
        stopAndlookAt(aPuck);
7
    	
8
        // This is a hack to help test the AI.

9
        if (mStandStill) return;
10
    	
11
        // Does the puck has an owner?

12
        if (getPuckOwner() != null) {
13
            // Yeah, it has.

14
            mBrain.popState();
15
16
            if (doesMyTeamHaveThePuck()) {
17
                // My team just got the puck, it's attack time!

18
                mBrain.pushState(attack);
19
            } else {
20
                // The opponent team got the puck, let's try to steal it.

21
                mBrain.pushState(stealPuck);
22
            }
23
        } else if (distance(this, aPuck) < 150) {
24
            // The puck has no owner and it is nearby. Let's pursue it.

25
            mBrain.popState();
26
            mBrain.pushState(pursuePuck);
27
        }
28
    }
29
    
30
    private function attack() :void {
31
    }
32
    
33
    private function stealPuck() :void {
34
    }
35
    
36
    private function pursuePuck() :void {
37
    }
38
}

Mari kita lanjutkan dengan implementasi kedudukan lain.

Mengejar Puck

Sekarang atlet telah mendapatkan beberapa persepsi tentang lingkungan dan dapat beralih dari kedudukan idle ke kedudukan manapun, mari fokus untuk mengejar puck saat tidak memiliki pemilik.

Seorang atlet akan beralih pursuePuck untuk segera setelah pertandingan dimulai, karena puck itu akan ditempatkan di tengah arena tanpa pemilik. Kedudukan pursuePuck (mengejar Puck) memiliki tiga transisi:

Kedudukan pursuePuck (mengejar puck) dan transisinya di FSM menggambarkan proses penyerangan. 

Transisi pertama adalah puck yang terlalu jauh (puck is too far away), dan mencoba untuk mensimulasikan apa yang terjadi dalam permainan nyata mengenai mengejar puck itu. Untuk alasan strategis, biasanya atlet yang paling dekat dengan puckadalah yang mencoba menangkapnya, sementara yang lain menunggu atau mencoba membantu.

Tanpa beralih ke siaga idle saat puck-nya jauh, setiap atlet AI-dikontrol akan mengejar puckpada saat yang sama, bahkan jika mereka jauh dari itu. Dengan mengecek jarak antara atlit dan puck-nya, pursuePuck keluar dari otak dan mendorongnya pada kedudukan siaga idle saat puck-nya terlalu jauh, yang berarti atlet itu "menyerah" mengejar puck-nya:

1
class Athlete {
2
    // (...)

3
4
    private function pursuePuck() :void {
5
        var aPuck :Puck = getPuck();
6
	
7
        if (distance(this, aPuck) > 150) {
8
            // Puck is too far away from our current position, so let's give up

9
            // pursuing the puck and hope someone will be closer to get the puck

10
            // for us.

11
            mBrain.popState();
12
            mBrain.pushState(idle);
13
        } else {
14
            // The puck is close, let's try to grab it.

15
        }
16
    }
17
    
18
    // (...)

19
}

Saat puck sudah dekat, atlet harus mengejarnya, yang bisa dengan mudah diraih dengan seek behavior . Dengan menggunakan posisi puck sebagai tujuan pencarian, atlet akan dengan anggun mengejar puck-nya dan menyesuaikan lintasannya saat puck-nya bergerak:

1
class Athlete {
2
    // (...)
3
    private function pursuePuck() :void {
4
        var aPuck :Puck = getPuck();
5
	
6
        mBoid.steering = mBoid.steering + mBoid.separation();
7
	
8
        if (distance(this, aPuck) > 150) {
9
            // Puck is too far away from our current position, so let's give up
10
            // pursuing the puck and hope someone will be closer to get the puck
11
            // for us.
12
            mBrain.popState();
13
            mBrain.pushState(idle);
14
        } else {
15
            // The puck is close, let's try to grab it.
16
            if (aPuck.owner == null) {
17
                // Nobody has the puck, it's our chance to seek and get it!
18
                mBoid.steering = mBoid.steering + mBoid.seek(aPuck.position);
19
		
20
            } else {
21
                // Someone just got the puck. If the new puck owner belongs to my team,
22
                // we should switch to 'attack', otherwise I should switch to 'stealPuck'
23
                // and try to get the puck back.
24
                mBrain.popState();
25
                mBrain.pushState(doesMyTeamHaveThePuck() ? attack : stealPuck);
26
            }
27
        }
28
    }
29
}

Dua transisi sisa di kedudukan persuePuck, tim memiliki puck (team has puck) dan lawan memiliki puck (opponent has the puck, terkait dengan puck yang tertangkap saat proses pengerjaan. Jika seseorang menangkap kepingnya, atlet tersebut harus memunculkan kedudukan persuePuck dan mendorong yang baru ke otak.

kedudukan yang harus didorong tergantung pada kepemilikan puck. Jika panggilan terhadap doesMyTeamHaveThePuck () mengembalikan nilai true, itu berarti bahwa rekan setimnya mendapatkan puck, jadi atlet harus mendorong serangan, yang berarti sudah waktunya berhenti mengejar puck dan mulai bergerak menuju sasaran lawan.  Jika lawan mendapat puck, atlet harus mendorongstealPuck, yang akan membuat tim mencoba mengembalikan puck-nya.

Sebagai peningkatan kecil, atlet tidak boleh terlalu dekat satu sama lain selama kedudukan pursuePuck state, karena gerakan mengejar yang "ramai" tidaklah wajar. Menambahkan separation ke kedudukan steering force (baris 6 pada kode di atas) memastikan atlet akan menjaga jarak minimum di antara mereka.

Hasilnya adalah tim yang mampu mengejar puck-nya. Demi pengujian, dalam demo ini, puck ditempatkan di tengah arena setiap beberapa detik, untuk membuat atlet terus bergerak:

Menyerang Dengan Puck

Setelah mendapatkan puck-nya, seorang atlet dan timnya harus bergerak menuju gawang lawan untuk mencetak gol. Itulah tujuan dari serangan tersebut:

Status serangan dan transisinya di FSM menggambarkan proses penyerangan

Kedudukan menyerang (attack) hanya memiliki dua transisi: lawan memiliki puck dan puck tidak memiliki pemilik. Karena kedudukan semata-mata dirancang untuk membuat atlet bergerak menuju gawang lawan, tidak ada gunanya tetap menyerang jika puck-nya tidak berada di bawah kepemilikan tim lagi.

Mengenai pergerakan menuju gawang lawan: atlit pembawa puck (leader) dan rekan tim yang membantunya harus bersikap berbeda. Leader harus mencapai gawang lawan, dan rekan tim harus membantunya di sepanjang jalan.

Hal ini dapat diimplementasikan dengan memeriksa apakah atlet yang menjalankan kode memiliki puck:

1
class Athlete {
2
    // (...)

3
    private function attack() :void {
4
        var aPuckOwner :Athlete = getPuckOwner();
5
	
6
        // Does the puck have an owner?

7
        if (aPuckOwner != null) {
8
            // Yeah, it has. Let's find out if the owner belongs to the opponents team.

9
            if (doesMyTeamHaveThePuck()) {
10
                if (amIThePuckOwner()) {
11
                    // My team has the puck and I am the one who has it! Let's move

12
                    // towards the opponent's goal.

13
                    mBoid.steering = mBoid.steering + mBoid.seek(getOpponentGoalPosition());
14
                    
15
                } else {
16
                    // My team has the puck, but a teammate has it. Let's just follow him

17
                    // to give some support during the attack.

18
                    mBoid.steering = mBoid.steering + mBoid.followLeader(aPuckOwner.boid);
19
                    mBoid.steering = mBoid.steering + mBoid.separation();
20
                }
21
            } else {
22
                // The opponent has the puck! Stop the attack

23
                // and try to steal it.

24
                mBrain.popState();
25
                mBrain.pushState(stealPuck);
26
            }
27
        } else {
28
            // Puck has no owner, so there is no point to keep

29
            // attacking. It's time to re-organize and start pursuing the puck.

30
            mBrain.popState();
31
            mBrain.pushState(pursuePuck);
32
        }
33
    }
34
}

Jika amIThePuckOwner () memberikan nilai true (baris 10), atlet yang menjalankan kode memiliki puck. Dalam hal ini, dia hanya akan mencari posisi gawang lawan. Cukup banyak logika yang sama yang digunakan untuk mengejar puck pada keduukan persuePuck

Jika amIThePuckOwner () memberikan nilai false, atlet tidak memiliki puck, jadi dia harus membantu pemimpinnya (leader). Membantu pemimpin adalah tugas yang rumit, jadi kita akan menyederhanakannya. Seorang atlet akan membantu pemimpin hanya dengan mencari posisi di depannya:

Rekan kerja membantu pemimpin (leader). 

Ketika pemimpin bergerak, ia akan dikelilingi oleh rekan tim saat mereka mengikuti titik terdepan.  Ini memberi pemimpin beberapa pilihan untuk meloloskan puck itu jika ada masalah. Seperti dalam permainan nyata, rekan setimnya di sekitarnya juga harus tetap berada di luar jalur pimpinan.

Pola bantuan ini dapat dicapai dengan menambahkan sedikit modifikasi versi pemimpin mengikuti perilaku (baris 18). Satu-satunya perbedaannya adalah bahwa atlet akan mengikuti satu poin di depan pemimpin, bukan satu di belakangnya seperti yang pada awalnya diterapkan dalam perilaku itu.

Atlet yang membantu pemimpin juga harus menjaga jarak minimum antara satu sama lain. Itu diimplementasikan dengan menambahkan gaya pemisah (garis 19). 

Hasilnya adalah sebuah tim mampu bergerak menuju gawang lawan, tanpa berkerumun dan saat mensimulasikan sebuah gerakan serangan yang dibantu:

Meningkatkan Dukungan Serangan

Implementasi kedudkan menyerang attack saat ini cukup baik untuk beberapa situasi, namun memiliki kekurangan. Saat seseorang menangkap puck-nya, dia menjadi pemimpin dan segera diikuti oleh rekan tim.

Apa yang terjadi jika sang pemimpin bergerak menuju gawangnya sendiri saat dia menangkap puck-nya? Lihatlah lebih dekat demo di atas dan perhatikan pola tidak wajar saat rekan tim mulai mengikuti pemimpinnya.

Ketika pemimpin menangkap puck, perilaku pencarian (seeking behavior) memerlukan beberapa waktu untuk memperbaiki lintasan pemimpin dan secara efektif membuat dia bergerak menuju gawang lawan. Bahkan ketika pemimpinnya "bermanuver", rekan tim akan mencoba untuk mencari poin ahead, yang berarti mereka akan bergerak menuju gawang mereka sendiri (atau tempat yang dituju pemimpin).

Saat pemimpin akhirnya dalam posisi dan siap bergerak menuju gawang lawan, rekan tim akan "bermanuver" untuk mengikuti sang pemimpin. Pemimpin kemudian akan bergerak tanpa dukungan rekan setimnya selama yang lain menyesuaikan lintasan mereka.

Cacat ini bisa diperbaiki dengan memeriksa apakah rekan setimnya berada di depan pemimpin saat tim memulihkan puck-nya. Di sini, kondisi "depan" berarti "lebih dekat ke gawang lawan":

1
class Athlete {
2
    // (...)

3
    private function isAheadOfMe(theBoid :Boid) :Boolean {
4
        var aTargetDistance :Number = distance(getOpponentGoalPosition(), theBoid);
5
        var aMyDistance :Number = distance(getOpponentGoalPosition(), mBoid.position);
6
	
7
        return aTargetDistance <= aMyDistance;
8
    }
9
10
    private function attack() :void {
11
        var aPuckOwner :Athlete = getPuckOwner();
12
	
13
        // Does the puck have an owner?

14
        if (aPuckOwner != null) {
15
            // Yeah, it has. Let's find out if the owner belongs to the opponents team.

16
            if (doesMyTeamHaveThePuck()) {
17
                if (amIThePuckOwner()) {
18
                    // My team has the puck and I am the one who has it! Let's move

19
                    // towards the opponent's goal.

20
                    mBoid.steering = mBoid.steering + mBoid.seek(getOpponentGoalPosition());
21
                    
22
                } else {
23
                    // My team has the puck, but a teammate has it. Is he ahead of me?

24
                    if (isAheadOfMe(aPuckOwner.boid)) {
25
                        // Yeah, he is ahead of me. Let's just follow him to give some support

26
                        // during the attack.

27
                        mBoid.steering = mBoid.steering + mBoid.followLeader(aPuckOwner.boid);
28
                        mBoid.steering = mBoid.steering + mBoid.separation();
29
                    } else {
30
                        // Nope, the teammate with the puck is behind me. In that case

31
                        // let's hold our current position with some separation from the

32
                        // other, so we prevent crowding.

33
                        mBoid.steering = mBoid.steering + mBoid.separation();
34
                    }
35
                }
36
            } else {
37
                // The opponent has the puck! Stop the attack

38
                // and try to steal it.

39
                mBrain.popState();
40
                mBrain.pushState(stealPuck);
41
            }
42
        } else {
43
            // Puck has no owner, so there is no point to keep

44
            // attacking. It's time to re-organize and start pursuing the puck.

45
            mBrain.popState();
46
            mBrain.pushState(pursuePuck);
47
        }
48
    }
49
}

Jika pemimpin (pemilik puck) berada di depan atlet yang menjalankan kodenya, maka atlet harus mengikuti pemimpin seperti yang dia lakukan sebelumnya (baris 27 dan 28). Jika pemimpin berada di belakangnya, atlet harus memegang posisi saat ini, menjaga jarak minimum dengan atlit yang lain (baris 33).

Hasilnya sedikit lebih meyakinkan daripada implementasi serangan awal:

Tips: Dengan menyesuaikan perhitungan jarak jauh dan perbandingan dengan metode isAheadOfMe (), sangat memungkinkan untuk  memodifikasi cara atlit memegang posisi mereka saat ini.

Merebut Puck

kedudukan terakhir dalam proses penyerangan adalah merebut puck (stealPuck), yang menjadi aktif saat tim lawan memiliki puck. Tujuan utama dari stealpuckk adalah untuk mencuri puck dari lawan yang membawanya, sehingga tim bisa mulai menyerang lagi:

Kedudukan stealPuck dan transisinya di FSM menggambarkan proses penyerangan.

 Karena gagasan di balik kedudukancini adalah mencuri puck dari lawan, jika puck itu dipulihkan oleh tim atau menjadi bebas (yaitu tidak memiliki pemilik), stealPuck akan muncul dari otak dan mendorong kedudukan yang benar untuk mengatasi situasi baru:

1
class Athlete {
2
    // (...)

3
    private function stealPuck() :void {
4
        // Does the puck have any owner?

5
        if (getPuckOwner() != null) {
6
            // Yeah, it has, but who has it?

7
            if (doesMyTeamHaveThePuck()) {
8
                // My team has the puck, so it's time to stop trying to steal

9
                // the puck and start attacking.

10
                mBrain.popState();
11
                mBrain.pushState(attack);
12
            } else {
13
                // An opponent has the puck.

14
                var aOpponentLeader :Athlete = getPuckOwner();
15
			
16
                // Let's pursue him while mantaining a certain separation from

17
                // the others to avoid that everybody will ocuppy the same

18
                // position in the pursuit.

19
                mBoid.steering = mBoid.steering + mBoid.pursuit(aOpponentLeader.boid);
20
                mBoid.steering = mBoid.steering + mBoid.separation();
21
            }
22
        } else {
23
            // The puck has no owner, it is probably running freely in the rink.

24
            // There is no point to keep trying to steal it, so let's finish the 'stealPuck' state

25
            // and switch to 'pursuePuck'.

26
            mBrain.popState();
27
            mBrain.pushState(pursuePuck);
28
        }
29
    }
30
}

Jika puck memiliki pemilik dan dia termasuk dalam tim lawan, atlet harus mengejar pemimpin lawan dan mencoba mencuri puck-nya.  Untuk mengejar pemimpin lawan, seorang atlet harus meramalkan di mana dia berada dalam waktu dekat, jadi dia bisa dicegat dalam lintasannya. Itu berbeda dengan hanya mencari pemimpin lawan.

Untungnya, ini bisa dengan mudah diraih dengan  pursue behavior  (line 19). Dengan menggunakan kekuatan pengejaran dalam kedudukan stealPuck, atlet akan mencoba mencegat pemimpin lawan, bukan hanya mengikutinya:

Mencegah Gerakan Merebut yang Penuh Sesak

implementasi saat ini dari stealPuck bekerja, namun dalam permainan nyata hanya satu atau dua atlet yang mendekati pemimpin lawan untuk mencuri puck-nya. Anggota tim lainnya tetap berada di daerah sekitar untuk membantu, yang mencegah pola pencurian yang penuh sesak.

Hal ini dapat diperbaiki dengan menambahkan pemeriksaan jarak (garis 17) sebelum pengejaran pemimpin lawan:

1
class Athlete {
2
    // (...)

3
    private function stealPuck() :void {
4
        // Does the puck have any owner?

5
        if (getPuckOwner() != null) {
6
            // Yeah, it has, but who has it?

7
            if (doesMyTeamHaveThePuck()) {
8
                // My team has the puck, so it's time to stop trying to steal

9
                // the puck and start attacking.

10
                mBrain.popState();
11
                mBrain.pushState(attack);
12
            } else {
13
                // An opponent has the puck.

14
                var aOpponentLeader :Athlete = getPuckOwner();
15
			
16
                // Is the opponent with the puck close to me?

17
                if (distance(aOpponentLeader, this) < 150) {
18
                    // Yeah, he is close! Let's pursue him while mantaining a certain

19
                    // separation from the others to avoid that everybody will ocuppy the same

20
                    // position in the pursuit.

21
                    mBoid.steering = mBoid.steering.add(mBoid.pursuit(aOpponentLeader.boid));
22
                    mBoid.steering = mBoid.steering.add(mBoid.separation(50));
23
				
24
                } else {
25
                    // No, he is too far away. In the future, we will switch

26
                    // to 'defend' and hope someone closer to the puck can

27
                    // steal it for us.

28
                    // TODO: mBrain.popState();

29
                    // TODO: mBrain.pushState(defend);

30
                }
31
            }
32
        } else {
33
            // The puck has no owner, it is probably running freely in the rink.

34
            // There is no point to keep trying to steal it, so let's finish the 'stealPuck' state

35
            // and switch to 'pursuePuck'.

36
            mBrain.popState();
37
            mBrain.pushState(pursuePuck);
38
        }
39
    }
40
}

Alih-alih membabi buta mengejar pemimpin lawan, seorang atlet akan memeriksa apakah jarak antara dia dan pemimpin lawan kurang dari, katakanlah, 150. Jika itu true, pengejaran itu terjadi secara normal, tapi jika jaraknya lebih dari 150, itu berarti atlet terlalu jauh dari pimpinan lawan.

Jika itu terjadi, tidak ada gunanya terus mencoba mencuri puck-nya, karena terlalu jauh dan mungkin ada rekan setimnya yang sudah mencoba melakukan hal yang sama.  Pilihan terbaik adalah munculkan stealPuck dari otak dan dorong kedudukan pertahanan (yang akan dijelaskan di tutorial selanjutnya). Untuk saat ini, seorang atlet hanya akan memegang posisi saat ini jika pemimpin lawan terlalu jauh. 

Hasilnya adalah pola perebutan yang lebih meyakinkan dan alami (tidak berkerumun):

Menghindari Lawan Ketika Menyerang

Ada satu trik terakhir yang harus dipelajari atlet agar bisa menyerang secara efektif. Saat ini, mereka bergerak menuju gawang lawan tanpa mempertimbangkan lawan di sepanjang jalan. Lawan harus dilihat sebagai ancaman, dan harus dihindari.

 Dengan menggunakan perilaku penghindaran tabrakan (collision avoidance), atlet bisa menghindari lawan saat mereka bergerak:

Perilaku menghindari tabrakan digunakan untuk menghindari lawan.

Lawan akan dilihat sebagai rintangan melingkar. Sebagai hasil dari sifat dinamis dari perilaku kemudi, yang diperbarui dalam setiap loop permainan, pola penghindaran akan berjalan dengan anggun dan lancar untuk memindahkan hambatan (yang terjadi di sini).

Untuk membuat atlit menghindari lawan (rintangan), satu baris harus ditambahkan ke kedudukan penyerangan (baris 14):

1
class Athlete {
2
    // (...)

3
    private function attack() :void {
4
        var aPuckOwner :Athlete = getPuckOwner();
5
	
6
        // Does the puck have an owner?

7
        if (aPuckOwner != null) {
8
            // Yeah, it has. Let's find out if the owner belongs to the opponents team.

9
            if (doesMyTeamHaveThePuck()) {
10
                if (amIThePuckOwner()) {
11
                    // My team has the puck and I am the one who has it! Let's move

12
                    // towards the opponent's goal, avoding any opponents along the way.

13
                    mBoid.steering = mBoid.steering + mBoid.seek(getOpponentGoalPosition());
14
                    mBoid.steering = mBoid.steering + mBoid.collisionAvoidance(getOpponentTeam().members);
15
		
16
                } else {
17
                    // My team has the puck, but a teammate has it. Is he ahead of me?

18
                    if (isAheadOfMe(aPuckOwner.boid)) {
19
                        // Yeah, he is ahead of me. Let's just follow him to give some support

20
                        // during the attack.

21
                        mBoid.steering = mBoid.steering + mBoid.followLeader(aPuckOwner.boid);
22
                        mBoid.steering = mBoid.steering + mBoid.separation();
23
                    } else {
24
                        // Nope, the teammate with the puck is behind me. In that case

25
                        // let's hold our current position with some separation from the

26
                        // other, so we prevent crowding.

27
                        mBoid.steering = mBoid.steering + mBoid.separation();
28
                    }
29
                }
30
            } else {
31
                // The opponent has the puck! Stop the attack

32
                // and try to steal it.

33
                mBrain.popState();
34
                mBrain.pushState(stealPuck);
35
            }
36
        } else {
37
            // Puck has no owner, so there is no point to keep

38
            // attacking. It's time to re-organize and start pursuing the puck.

39
            mBrain.popState();
40
            mBrain.pushState(pursuePuck);
41
        }
42
    }
43
}

Baris ini akan menambahkan kekuatan  penghindaran tabrakan ke atlit, yang akan dikombinasikan dengan kekuatan yang sudah ada. Alhasil, atlit akan menghindari rintangan sekaligus mencari gawang lawan.

Berikut adalah demonstrasi atlet yang menjalankan kedudukan menyerang (attack). Lawan tidak bergerak untuk menyoroti perilaku penghindaran tabrakan:

Kesimpulan

Tutorial ini menjelaskan penerapan pola serangan yang digunakan oleh atlit untuk merebut dan membawa puck ke arah gawang lawan. Dengan menggunakan kombinasi perilaku kemudi (steering behavior), atlet kini mampu melakukan pola pergerakan yang kompleks, seperti mengikuti seorang pemimpin atau mengejar lawan dengan puck.

Seperti yang telah dibahas sebelumnya, implementasi serangan tersebut bertujuan untuk mensimulasikan apa yang dilakukan manusia, sehingga hasilnya merupakan perkiraan dari sebuah game yang sebenarnya. Dengan secara individual mengutak-atik bagian kedudukan yang menyusun serangan, Anda dapat menghasilkan simulasi yang lebih baik, atau yang sesuai dengan kebutuhan Anda.

Pada tutorial selanjutnya, Anda akan belajar bagaimana membuat atlet bertahan. AI akan menjadi fitur lengkap, mampu menyerang dan bertahan, menghasilkan kecocokan dengan 100% tim yang dikendalikan AI yang bermain satu sama lain.

Referensi

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 Game Development 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.