Indonesian (Bahasa Indonesia) translation by Ari Ana (you can also view the original English article)
Dalam tutorial ini saya ingin menunjukkan kepada Anda betapa mudahnya membuat permainan "Snake" klasik dalam Flash. Saya akan mencoba menjelaskan semuanya dengan mudah, selangkah demi selangkah, sehingga Anda dapat mengembangkan permainan lebih lanjut untuk kebutuhan Anda! Permainan ini akan dikembangkan di AS3 dan saya akan menggunakan IDE FlashDevelop.
Perkenalan
Permainannya tidak akan rumit. Setiap kali kita menabrak dinding, itu akan memulai kembali permainannya. Setelah memakan apel, ular akan tumbuh, dan Apple 'baru' akan muncul. (Sebenarnya, itu akan menjadi apel yang sama, tapi saya akan menjelaskannya nanti.)
Salah satu aspek terpenting dari permainan ini adalah reaksi kode terhadap peristiwa KEY_DOWN. Ular hanya akan mengubah arahnya setelah tanda tick berlalu, tidak segera setelah penekanan tombol. Ini berarti bahwa, jika ular itu berjalan dengan benar, dan Anda menekan ke bawah dan kiri dengan sangat cepat, ular itu akan turun, bukan ke bawah DAN kiri. Tanpa 'fitur' ini ular akan memungkinkan kita untuk pergi ke kiri ketika kita berjalan ke kanan, yang berarti itu menghantam dirinya sendiri.
Mari Lihat Permainan Ini!
Mari kita lihat hasil akhir yang akan kita jalani:
Langkah 1: Membuat Proyek
Di FlashDevelop, buat Project baru, dan di dalam folder 'src' buat folder 'com'. Di folder 'com' buat kelas baru, dan beri nama 'Element.as'.
Atur dimensi proyek menjadi 600x600px.

Langkah 2: Tunggu... Apa itu Elemen?
Ular itu membentuk kotak biru, yang saya sebut elemen. Kita akan membuat Kelas Element, yang menggambar elemen. Apel merah juga akan menjadi elemen, jadi kita akan memperpanjang kode dengan beberapa baris lagi.
Oleh karena itu kita tidak akan membuat kelas baru untuk apel. (Tetapi jika Anda benar-benar ingin, Anda bisa.)
Langkah 3: Menulis Kelas Element
Kelas Element menciptakan persegi. Itu tidak menggambarnya di atas panggung, itu hanya menciptakannya. Titik registrasi elemen - posisi yang dimaksud oleh koordinat x dan y - berada di kiri atas.
Setelah membuka Element.as Anda akan melihat sesuatu seperti ini:
1 |
|
2 |
package com |
3 |
{
|
4 |
/**
|
5 |
* ...
|
6 |
* @author Fuszenecker Zsombor
|
7 |
*/
|
8 |
public class Element |
9 |
{
|
10 |
|
11 |
public function Element() |
12 |
{
|
13 |
|
14 |
}
|
15 |
|
16 |
}
|
17 |
}
|
Pertama kita membutuhkan ini untuk memperluas kelas Shape, jadi kita bisa menggunakan obyek graphics
untuk menggambar persegi. Setelah ini, buat dua variabel: satu untuk arah (jika itu bagian dari ular), dan satu untuk nilai skor (jika itu apel), dan kemudian ubah parameter fungsi constructor:
1 |
|
2 |
package com |
3 |
{
|
4 |
import flash.display.Shape; |
5 |
|
6 |
public class Element extends Shape |
7 |
{
|
8 |
protected var _direction:String; |
9 |
//IF IT IS AN APPLE ->
|
10 |
protected var _catchValue:Number; |
11 |
|
12 |
//color,alpha,width,height
|
13 |
public function Element(_c:uint,_a:Number,_w:Number,_h:Number) |
14 |
{
|
15 |
|
16 |
}
|
17 |
}
|
18 |
}
|
Sekarang isi fungsi dengan beberapa kode:
1 |
|
2 |
package com |
3 |
{
|
4 |
import flash.display.Shape; |
5 |
|
6 |
public class Element extends Shape |
7 |
{
|
8 |
protected var _direction:String; |
9 |
//IF IT IS AN APPLE ->
|
10 |
protected var _catchValue:Number; |
11 |
|
12 |
//color,alpha,width,height
|
13 |
public function Element(_c:uint,_a:Number,_w:Number,_h:Number) |
14 |
{
|
15 |
graphics.lineStyle(0, _c, _a); |
16 |
graphics.beginFill(_c, _a); |
17 |
graphics.drawRect(0, 0, _w, _h); |
18 |
graphics.endFill(); |
19 |
|
20 |
_catchValue = 0; |
21 |
}
|
22 |
}
|
23 |
}
|
Sekarang, setiap kali kita membuat elemen, itu akan menggambar persegi panjang dan mengatur nilai skor dari elemen ke 0 secara default. (Ia tidak akan menempatkan persegi panjang di atas panggung, itu hanya menggambarnya di dalam dirinya sendiri. Perhatikan bahwa kita belum memanggil fungsi addChild()
.)
Mari selesaikan kelas ini dan akhirnya kita bisa menguji seberapa banyak yang sudah kita lakukan:
1 |
|
2 |
package com |
3 |
{
|
4 |
import flash.display.Shape; |
5 |
|
6 |
public class Element extends Shape |
7 |
{
|
8 |
protected var _direction:String; |
9 |
//IF IT IS AN APPLE ->
|
10 |
protected var _catchValue:Number; |
11 |
|
12 |
//color,alpha,width,height
|
13 |
public function Element(_c:uint,_a:Number,_w:Number,_h:Number) |
14 |
{
|
15 |
graphics.lineStyle(0, _c, _a); |
16 |
graphics.beginFill(_c, _a); |
17 |
graphics.drawRect(0, 0, _w, _h); |
18 |
graphics.endFill(); |
19 |
|
20 |
_catchValue = 0; |
21 |
}
|
22 |
|
23 |
//ONLY USED IN CASE OF A PART OF THE SNAKE
|
24 |
public function set direction(value:String):void |
25 |
{
|
26 |
_direction = value; |
27 |
}
|
28 |
public function get direction():String |
29 |
{
|
30 |
return _direction; |
31 |
}
|
32 |
|
33 |
//ONLY USED IN CASE OF AN APPLE
|
34 |
public function set catchValue(value:Number):void |
35 |
{
|
36 |
_catchValue = value; |
37 |
}
|
38 |
public function get catchValue():Number |
39 |
{
|
40 |
return _catchValue; |
41 |
}
|
42 |
}
|
43 |
|
44 |
}
|
Kita menciptakan empat fungsi untuk mengubah arah dan nilai dari apel. Kita mencapai ini dengan menggunakan setter dan getter. Lebih lanjut tentang Setter/Getter di artikel ini!
Langkah 4: Menguji Kelas Element
Buka Main.as sekarang.
Impor kelas com.Element
dan buat Element dalam fungsi init()
:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.display.Sprite; |
5 |
import flash.events.Event; |
6 |
import com.Element; |
7 |
|
8 |
public class Main extends Sprite |
9 |
{
|
10 |
public function Main() |
11 |
{
|
12 |
if(stage) |
13 |
addEventListener(Event.ADDED_TO_STAGE, init); |
14 |
else
|
15 |
init(); |
16 |
}
|
17 |
|
18 |
private function init(e:Event = null):void |
19 |
{
|
20 |
var testElement:Element = new Element(0x00AAFF, 1, 10, 10); |
21 |
testElement.x = 50; |
22 |
testElement.y = 50; |
23 |
this.addChild(testElement); |
24 |
|
25 |
}
|
26 |
|
27 |
}
|
28 |
}
|
Pertama kita membuat variabel testElement
yang memegang elemen kita. Kita membuat Element baru dan menetapkan itu ke variabel testElement
kita. Perhatikan argumen yang kita kirimkan: pertama kita berikan warna, lalu alfa, lebar, dan tinggi. Jika Anda melihat pada fungsi Element di kelas Element, Anda dapat melihat bagaimana menggunakan data ini untuk menggambar persegi panjang.
Setelah membuat Element, kita memposisikannya dan meletakkannya di atas panggung!
Langkah 5: Mengatur Variabel
Lihatlah kode berikut. Saya menulis fungsi variabel di setelahnya (perhatikan bahwa kita mengimpor kelas yang diperlukan juga):
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.display.Sprite; |
5 |
import flash.text.TextField; |
6 |
import flash.utils.Timer; |
7 |
import flash.events.TimerEvent; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.events.KeyboardEvent; |
10 |
import flash.events.MouseEvent; |
11 |
import flash.events.Event; |
12 |
|
13 |
import com.Element; |
14 |
|
15 |
public class Main extends Sprite |
16 |
{
|
17 |
|
18 |
//DO NOT GIVE THESE VARS A VALUE HERE!
|
19 |
//Give them their values in the init() function.
|
20 |
private var snake_vector:Vector.<Element>; //the snake's parts are held in here |
21 |
private var markers_vector:Vector.<Object>; //the markers are held in here |
22 |
private var timer:Timer; |
23 |
private var dead:Boolean; |
24 |
private var min_elements:int; //holds how many parts the snake should have at the beginning |
25 |
private var apple:Element; //Our apple |
26 |
private var space_value:Number; //space between the snake's parts |
27 |
private var last_button_down:uint; //the keyCode of the last button pressed |
28 |
private var flag:Boolean; //is it allowed to change direction? |
29 |
private var score:Number; |
30 |
private var score_tf:TextField; //the Textfield showing the score |
31 |
|
32 |
public function Main() |
33 |
{
|
34 |
if(stage) |
35 |
addEventListener(Event.ADDED_TO_STAGE, init); |
36 |
else
|
37 |
init(); |
38 |
}
|
39 |
|
40 |
private function init(e:Event = null):void |
41 |
{
|
42 |
snake_vector = new Vector.<Element>; |
43 |
markers_vector = new Vector.<Object>; |
44 |
space_value = 2; //There will be 2px space between every Element |
45 |
timer = new Timer(50); //Every 50th millisecond, the moveIt() function will be fired! This will set the SPEED of the snake |
46 |
dead = false; |
47 |
min_elements = 10; //We will begin with 10 elements. |
48 |
apple = new Element(0xFF0000, 1, 10, 10); //red, not transparent, width:10, height: 10; |
49 |
apple.catchValue = 0; //pretty obvious - the score of the apple |
50 |
last_button_down = Keyboard.RIGHT; //The first direction of the snake is set in this variable |
51 |
score = 0; |
52 |
score_tf = new TextField(); //this is the TextField which shows our score. |
53 |
this.addChild(score_tf); |
54 |
}
|
55 |
}
|
56 |
}
|
Variabel yang paling penting adalah snake_vector
. Kita akan menempatkan setiap Element dari ular di Vector ini.
Lalu ada markers_vector
. Kita akan menggunakan penanda untuk mengatur arah dari bagian-bagian ular. Setiap obyek dalam Vector ini akan memiliki posisi dan tipe. Tipe ini akan memberi tahu kita apakah ular harus pergi ke kanan, kiri, atas, atau ke bawah setelah 'memukul' obyek. (Mereka tidak akan bertabrakan, hanya posisi penanda dan bagian ular yang akan diperiksa.)
Sebagai contoh, jika kita menekan DOWN, sebuah obyek akan dibuat. X dan y dari obyek ini akan menjadi koordinat x dan y kepala ular, dan jenisnya akan "Down". Setiap kali posisi salah satu Element ular sama dengan objek ini, arah elemen ular akan diatur ke "Down".
Silakan baca komentar di sebelah variabel untuk memahami apa yang dilakukan variabel lain!
Langkah 6: Menulis Fungsi attachElement()
Fungsi attachElement()
akan mengambil empat parameter: elemen ular baru, koordinat x dan y, dan arah bagian terakhir dari ular.
1 |
|
2 |
private function attachElement(who:Element,lastXPos:Number = 0,lastYPos:Number = 0,dirOfLast:String = "R"):void |
3 |
{
|
4 |
|
5 |
}
|
Sebelum kita meletakkan elemen di atas panggung kita harus memposisikannya. Tetapi untuk ini kita memerlukan arah elemen terakhir ular, untuk mengetahui apakah elemen baru harus berada di atas, di bawah, atau di samping ini.
Setelah memeriksa arah dan mengatur posisi, kita bisa menambahkannya ke panggung.
1 |
|
2 |
private function attachElement(who:Element,lastXPos:Number = 0,lastYPos:Number = 0,dirOfLast:String = "R"):void |
3 |
{
|
4 |
if (dirOfLast == "R") |
5 |
{
|
6 |
who.x = lastXPos - snake_vector[0].width - space_value; |
7 |
who.y = lastYPos; |
8 |
}
|
9 |
else if(dirOfLast == "L") |
10 |
{
|
11 |
who.x = lastXPos + snake_vector[0].width + space_value; |
12 |
who.y = lastYPos; |
13 |
}
|
14 |
else if(dirOfLast == "U") |
15 |
{
|
16 |
who.x = lastXPos; |
17 |
who.y = lastYPos + snake_vector[0].height + space_value; |
18 |
}
|
19 |
else if(dirOfLast == "D") |
20 |
{
|
21 |
who.x = lastXPos; |
22 |
who.y = lastYPos - snake_vector[0].height - space_value; |
23 |
}
|
24 |
this.addChild(who); |
25 |
}
|
Sekarang kita dapat menggunakan fungsi ini dalam fungsi init()
:
1 |
|
2 |
for(var i:int=0;i<min_elements;++i) |
3 |
{
|
4 |
snake_vector[i] = new Element(0x00AAFF,1,10,10); |
5 |
snake_vector[i].direction = "R"; //The starting direction of the snake |
6 |
if (i == 0)//first snake element |
7 |
{
|
8 |
//you have to place the first element on a GRID. (now: 0,0)
|
9 |
//[possible x positions: (snake_vector[0].width+space_value)*<UINT> ]
|
10 |
attachElement(snake_vector[i],0,0,snake_vector[i].direction) |
11 |
snake_vector[0].alpha = 0.7; |
12 |
}
|
13 |
else
|
14 |
{
|
15 |
attachElement(snake_vector[i], snake_vector[i - 1].x, snake_vector[i - 1].y, snake_vector[i - 1].direction); |
16 |
}
|
17 |
}
|
Kita membuat 10 Element pertama, dan mengatur arah mereka ke 'R' (kanan). Jika ini adalah elemen pertama, kita memanggil attachElement()
dan kita mengubah alpha-nya sedikit (jadi "head" adalah warna yang sedikit lebih terang).
Jika Anda ingin mengatur posisi di tempat lain, maka ingatlah hal-hal berikut: ular harus diletakkan di atas grid, jika tidak maka akan terlihat buruk dan tidak akan berfungsi. Jika Anda ingin mengubah posisi x dan y Anda dapat melakukannya dengan cara berikut:
Mengatur posisi x: (snake_vector[0].width+space_value)*[UINT]
, di mana Anda harus mengganti [UINT] dengan bilangan bulat positif.
Mengatur posisi y: (snake_vector[0].height+space_value)*[UINT]
, di mana Anda harus mengganti [UINT] dengan bilangan bulat positif.
Mari kita ubah ke ini:
1 |
|
2 |
if (i == 0)//first snake element |
3 |
{
|
4 |
//you have to place the first element on a GRID. (now: 0,0)
|
5 |
//[possible x positions: (snake_vector[0].width+space_value)*<UINT>]
|
6 |
attachElement( |
7 |
snake_vector[i], |
8 |
(snake_vector[0].width+space_value)*20, |
9 |
(snake_vector[0].height+space_value)*10, |
10 |
snake_vector[i].direction |
11 |
); |
12 |
snake_vector[0].alpha = 0.7; |
13 |
}
|
Dan elemen pertama ular diatur ke ruang 20 di x-grid dan 10 ruang di y-grid.
Inilah yang telah kita dapat sejauh ini:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.display.Sprite; |
5 |
import flash.text.TextField; |
6 |
import flash.utils.Timer; |
7 |
import flash.events.TimerEvent; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.events.KeyboardEvent; |
10 |
import flash.events.MouseEvent; |
11 |
import flash.events.Event; |
12 |
|
13 |
import com.Element; |
14 |
|
15 |
public class Main extends Sprite |
16 |
{
|
17 |
|
18 |
//DO NOT GIVE THEM A VALUE HERE! Give them a value in the init() function
|
19 |
private var snake_vector:Vector.<Element>; //the snake's parts are held in here |
20 |
private var markers_vector:Vector.<Object>; //the markers are held in here |
21 |
private var timer:Timer; |
22 |
private var dead:Boolean; |
23 |
private var min_elements:int; //holds how many parts should the snake have at the beginning |
24 |
private var apple:Element; //Our apple |
25 |
private var space_value:Number; //space between the snake parts |
26 |
private var last_button_down:uint; //the keyCode of the last button pressed |
27 |
private var flag:Boolean; //is it allowed to change direction? |
28 |
private var score:Number; |
29 |
private var score_tf:TextField; //the Textfield showing the score |
30 |
|
31 |
public function Main() |
32 |
{
|
33 |
if(stage) |
34 |
addEventListener(Event.ADDED_TO_STAGE, init); |
35 |
else
|
36 |
init(); |
37 |
}
|
38 |
|
39 |
private function init(e:Event = null):void |
40 |
{
|
41 |
snake_vector = new Vector.<Element>; |
42 |
markers_vector = new Vector.<Object>; |
43 |
space_value = 2; |
44 |
timer = new Timer(50); //Every 50th millisecond, the moveIt() function will be fired! |
45 |
dead = false; |
46 |
min_elements = 10; //We will begin with 10 elements. |
47 |
apple = new Element(0xFF0000, 1,10, 10); //red, not transparent, width:10, height: 10; |
48 |
apple.catchValue = 0; //pretty obvious |
49 |
last_button_down = Keyboard.RIGHT; //The first direction of the snake is set in this variable |
50 |
score = 0; |
51 |
score_tf = new TextField(); //this is the TextField which shows our score. |
52 |
this.addChild(score_tf); |
53 |
|
54 |
for(var i:int=0;i<min_elements;++i) |
55 |
{
|
56 |
snake_vector[i] = new Element(0x00AAFF,1,10,10); |
57 |
snake_vector[i].direction = "R"; //The starting direction of the snake |
58 |
if (i == 0)//first snake element |
59 |
{
|
60 |
//you have to place the first element on a GRID. (now: 0,0) [possible x positions: (snake_vector[0].width+space_value)*<UINT> ]
|
61 |
attachElement(snake_vector[i], (snake_vector[0].width + space_value) * 20, (snake_vector[0].height + space_value) * 10, snake_vector[i].direction); |
62 |
snake_vector[0].alpha = 0.7; |
63 |
}
|
64 |
else
|
65 |
{
|
66 |
attachElement(snake_vector[i], snake_vector[i - 1].x, snake_vector[i - 1].y, snake_vector[i - 1].direction); |
67 |
}
|
68 |
}
|
69 |
}
|
70 |
|
71 |
private function attachElement(who:Element,lastXPos:Number = 0,lastYPos:Number = 0,dirOfLast:String = "R"):void |
72 |
{
|
73 |
if (dirOfLast == "R") |
74 |
{
|
75 |
who.x = lastXPos - snake_vector[0].width - space_value; |
76 |
who.y = lastYPos; |
77 |
}
|
78 |
else if(dirOfLast == "L") |
79 |
{
|
80 |
who.x = lastXPos + snake_vector[0].width + space_value; |
81 |
who.y = lastYPos; |
82 |
}
|
83 |
else if(dirOfLast == "U") |
84 |
{
|
85 |
who.x = lastXPos; |
86 |
who.y = lastYPos + snake_vector[0].height + space_value; |
87 |
}
|
88 |
else if(dirOfLast == "D") |
89 |
{
|
90 |
who.x = lastXPos; |
91 |
who.y = lastYPos - snake_vector[0].height - space_value; |
92 |
}
|
93 |
this.addChild(who); |
94 |
}
|
95 |
}
|
96 |
}
|
Langkah 7: Menulis Fungsi placeApple()
Fungsi ini melakukan hal berikut:
- Ini memeriksa apakah apel itu tertangkap. Untuk ini kita akan menggunakan parameter
caught
, dan mengatur nilai defaultnya ketrue
, jika kita tidak melewatkan nilai apa pun sebagai parameter di masa depan. Jika tertangkap, itu menambah 10 nilai skor apel (jadi apel berikutnya bernilai lebih). - Setelah ini apel harus direposisi (kita tidak membuat apel baru) pada posisi grid acak.
- Jika ditempatkan pada ular, kita harus menempatkannya di tempat lain.
- Jika belum di atas panggung, kita letakkan di sana.
1 |
|
2 |
private function placeApple(caught:Boolean = true):void |
3 |
{
|
4 |
if (caught) |
5 |
apple.catchValue += 10; |
6 |
|
7 |
var boundsX:int = (Math.floor(stage.stageWidth / (snake_vector[0].width + space_value)))-1; |
8 |
var randomX:Number = Math.floor(Math.random()*boundsX); |
9 |
|
10 |
var boundsY:int = (Math.floor(stage.stageHeight/(snake_vector[0].height + space_value)))-1; |
11 |
var randomY:Number = Math.floor(Math.random()*boundsY); |
12 |
|
13 |
apple.x = randomX * (apple.width + space_value); |
14 |
apple.y = randomY * (apple.height + space_value); |
15 |
|
16 |
for(var i:uint=0;i<snake_vector.length-1;i++) |
17 |
{
|
18 |
if(snake_vector[i].x == apple.x && snake_vector[i].y == apple.y) |
19 |
placeApple(false); |
20 |
}
|
21 |
if (!apple.stage) |
22 |
this.addChild(apple); |
23 |
}
|
Akan ada beberapa matematika di sini, tetapi jika Anda memikirkannya, Anda harus memahami mengapa demikian. Hanya menggambar di beberapa kertas jika perlu.
-
boundsX
akan menampung berapa banyak elemen yang dapat digambar dalam satu baris. -
randomX
mengambilboundsX
ini, mengalikannya dengan Angka antara nol dan satu, dan membulatkan kebawah. JikaboundsX
adalah 12 dan Angka acak adalah 0,356, makafloor(12*0,356)
adalah 4, sehingga apel akan ditempatkan pada tempat ke-4 pada x-grid. -
boundsY
akan menampung berapa banyak elemen yang dapat digambar dalam satu kolom. -
randomY
mengambilboundsY
ini, mengalikannya dengan Angka antara nol dan satu, dan membulatkan kebawah. - Kemudian kita menetapkan posisi x dan y ke angka-angka ini.
Dalam perulangan for, kita memeriksa apakah posisi x dan y apel yang baru identik dengan salah satu elemen snake_vectors
. Jika demikian, kita memanggil fungsi placeApple()
lagi (fungsi rekursif), dan mengatur parameter ke false
. (Artinya apel itu tidak tertangkap, kita hanya perlu memposisikan ulang)
(apple.stage)
mengembalikan nilai true jika apel ada di panggung. kita menggunakan operator '!' untuk membalikkan nilai itu, jadi jika TIDAK di atas panggung, kita letakkan di sana.
Hal terakhir yang perlu kita lakukan adalah memanggil fungsi placeApple()
di akhir fungsi init()
.
1 |
|
2 |
private function init(e:Event = null):void |
3 |
{
|
4 |
/*
|
5 |
.
|
6 |
.
|
7 |
.
|
8 |
*/
|
9 |
|
10 |
placeApple(false); |
11 |
}
|
Perhatikan bahwa kita melewatkan false
sebagai parameter. Ini logis, karena kita tidak menangkap apel dalam fungsi init()
. Kita hanya akan menangkapnya dalam fungsi moveIt()
.
Sekarang hanya ada tiga fungsi untuk menulis: fungsi directionChanged()
, moveIt()
dan gameOver()
.
Langkah 8: Memulai Fungsi moveIt()
Fungsi moveIt()
bertanggung jawab untuk semua pergerakan. Fungsi ini akan memeriksa batas dan memeriksa apakah ada obyek pada posisi x dan y dari kepala ular. Itu juga akan mencari apel di posisi ini.
Untuk semua ini, kita akan menggunakan variabel timer kita.
Tambahkan dua baris lagi di akhir fungsi init()
:
1 |
|
2 |
timer.addEventListener(TimerEvent.TIMER,moveIt); |
3 |
timer.start(); |
Lihatlah komentar-komentar di source code, untuk melihat blok kode mana yang melakukan apa.
1 |
|
2 |
private function moveIt(e:TimerEvent):void |
3 |
{
|
4 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
5 |
{
|
6 |
//This code runs if the snakes heads position and the apples position are the same
|
7 |
}
|
8 |
|
9 |
if (snake_vector[0].x > stage.stageWidth-snake_vector[0].width || snake_vector[0].x < 0 || snake_vector[0].y > stage.stageHeight-snake_vector[0].height || snake_vector[0].y < 0) |
10 |
{
|
11 |
//This block runs if the snakes head is out of the stage (hitting the walls)
|
12 |
}
|
13 |
|
14 |
|
15 |
for (var i:int = 0; i < snake_vector.length; i++) |
16 |
{
|
17 |
/*
|
18 |
START OF FOR BLOCK
|
19 |
This whole 'for' block will run as many times, as many elements the snake has.
|
20 |
If there are four snake parts, this whole for cycle will run four times.
|
21 |
*/
|
22 |
|
23 |
if (snake_vector[i] != snake_vector[0] && (snake_vector[0].x == snake_vector[i].x && snake_vector[0].y == snake_vector[i].y)) |
24 |
{
|
25 |
//If the snakes heads position is the same as any of the snake parts, this block will run (Checking the collision with itself).
|
26 |
}
|
27 |
|
28 |
if (markers_vector.length > 0) |
29 |
{
|
30 |
//if there are direction markers, this code runs
|
31 |
}
|
32 |
|
33 |
|
34 |
var DIRECTION:String = snake_vector[i].direction; //getting the direction of the current snake element. |
35 |
switch (DIRECTION) |
36 |
{
|
37 |
//Sets the new position of the snakes part
|
38 |
}
|
39 |
|
40 |
/*
|
41 |
END OF FOR BLOCK
|
42 |
*/
|
43 |
}
|
44 |
|
45 |
}
|
Sekarang kita perlu mengkodekan pergerakannya. Untuk ini kita melompat ke blok switch, yang akan berjalan pada setiap bagian ular, karena perulangan for.
Pertama kita perlu memeriksa arah elemen saat ini.
1 |
|
2 |
switch (DIRECTION) |
3 |
{
|
4 |
case "R" : |
5 |
//Here we need to set the new x position for the current part
|
6 |
break; |
7 |
case "L" : |
8 |
//Here we need to set the new x position for the current part
|
9 |
break; |
10 |
case "D" : |
11 |
//Here we need to set the new y position for the current part
|
12 |
break; |
13 |
case "U" : |
14 |
//Here we need to set the new y position for the current part
|
15 |
break; |
16 |
}
|
Ketika arah bagian diatur ke "R", misalnya, kita perlu menambahkan sesuatu ke posisi X saat ini (nilai space_value
plus lebar bagian ular).
Dengan pemikiran ini, kita bisa mengisinya:
1 |
|
2 |
switch (DIRECTION) |
3 |
{
|
4 |
case "R" : |
5 |
snake_vector[i].x += snake_vector[i].width + space_value; |
6 |
break; |
7 |
case "L" : |
8 |
snake_vector[i].x -= snake_vector[i].width + space_value; |
9 |
break; |
10 |
case "D" : |
11 |
snake_vector[i].y += snake_vector[i].height + space_value; |
12 |
break; |
13 |
case "U" : |
14 |
snake_vector[i].y -= snake_vector[i].width + space_value; |
15 |
break; |
16 |
}
|
Setelah menguji kode, Anda harus melihat bahwa ular bergerak, dan pergi keluar dari panggung dan tidak pernah berhenti. (Anda mungkin perlu menyegarkan halaman - atau klik saja di sini untuk memuatnya di jendela baru.)
Jadi kita harus menghentikan ular itu
Langkah 9: Menulis Fungsi gameOver()
Fungsi ini akan menjadi yang terpendek. Kita hanya membersihkan panggung dan memulai kembali:
1 |
|
2 |
private function gameOver():void |
3 |
{
|
4 |
dead = true; |
5 |
timer.stop(); |
6 |
while (this.numChildren) |
7 |
this.removeChildAt(0); |
8 |
timer.removeEventListener(TimerEvent.TIMER,moveIt); |
9 |
init(); |
10 |
}
|
Itu saja. Kita mengatur variabel dead
menjadi true, menghentikan pergerakan dengan timer, menghapus setiap anak dari kelas dan memanggil fungsi init()
, seperti kita baru saja memulai permainan.
Sekarang, mari kita kembali ke fungsi moveIt()
.
Langkah 10: Melanjutkan Fungsi moveIt()
Kita akan menggunakan fungsi gameOver()
di dua tempat. Yang pertama adalah ketika kita memeriksa apakah kepala berada di luar batas, dan yang kedua adalah ketika ular menyerang dirinya sendiri:
1 |
|
2 |
private function moveIt(e:TimerEvent):void |
3 |
{
|
4 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
5 |
{
|
6 |
//This code runs if the snakes heads position and the apples position are the same
|
7 |
}
|
8 |
|
9 |
if (snake_vector[0].x > stage.stageWidth-snake_vector[0].width || snake_vector[0].x < 0 || snake_vector[0].y > stage.stageHeight-snake_vector[0].height || snake_vector[0].y < 0) |
10 |
{
|
11 |
gameOver(); |
12 |
}
|
13 |
|
14 |
|
15 |
for (var i:int = 0; i < snake_vector.length; i++) |
16 |
{
|
17 |
/*
|
18 |
START OF FOR BLOCK
|
19 |
This whole 'for' block will run as many times, as many elements the snake has.
|
20 |
If there are four snake parts, this whole for cycle will run four times.
|
21 |
*/
|
22 |
|
23 |
if (snake_vector[i] != snake_vector[0] && (snake_vector[0].x == snake_vector[i].x && snake_vector[0].y == snake_vector[i].y)) |
24 |
{
|
25 |
//If the snakes heads position is the same as any of the snake parts, this block will run
|
26 |
gameOver(); |
27 |
}
|
28 |
|
29 |
if (markers_vector.length > 0) |
30 |
{
|
31 |
//if there are direction markers, this code runs
|
32 |
}
|
33 |
|
34 |
|
35 |
var DIRECTION:String = snake_vector[i].direction; //getting the direction of the current snake element. |
36 |
switch (DIRECTION) |
37 |
{
|
38 |
case "R" : |
39 |
snake_vector[i].x += snake_vector[i].width + space_value; |
40 |
break; |
41 |
case "L" : |
42 |
snake_vector[i].x -= snake_vector[i].width + space_value; |
43 |
break; |
44 |
case "D" : |
45 |
snake_vector[i].y += snake_vector[i].height + space_value; |
46 |
break; |
47 |
case "U" : |
48 |
snake_vector[i].y -= snake_vector[i].width + space_value; |
49 |
break; |
50 |
}
|
51 |
|
52 |
/*
|
53 |
END OF FOR BLOCK
|
54 |
*/
|
55 |
}
|
56 |
|
57 |
}
|
Ini adalah kode yang kita miliki sekarang:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.display.Sprite; |
5 |
import flash.text.TextField; |
6 |
import flash.utils.Timer; |
7 |
import flash.events.TimerEvent; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.events.KeyboardEvent; |
10 |
import flash.events.MouseEvent; |
11 |
import flash.events.Event; |
12 |
|
13 |
import com.Element; |
14 |
|
15 |
public class Main extends Sprite |
16 |
{
|
17 |
|
18 |
//DO NOT GIVE THEM A VALUE HERE! Give them a value in the init() function
|
19 |
private var snake_vector:Vector.<Element>; //the snake's parts are held in here |
20 |
private var markers_vector:Vector.<Object>; //the markers are held in here |
21 |
private var timer:Timer; |
22 |
private var dead:Boolean; |
23 |
private var min_elements:int; //holds how many parts should the snake have at the beginning |
24 |
private var apple:Element; //Our apple |
25 |
private var space_value:Number; //space between the snake parts |
26 |
private var last_button_down:uint; //the keyCode of the last button pressed |
27 |
private var flag:Boolean; //is it allowed to change direction? |
28 |
private var score:Number; |
29 |
private var score_tf:TextField; //the Textfield showing the score |
30 |
|
31 |
public function Main() |
32 |
{
|
33 |
if(stage) |
34 |
addEventListener(Event.ADDED_TO_STAGE, init); |
35 |
else
|
36 |
init(); |
37 |
}
|
38 |
|
39 |
private function init(e:Event = null):void |
40 |
{
|
41 |
snake_vector = new Vector.<Element>; |
42 |
markers_vector = new Vector.<Object>; |
43 |
space_value = 2; |
44 |
timer = new Timer(50); //Every 50th millisecond, the moveIt() function will be fired! |
45 |
dead = false; |
46 |
min_elements = 10; //We will begin with 10 elements. |
47 |
apple = new Element(0xFF0000, 1,10, 10); //red, not transparent, width:10, height: 10; |
48 |
apple.catchValue = 0; //pretty obvious |
49 |
last_button_down = Keyboard.RIGHT; //The first direction of the snake is set in this variable |
50 |
score = 0; |
51 |
score_tf = new TextField(); //this is the TextField which shows our score. |
52 |
this.addChild(score_tf); |
53 |
|
54 |
for(var i:int=0;i<min_elements;++i) |
55 |
{
|
56 |
snake_vector[i] = new Element(0x00AAFF,1,10,10); |
57 |
snake_vector[i].direction = "R"; //The starting direction of the snake |
58 |
if (i == 0)//first snake element |
59 |
{
|
60 |
//you have to place the first element on a GRID. (now: 0,0) [possible x positions: (snake_vector[0].width+space_value)*<UINT> ]
|
61 |
attachElement(snake_vector[i], (snake_vector[0].width + space_value) * 20, (snake_vector[0].height + space_value) * 10, snake_vector[i].direction); |
62 |
snake_vector[0].alpha = 0.7; |
63 |
}
|
64 |
else
|
65 |
{
|
66 |
attachElement(snake_vector[i], snake_vector[i - 1].x, snake_vector[i - 1].y, snake_vector[i - 1].direction); |
67 |
}
|
68 |
}
|
69 |
|
70 |
placeApple(false); |
71 |
timer.addEventListener(TimerEvent.TIMER, moveIt); |
72 |
timer.start(); |
73 |
}
|
74 |
|
75 |
private function attachElement(who:Element,lastXPos:Number = 0,lastYPos:Number = 0,dirOfLast:String = "R"):void |
76 |
{
|
77 |
if (dirOfLast == "R") |
78 |
{
|
79 |
who.x = lastXPos - snake_vector[0].width - space_value; |
80 |
who.y = lastYPos; |
81 |
}
|
82 |
else if(dirOfLast == "L") |
83 |
{
|
84 |
who.x = lastXPos + snake_vector[0].width + space_value; |
85 |
who.y = lastYPos; |
86 |
}
|
87 |
else if(dirOfLast == "U") |
88 |
{
|
89 |
who.x = lastXPos; |
90 |
who.y = lastYPos + snake_vector[0].height + space_value; |
91 |
}
|
92 |
else if(dirOfLast == "D") |
93 |
{
|
94 |
who.x = lastXPos; |
95 |
who.y = lastYPos - snake_vector[0].height - space_value; |
96 |
}
|
97 |
this.addChild(who); |
98 |
}
|
99 |
|
100 |
private function placeApple(caught:Boolean = true):void |
101 |
{
|
102 |
if (caught) |
103 |
apple.catchValue += 10; |
104 |
|
105 |
var boundsX:int = (Math.floor(stage.stageWidth / (snake_vector[0].width + space_value)))-1; |
106 |
var randomX:Number = Math.floor(Math.random()*boundsX); |
107 |
|
108 |
var boundsY:int = (Math.floor(stage.stageHeight/(snake_vector[0].height + space_value)))-1; |
109 |
var randomY:Number = Math.floor(Math.random()*boundsY); |
110 |
|
111 |
apple.x = randomX * (apple.width + space_value); |
112 |
apple.y = randomY * (apple.height + space_value); |
113 |
|
114 |
for(var i:uint=0;i<snake_vector.length-1;i++) |
115 |
{
|
116 |
if(snake_vector[i].x == apple.x && snake_vector[i].y == apple.y) |
117 |
placeApple(false); |
118 |
}
|
119 |
if (!apple.stage) |
120 |
this.addChild(apple); |
121 |
}
|
122 |
|
123 |
private function moveIt(e:TimerEvent):void |
124 |
{
|
125 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
126 |
{
|
127 |
//This code runs if the snakes heads position and the apples position are the same
|
128 |
}
|
129 |
|
130 |
if (snake_vector[0].x > stage.stageWidth-snake_vector[0].width || snake_vector[0].x < 0 || snake_vector[0].y > stage.stageHeight-snake_vector[0].height || snake_vector[0].y < 0) |
131 |
{
|
132 |
gameOver(); |
133 |
}
|
134 |
|
135 |
|
136 |
for (var i:int = 0; i < snake_vector.length; i++) |
137 |
{
|
138 |
/*
|
139 |
START OF FOR BLOCK
|
140 |
This whole 'for' block will run as many times, as many elements the snake has.
|
141 |
If there are four snake parts, this whole for cycle will run four times.
|
142 |
*/
|
143 |
|
144 |
if (snake_vector[i] != snake_vector[0] && (snake_vector[0].x == snake_vector[i].x && snake_vector[0].y == snake_vector[i].y)) |
145 |
{
|
146 |
//If the snakes heads position is the same as any of the snake parts, this block will run
|
147 |
gameOver(); |
148 |
}
|
149 |
|
150 |
if (markers_vector.length > 0) |
151 |
{
|
152 |
//if there are direction markers, this code runs
|
153 |
}
|
154 |
|
155 |
|
156 |
var DIRECTION:String = snake_vector[i].direction; //getting the direction of the current snake element. |
157 |
switch (DIRECTION) |
158 |
{
|
159 |
case "R" : |
160 |
snake_vector[i].x += snake_vector[i].width + space_value; |
161 |
break; |
162 |
case "L" : |
163 |
snake_vector[i].x -= snake_vector[i].width + space_value; |
164 |
break; |
165 |
case "D" : |
166 |
snake_vector[i].y += snake_vector[i].height + space_value; |
167 |
break; |
168 |
case "U" : |
169 |
snake_vector[i].y -= snake_vector[i].width + space_value; |
170 |
break; |
171 |
}
|
172 |
|
173 |
/*
|
174 |
END OF FOR BLOCK
|
175 |
*/
|
176 |
}
|
177 |
|
178 |
}
|
179 |
|
180 |
private function gameOver():void |
181 |
{
|
182 |
dead = true; |
183 |
timer.stop(); |
184 |
while (this.numChildren) |
185 |
this.removeChildAt(0); |
186 |
timer.removeEventListener(TimerEvent.TIMER,moveIt); |
187 |
//stage.removeEventListener(KeyboardEvent.KEY_DOWN,directionChanged);
|
188 |
init(); |
189 |
}
|
190 |
|
191 |
}
|
192 |
}
|
Langkah 11: Fungsi directionChanged()
Kita ingin listen ke keyboard, jadi kita benar-benar dapat mengendalikan ular. Untuk ini kita perlu memasukkan beberapa kode ke fungsi init()
dan fungsi gameOver()
.
Taruh ini di akhir fungsi init()
(mengatur fungsi listener):
1 |
|
2 |
stage.addEventListener(KeyboardEvent.KEY_DOWN,directionChanged); |
Dan ini di akhir fungsi gameOver()
:
1 |
|
2 |
stage.removeEventListener(KeyboardEvent.KEY_DOWN,directionChanged); |
Sekarang buat fungsi baru:
1 |
|
2 |
private function directionChanged(e:KeyboardEvent):void |
3 |
{
|
4 |
var m:Object = new Object(); //MARKER OBJECT |
5 |
//this will be added to the markers_vector, and have the properties x,y, and type
|
6 |
//the type property will show us the direction. if it is set to right, whenever a snake's part hits it,
|
7 |
//the direction of that snake's part will be set to right also
|
8 |
|
9 |
if (e.keyCode == Keyboard.LEFT && last_button_down != e.keyCode && last_button_down != Keyboard.RIGHT) |
10 |
{
|
11 |
//If we pressed the LEFT arrow,
|
12 |
//and it was not the last key we pressed,
|
13 |
//and the last key pressed was not the RIGHT arrow either...
|
14 |
//Then this block of code will run
|
15 |
}
|
16 |
markers_vector.push(m); //we push the object into a vector, so we can acces to it later (in the moveIt() function) |
17 |
}
|
Apa yang masuk ke blok if?
- Arah kepala harus ditulis ulang.
- Obyek penanda harus diatur dengan benar.
- Variabel last_button harus disetel ke tombol terakhir yang ditekan.
1 |
|
2 |
if (e.keyCode == Keyboard.LEFT && last_button_down != e.keyCode && last_button_down != Keyboard.RIGHT && flag) |
3 |
{
|
4 |
snake_vector[0].direction = "L"; |
5 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"L"}; |
6 |
last_button_down = Keyboard.LEFT; |
7 |
}
|
Ulangi ini tiga kali lagi, dan kita akan memiliki ini:
1 |
|
2 |
private function directionChanged(e:KeyboardEvent):void |
3 |
{
|
4 |
var m:Object = new Object(); //MARKER OBJECT |
5 |
|
6 |
if (e.keyCode == Keyboard.LEFT && last_button_down != e.keyCode && last_button_down != Keyboard.RIGHT) |
7 |
{
|
8 |
snake_vector[0].direction = "L"; |
9 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"L"}; |
10 |
last_button_down = Keyboard.LEFT; |
11 |
}
|
12 |
else if (e.keyCode == Keyboard.RIGHT && last_button_down != e.keyCode && last_button_down != Keyboard.LEFT) |
13 |
{
|
14 |
snake_vector[0].direction = "R"; |
15 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"R"}; |
16 |
last_button_down = Keyboard.RIGHT; |
17 |
}
|
18 |
else if (e.keyCode == Keyboard.UP && last_button_down != e.keyCode && last_button_down != Keyboard.DOWN) |
19 |
{
|
20 |
snake_vector[0].direction = "U"; |
21 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"U"}; |
22 |
last_button_down = Keyboard.UP; |
23 |
}
|
24 |
else if (e.keyCode == Keyboard.DOWN && last_button_down != e.keyCode && last_button_down != Keyboard.UP) |
25 |
{
|
26 |
snake_vector[0].direction = "D"; |
27 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"D"}; |
28 |
last_button_down = Keyboard.DOWN; |
29 |
}
|
30 |
markers_vector.push(m); |
31 |
}
|
Kita membutuhkan satu hal lagi untuk mengujinya. Dalam fungsi moveIt() kita memiliki sesuatu seperti ini:
1 |
|
2 |
if (markers_vector.length > 0) |
3 |
{
|
4 |
//if there are direction markers, this code runs
|
5 |
}
|
Di sini kita perlu perulangan lagi, untuk memeriksa setiap bagian ular terhadap setiap penanda di atas panggung, dan memeriksa apakah mereka bertabrakan. Jika iya, kita perlu mengatur arah bagian ular ke jenis penanda. Jika ini adalah bagian ular terakhir yang bertabrakan dengan penanda, kita perlu menghapus penanda dari markers_vector
, juga, sehingga bagian ular tidak bertabrakan dengannya lagi.
1 |
|
2 |
if (markers_vector.length > 0) |
3 |
{
|
4 |
for(var j:uint=0;j < markers_vector.length;j++) |
5 |
{
|
6 |
if(snake_vector[i].x == markers_vector[j].x && snake_vector[i].y == markers_vector[j].y) |
7 |
{
|
8 |
//setting the direction
|
9 |
snake_vector[i].direction = markers_vector[j].type; |
10 |
if(i == snake_vector.length-1) |
11 |
{
|
12 |
//if its the last snake_part
|
13 |
markers_vector.splice(j, 1); |
14 |
}
|
15 |
}
|
16 |
}
|
17 |
}
|
Sekarang jika Anda bermain dengannya itu terlihat baik-baik saja, tetapi ada bug di sana. Ingat apa yang saya katakan di awal tutorial?
Sebagai contoh, jika ular bergerak ke kanan dan Anda menekan kombo turun-kiri dengan sangat cepat, ia akan memukul dirinya sendiri dan memulai kembali permainan.
Bagaimana kita memperbaikinya? Itu mudah. Kita memiliki variabel flag
kita, dan kita akan menggunakannya untuk ini. Kita hanya akan dapat mengubah arah ular ketika ini diatur ke true (Default adalah false, periksa fungsi init()
untuk itu).
Jadi kita perlu mengubah fungsi directionChanged()
sedikit. Kepala blok if harus diubah: tambahkan sebuah klausa && flag
di akhir setiap 'if'.
1 |
|
2 |
private function directionChanged(e:KeyboardEvent):void |
3 |
{
|
4 |
var m:Object = new Object(); //MARKER OBJECT |
5 |
|
6 |
if (e.keyCode == Keyboard.LEFT && last_button_down != e.keyCode && last_button_down != Keyboard.RIGHT && flag) |
7 |
{
|
8 |
snake_vector[0].direction = "L"; |
9 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"L"}; |
10 |
last_button_down = Keyboard.LEFT; |
11 |
flag = false; |
12 |
}
|
13 |
else if (e.keyCode == Keyboard.RIGHT && last_button_down != e.keyCode && last_button_down != Keyboard.LEFT && flag) |
14 |
{
|
15 |
snake_vector[0].direction = "R"; |
16 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"R"}; |
17 |
last_button_down = Keyboard.RIGHT; |
18 |
flag = false; |
19 |
}
|
20 |
else if (e.keyCode == Keyboard.UP && last_button_down != e.keyCode && last_button_down != Keyboard.DOWN && flag) |
21 |
{
|
22 |
snake_vector[0].direction = "U"; |
23 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"U"}; |
24 |
last_button_down = Keyboard.UP; |
25 |
flag = false; |
26 |
}
|
27 |
else if (e.keyCode == Keyboard.DOWN && last_button_down != e.keyCode && last_button_down != Keyboard.UP && flag) |
28 |
{
|
29 |
snake_vector[0].direction = "D"; |
30 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"D"}; |
31 |
last_button_down = Keyboard.DOWN; |
32 |
flag = false; |
33 |
}
|
34 |
markers_vector.push(m); |
35 |
}
|
Jika Anda mengujinya sekarang, itu tidak akan berhasil karena penandanya selalu false.
Kapan kita perlu mengaturnya menjadi true?
Setelah pindah/tick kita dapat mengizinkan pengguna untuk mengubah arah, kita hanya tidak ingin mengubahnya dua kali dalam satu tick. Jadi letakkan ini di akhir fungsi moveIt()
:
1 |
|
2 |
flag = true; |
Sekarang uji, dan tidak ada bug lagi.
Langkah 12: Menyelesaikan Permainan
Sekarang satu-satunya hal yang perlu kita lakukan adalah 'apple-check'
Ingat ini di awal fungsi moveIt()
?
1 |
|
2 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
3 |
{
|
4 |
//This code runs if the snake's head's position and the apple's position are the same
|
5 |
}
|
Inilah yang perlu kita lakukan di sana:
- Memanggil fungsi placeApple(). (Kita tidak menetapkan parameter ke false; kita membiarkannya seperti itu. Default adalah true.)
- Menampilkan skor saat ini
- Lampirkan elemen baru ke bagian terakhir ular.
1 |
|
2 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
3 |
{
|
4 |
//calling the placeApple() function
|
5 |
placeApple(); |
6 |
//show the current Score
|
7 |
score += apple.catchValue; |
8 |
score_tf.text = "Score:" + String(score); |
9 |
//Attach a new snake Element
|
10 |
snake_vector.push(new Element(0x00AAFF,1,10,10)); |
11 |
snake_vector[snake_vector.length-1].direction = snake_vector[snake_vector.length-2].direction; //lastOneRichtung |
12 |
//attachElement(who,lastXPos,lastYPos,lastDirection)
|
13 |
attachElement(snake_vector[snake_vector.length-1], |
14 |
(snake_vector[snake_vector.length-2].x), |
15 |
snake_vector[snake_vector.length-2].y, |
16 |
snake_vector[snake_vector.length-2].direction); |
17 |
}
|
Sekarang semuanya harus berfungsi dengan baik. Cobalah:
Di sini adalah seluruh kelas Main lagi:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.display.Sprite; |
5 |
import flash.text.TextField; |
6 |
import flash.utils.Timer; |
7 |
import flash.events.TimerEvent; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.events.KeyboardEvent; |
10 |
import flash.events.MouseEvent; |
11 |
import flash.events.Event; |
12 |
|
13 |
import com.Element; |
14 |
|
15 |
public class Main extends Sprite |
16 |
{
|
17 |
//DO NOT GIVE THEM A VALUE HERE! Give them a value in the init() function
|
18 |
private var snake_vector:Vector.<Element>; //the snake's parts are held in here |
19 |
private var markers_vector:Vector.<Object>; //the markers are held in here |
20 |
private var timer:Timer; |
21 |
private var dead:Boolean; |
22 |
private var min_elements:int; //holds how many parts should the snake have at the beginning |
23 |
private var apple:Element; //Our apple |
24 |
private var space_value:Number; //space between the snake parts |
25 |
private var last_button_down:uint; //the keyCode of the last button pressed |
26 |
private var flag:Boolean; //is it allowed to change direction? |
27 |
private var score:Number; |
28 |
private var score_tf:TextField; //the Textfield showing the score |
29 |
|
30 |
public function Main() |
31 |
{
|
32 |
if(stage) |
33 |
addEventListener(Event.ADDED_TO_STAGE, init); |
34 |
else
|
35 |
init(); |
36 |
}
|
37 |
|
38 |
private function init(e:Event = null):void |
39 |
{
|
40 |
snake_vector = new Vector.<Element>; |
41 |
markers_vector = new Vector.<Object>; |
42 |
space_value = 2; |
43 |
timer = new Timer(50); //Every 50th millisecond, the moveIt() function will be fired! |
44 |
dead = false; |
45 |
min_elements = 1; |
46 |
apple = new Element(0xFF0000, 1,10, 10); //red, not transparent, width:10, height: 10; |
47 |
apple.catchValue = 0; //pretty obvious |
48 |
last_button_down = Keyboard.RIGHT; //The starting direction of the snake (only change it if you change the 'for cycle' too.) |
49 |
score = 0; |
50 |
score_tf = new TextField(); |
51 |
this.addChild(score_tf); |
52 |
|
53 |
//Create the first <min_elements> Snake parts
|
54 |
for(var i:int=0;i<min_elements;++i) |
55 |
{
|
56 |
snake_vector[i] = new Element(0x00AAFF,1,10,10); |
57 |
snake_vector[i].direction = "R"; //The starting direction of the snake |
58 |
if (i == 0) |
59 |
{
|
60 |
//you have to place the first element on a GRID. (now: 0,0) [possible x positions: (snake_vector[0].width+space_value)*<UINT> ]
|
61 |
attachElement(snake_vector[i],0,0,snake_vector[i].direction) |
62 |
snake_vector[0].alpha = 0.7; |
63 |
}
|
64 |
else
|
65 |
{
|
66 |
attachElement(snake_vector[i], snake_vector[i - 1].x, snake_vector[i - 1].y, snake_vector[i - 1].direction); |
67 |
}
|
68 |
}
|
69 |
|
70 |
placeApple(false); |
71 |
timer.addEventListener(TimerEvent.TIMER,moveIt); |
72 |
stage.addEventListener(KeyboardEvent.KEY_DOWN,directionChanged); |
73 |
timer.start(); |
74 |
}
|
75 |
|
76 |
private function attachElement(who:Element,lastXPos:Number = 0,lastYPos:Number = 0,dirOfLast:String = "R"):void |
77 |
{
|
78 |
if (dirOfLast == "R") |
79 |
{
|
80 |
who.x = lastXPos - snake_vector[0].width - space_value; |
81 |
who.y = lastYPos; |
82 |
}
|
83 |
else if(dirOfLast == "L") |
84 |
{
|
85 |
who.x = lastXPos + snake_vector[0].width + space_value; |
86 |
who.y = lastYPos; |
87 |
}
|
88 |
else if(dirOfLast == "U") |
89 |
{
|
90 |
who.x = lastXPos; |
91 |
who.y = lastYPos + snake_vector[0].height + space_value; |
92 |
}
|
93 |
else if(dirOfLast == "D") |
94 |
{
|
95 |
who.x = lastXPos; |
96 |
who.y = lastYPos - snake_vector[0].height - space_value; |
97 |
}
|
98 |
this.addChild(who); |
99 |
}
|
100 |
|
101 |
private function placeApple(caught:Boolean = true):void |
102 |
{
|
103 |
if (caught) |
104 |
apple.catchValue += 10; |
105 |
|
106 |
var boundsX:int = (Math.floor(stage.stageWidth / (snake_vector[0].width + space_value)))-1; |
107 |
var randomX:Number = Math.floor(Math.random()*boundsX); |
108 |
|
109 |
var boundsY:int = (Math.floor(stage.stageHeight/(snake_vector[0].height + space_value)))-1; |
110 |
var randomY:Number = Math.floor(Math.random()*boundsY); |
111 |
|
112 |
apple.x = randomX * (apple.width + space_value); |
113 |
apple.y = randomY * (apple.height + space_value); |
114 |
|
115 |
for(var i:uint=0;i<snake_vector.length-1;i++) |
116 |
{
|
117 |
if(snake_vector[i].x == apple.x && snake_vector[i].y == apple.y) |
118 |
placeApple(false); |
119 |
}
|
120 |
if (!apple.stage) |
121 |
this.addChild(apple); |
122 |
}
|
123 |
|
124 |
private function moveIt(e:TimerEvent):void |
125 |
{
|
126 |
if (snake_vector[0].x == apple.x && snake_vector[0].y == apple.y) |
127 |
{
|
128 |
placeApple(); |
129 |
//show the current Score
|
130 |
score += apple.catchValue; |
131 |
score_tf.text = "Score:" + String(score); |
132 |
//Attach a new snake Element
|
133 |
snake_vector.push(new Element(0x00AAFF,1,10,10)); |
134 |
snake_vector[snake_vector.length-1].direction = snake_vector[snake_vector.length-2].direction; //lastOneRichtung |
135 |
attachElement(snake_vector[snake_vector.length-1], |
136 |
(snake_vector[snake_vector.length-2].x), |
137 |
snake_vector[snake_vector.length-2].y, |
138 |
snake_vector[snake_vector.length-2].direction); |
139 |
}
|
140 |
if (snake_vector[0].x > stage.stageWidth-snake_vector[0].width || snake_vector[0].x < 0 || snake_vector[0].y > stage.stageHeight-snake_vector[0].height || snake_vector[0].y < 0) |
141 |
{
|
142 |
gameOver(); |
143 |
}
|
144 |
|
145 |
for (var i:int = 0; i < snake_vector.length; i++) |
146 |
{
|
147 |
if (markers_vector.length > 0) |
148 |
{
|
149 |
for(var j:uint=0;j < markers_vector.length;j++) |
150 |
{
|
151 |
if(snake_vector[i].x == markers_vector[j].x && snake_vector[i].y == markers_vector[j].y) |
152 |
{
|
153 |
snake_vector[i].direction = markers_vector[j].type; |
154 |
if(i == snake_vector.length-1) |
155 |
{
|
156 |
markers_vector.splice(j, 1); |
157 |
}
|
158 |
}
|
159 |
}
|
160 |
}
|
161 |
if (snake_vector[i] != snake_vector[0] && (snake_vector[0].x == snake_vector[i].x && snake_vector[0].y == snake_vector[i].y)) |
162 |
{
|
163 |
gameOver(); |
164 |
}
|
165 |
|
166 |
//Move the boy
|
167 |
var DIRECTION:String = snake_vector[i].direction; |
168 |
switch (DIRECTION) |
169 |
{
|
170 |
case "R" : |
171 |
snake_vector[i].x += snake_vector[i].width + space_value; |
172 |
break; |
173 |
case "L" : |
174 |
snake_vector[i].x -= snake_vector[i].width + space_value; |
175 |
break; |
176 |
case "D" : |
177 |
snake_vector[i].y += snake_vector[i].height + space_value; |
178 |
break; |
179 |
case "U" : |
180 |
snake_vector[i].y -= snake_vector[i].width + space_value; |
181 |
break; |
182 |
}
|
183 |
|
184 |
}
|
185 |
|
186 |
flag = true; |
187 |
}
|
188 |
|
189 |
private function gameOver():void |
190 |
{
|
191 |
dead = true; |
192 |
timer.stop(); |
193 |
while (this.numChildren) |
194 |
this.removeChildAt(0); |
195 |
timer.removeEventListener(TimerEvent.TIMER,moveIt); |
196 |
stage.removeEventListener(KeyboardEvent.KEY_DOWN,directionChanged); |
197 |
init(); |
198 |
}
|
199 |
|
200 |
private function directionChanged(e:KeyboardEvent):void |
201 |
{
|
202 |
var m:Object = new Object(); //MARKER OBJECT |
203 |
|
204 |
if (e.keyCode == Keyboard.LEFT && last_button_down != e.keyCode && last_button_down != Keyboard.RIGHT && flag) |
205 |
{
|
206 |
snake_vector[0].direction = "L"; |
207 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"L"}; |
208 |
last_button_down = Keyboard.LEFT; |
209 |
flag = false; |
210 |
}
|
211 |
else if (e.keyCode == Keyboard.RIGHT && last_button_down != e.keyCode && last_button_down != Keyboard.LEFT && flag) |
212 |
{
|
213 |
snake_vector[0].direction = "R"; |
214 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"R"}; |
215 |
last_button_down = Keyboard.RIGHT; |
216 |
flag = false; |
217 |
}
|
218 |
else if (e.keyCode == Keyboard.UP && last_button_down != e.keyCode && last_button_down != Keyboard.DOWN && flag) |
219 |
{
|
220 |
snake_vector[0].direction = "U"; |
221 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"U"}; |
222 |
last_button_down = Keyboard.UP; |
223 |
flag = false; |
224 |
}
|
225 |
else if (e.keyCode == Keyboard.DOWN && last_button_down != e.keyCode && last_button_down != Keyboard.UP && flag) |
226 |
{
|
227 |
snake_vector[0].direction = "D"; |
228 |
m = {x:snake_vector[0].x, y:snake_vector[0].y, type:"D"}; |
229 |
last_button_down = Keyboard.DOWN; |
230 |
flag = false; |
231 |
}
|
232 |
markers_vector.push(m); |
233 |
}
|
234 |
|
235 |
}
|
236 |
|
237 |
}
|
Langkah 13: Menyimpulkan Semuanya
Selamat! Anda baru saja membuat permainan yang bagus. Sekarang Anda bisa mengembangkannya lebih jauh, dan membuat apel super atau sesuatu. Untuk itu saya sarankan menggunakan fungsi lain yang bernama placeSuperApple()
dan kelas baru bernama SuperApple
. Setiap kali Anda menangkap apel super, bagian ular bisa diperpanjang oleh tiga elemen, mungkin. Ini bisa diatur dengan setter/getter di kelas SuperApple
.
Jika Anda ingin melakukan ini, dan Anda terjebak di suatu tempat, tinggalkan saja saya komentar di sini.
Terima kasih atas waktu Anda!