ในบทความตอนนี้ เราจะมาสร้างเกมเล็กๆ แบบในรูปข้างบนนี้ด้วย AndEngine กันครับ
ห่างหายไปนานมาก จากตอนที่แล้ว เนื่องด้วยผู้เขียนกำลังอ่อนแรง แต่ในเมื่อยังไม่ตาย ก็ต้องสู้ๆ ต่อไปล่ะนะ
ตอนที่แล้วผมเกริ่นเกี่ยวกับ AndEngine ไว้พอประมาณ และให้ load source code ลองไปศึกษากันดู ถ้ายังไม่มีก็ที่นี้เลยครับ http://pilotpol.blogspot.com/2013/05/rpg-android-andengine-1.html
ส่วนตอนนี้ก็จะอธิบายตามความเข้าใจของตนเอง เกี่ยวกับ Game Engine อันนี้ และการเขียนบน Android Platform แบบ Step by Step ตั้งแต่เริ่มต้นเลยก็แล้วกัน
1. เริ่มแรกก่อน ถ้าจะเขียน app อะไรสักอย่างบน android แบบ native ล่ะก็ ก็ต้องไป download AndroidSDK มาก่อน ถึงตรงนี้ทุกท่านที่ต้องการหา GameEngine สักตัวน่าจะมี และได้ลองเขียน HelloAndroid กันแล้ว ถ้ายังไม่มีก็ตรงนี้ได้ครับ http://pilotpol.blogspot.com/2013/05/android-thai-pilot-pray-2.html
2. หลังจากมี Android Developer Tools แล้ว และพอจะรู้หลักในการเขียน android แบบทั่วไปแล้ว (เรื่องเขียนไม่มีไรมากครับ ไปที่สร้าง project ใหม่ แล้วให้มันสร้างเป็นแนวทางให้ก็ได้) ต่อไปก็เตรียมตัวเรียนรู้ Engine ตัวนี้กันเลย !
บอกไว้ก่อนว่าผมไม่ได้อ่านจาก Cookbook ของ AndEngine โดยตรง เพราะฉะนั้นจึงอาจจะตกหล่นไปบ้าง และไม่ถูกหลักเท่าไร แต่ก็สามารถสร้างเกมตามต้องการได้ล่ะนะ
เริ่มจาก Download Library ของ AndEngine มา ตรงนี้ก็จะมีอยู่ 2 แบบ แล้วแต่ชอบ
- Download Source code มาเลยแล้วมาเปิด Project ใน Package Explorer ที่นี้พอเวลาสร้าง game ของเราเอง เราก็ต้องเรียกหาที่อยู่ของบรรดา Project AndEngine ทั้งหลายทุกครั้ง หาได้จากตรงนี้ครับ https://github.com/nicolasgramlich/AndEngine
- Download เฉพาะ Library ที่เป็นไฟล์ *.jar ไปวางไว้ที่ folder lib ภายใต้ project อันนี้ผมรวบรวมไว้ให้และมีแก้ไขเล็กน้อยเพื่อใช้สำหรับ project RPG ของผมเอง ตรงนี้ครับ https://docs.google.com/file/d/0B_raxIdscReBRnFMY05tR1daNms/edit?usp=sharing
ในที่นี้จะเอาง่ายๆ ไว้ก่อน ก็จะอธิบายเฉพาะแบบที่ 2 ก็แล้วกันนะครับ
มาเริ่มโปรเจ็คเล็กๆ กันเลยครับ
1. ไปที่ New > Android Application Project
ตั้งชื่อ app ชื่อ project ตามใจชอบได้เลยครับ แล้วก็ชื่อ package name ใครยังไม่ชำนาญ ก็ตั้งตามตัวอย่างไปก่อนก็ได้ครับ จากนั้นมาเลือก 4 ช่องล่าง ตามใจชอบอีกเช่นกัน สำหรับในตัวอย่าง ผมให้ app รองรับต่ำสุดที่ Android 2.3 เลือกรุ่นเป้าหมายคือ Android 4.0 เลือกตัวที่จะมา Compile Code คือ Android 4.2 และ Theme เป็นค่า default ของมันครับ จากนั้นกด Next > โลด...
กด Next > ต่อไปเลยครับ
ปรับแต่ง Icon ตามชอบใจได้เลยครับ เสร็จเรียบร้อย กด Next >
หน้านี้ก็ตาม Default มันเลยครับ เลือก Blank Activity แล้วกด Next >
เสร็จแล้วครับ กด Finish ได้เลย
จะได้เป็นไฟล์ Zip นะครับ นำไฟล์ Zip ไปวางไว้ใน folder libs ใน Project ครับ แล้วแตกไฟล์ออกที่นั่น (ตอนแตกไฟล์ อาจจะมีซ้ำอันหนึ่งนะครับ เป็น android-support-v4.jar ซึ่ง จะเลือกให้ทับไป หรือไม่ทับก็ได้ครับ)
เสร็จสรรพแล้ว ภายใน folder libs ของ Project เรา ควรจะมีไฟล์หน้าตาประมาณนี้นะครับ
พวกนี้เป็นไฟล์ lib ของ AndEngine ทั้งหมดครับ ซึ่งในตัวอย่างก็ไม่ได้ใช้หมดหรอกครับ ใครจะลบออกให้เหลือเฉพาะที่ใช้ก็ได้นะครับ
เริ่มแรกที่ folder assets ภายใต้ Project ของเรานะครับ (อันนี้ของผมเป็น helloAndEngine) สร้าง folder font ขึ้นมาตามรูปครับ แล้วไปหา font อะไรก็ได้มาวางไว้ครับ นามสกุลเป็น .ttf นะครับ
หรือถ้าจะสนับสนุนของ DroidSans แบบผม ก็ไป Download มาได้เลยครับ ที่นี่ http://www.nuuneoi.com/blog/blog.php?read_id=296 ต้องขอขอบคุณ คุณ NuuNeoI เจ้าของ font มา ณ โอกาสนี้ด้วยครับ (ผมไม่รู้จักเป็นการส่วนตัวกะเขาหรอกนะครับ)
Dowload font มาลงที่ Folder font แล้วก็ยังเหลือ รูปภาพตัวละครของเราครับ ดูข้อต่อไปกันเลย
สร้าง Folder gfx ภายใต้ assets ตามภาพด้านล่างนี้ครับ จากนั้น Copy ไฟล์ภาพตัวละครด้านบน ไปวางไว้ที่ Folder นั้น โดยตั้งชื่ออะไรก็สุดแล้วแต่ครับ ของผมตั้งเป็น player แต่นามสกุลเป็น png นะครับ
ที่นี่เราก็จะได้หน้าตาของ Project เป็นแบบนี้ครับ ภายใต้ assets มี fonts และ gfx ส่วน libs ก็มี ไฟล์ jar ของ AndEngine อยู่แล้ว
ใครที่ตั้งชื่ออื่น ก็จะไม่เหมือนกันนะครับ
11. ใน Code ให้ลบ Activity หลัง extends ออกไปเลยครับ แล้วก็ Code ข้างในด้วย เพราะเราจะเปลี่ยนมาใช้ Code แบบด้านล่างแทน
เราเรียก extends SimpleBaseGameActivity แทนการเรียกใช้ Activity ตามแบบแอพทั่วไปครับ และภายใน Class ก็จะต้องเรียก Method 3 ตัวตามกรอบสีแดงครับ อธิบายได้ดังนี้นะครับ
- onCreateEngineOptions() เป็นตัวสร้างสภาพแวดล้อมเริ่มต้นของ AndEngine ให้กับ แอพของเราครับ เดี๋ยว Code ภายในเราจะมาว่ากันอีกที
- onCreateResources() เป็นตัวสร้างพวกสิ่งต่างๆ ในตอนเริ่มต้น สำหรับเกมของเราครับ
- onCreateScene() ตัวนี้ใช้สร้าง Scene กำหนด Object ต่างๆ ให้กับ scene ที่ใช้แสดงผลออกทางหน้าจอ และทำการ update scene วนรอบไปเรื่อยๆ ภายในนี้เราก็เขียน Code ดักทำโน้นนี้เพื่อใช้ run game เราครับ
จากนี้ไปเป็นตัว Code นะครับ ผมจะทำสีพื้นเป็นสี นี้ ครับ
ในส่วน Attribute สร้างตัวแปรสำหรับ class ดังนี้ครับ
// game engine
private Scene scene;
private static final int CAMERA_WIDTH = 800;
private static final int CAMERA_HEIGHT = 480;
private BoundCamera mBoundChaseCamera;
// resource
private BitmapTextureAtlas mBitmapTextureAtlas;
private TiledTextureRegion mPlayerTextureRegion;
private Font mFont;
// object on scene
private Text hellotxt;
private int countd = 10;
สร้างตัวแปรกันแล้ว เราก็มาเขียน code ในส่วน onCreateEngineOptions กันครับ ดังนี้
// ตั้งค่ามุมกล้อง
this.mBoundChaseCamera = new BoundCamera(0, 0, CAMERA_WIDTH,CAMERA_HEIGHT);
// ตั้งค่า engine
final EngineOptions engineOptions = new EngineOptions(
true,
ScreenOrientation.LANDSCAPE_FIXED,
new RatioResolutionPolicy( CAMERA_WIDTH, CAMERA_HEIGHT ),
this.mBoundChaseCamera);
// ตั้งค่าให้สามารถ multitouch ขณะเล่นเกมได้
engineOptions.getTouchOptions().setNeedsMultiTouch(true);
return engineOptions;
ก็ตรงไปตรงมาครับ เริ่มแรกก็สร้างมุมกล้องขึ้นมาก่อน แล้วก็สร้างตัว Engine ภายใน EngineOptions เราก็สามารถกำหนดได้ว่า จะให้เป็นแนวตั้งหรือแนวนอน ในที่นี้เป็นแบบแนวนอนและ Fixed ไว้เลย
บรรทัดต่อมาก็ตั้งให้สามารถ Touch ได้มากกว่า 1 จุดครับ ตรงนี้สำคัญสำหรับเกมแบบใช้ปุ่มควบคุมเสมือนมากครับ เพราะถ้าไม่ตั้งค่าตรงนี้ เมื่อเรากดบังคับตัวละครค้างไว้ เราจะไม่สามารถกดหน้าจอป้อนคำสั่งใดๆ ได้อีก เพราะตัว engine จะรับค่าเพียง 1 จุดสัมผัสเท่านั้นครับ
แล้วก็ return ค่าออกไปตามที่ method นี้เรียกใช้ เป็นอันจบการสร้าง engine ครับ ที่นี้ก็เหลือ สร้าง Resource เตรียมไว้ แล้วก็เอามันออกมาแสดงครับ
ในเกมของเราเบื้องต้นจะยังไม่มีอะไรมา ผมจะสร้าง 1 ตัวละครกระดุ๊กกระดิ๊กได้ และ 1 การแสดงตัวหนังสือภาษาไทย พร้อมการเปลี่ยนแปลงที่กำหนดโดยระยะเวลานะครับ เริ่มไปต่อกันได้เลย
onCreateResources() ในนี้ให้เขียน Code ดังนี้ครับ
//player resource
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
mBitmapTextureAtlas = new BitmapTextureAtlas( this.getTextureManager(), 96, 192, TextureOptions.DEFAULT);
mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createTiledFromAsset(
mBitmapTextureAtlas, this,
"player.png", 0, 0, 3, 4);
mBitmapTextureAtlas.load();
//font resource
final ITexture droidFontTexture = new BitmapTextureAtlas(this.getTextureManager(), 256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
FontFactory.setAssetBasePath("font/");
mFont = FontFactory.createFromAsset(this.getFontManager(), droidFontTexture, this.getAssets(), "DroidSans.ttf", 24, true, Color.WHITE );
mFont.load();
ไล่จาก Code ดูเลยนะครับ ส่วน comment แรกเราจะ load ตัวละครก่อนครับ
เริ่มจาก กำหนด path ที่จะ load พวกรูปต่างๆ ให้กับตัว load texture ของ AndEngine ครับ ชื่อยาวๆ ก็คือ BitmapTextureAtlasTextureRegionFactory ครับ
ต่อมาจะต้องทำการสร้างตัว TextureAtlas ขึ้นมาครับ ตัวนี้จะเป็นตัวเก็บรูปภาพเอาไว้ครับ ในที่นี้จะเป็นภาพใหญ่ๆ ก่อนตัด parameter 96,192 คือความกว้างและความสูงของตัวเก็บภาพ ในที่นี้จะสร้างขนาดเท่ากับรูปที่โหลดขึ้นมาครับ ( load 1 ตัวก็ต้องมีตัวเก็บ 1 ตัวนะครับ หรือถ้าจะใช้รูปเดียวกันก็ไม่ต้องโหลดขึ้นมาอีกครับ)
จากนั้นทำการสร้าง TextureRegion (ตัวกำหนดขอบเขตของ texture) แบบ Tiled ขึ้นมาครับ ในนี้จะมี parameter ที่ใส่ชื่อไฟล์ (player.png) และจำนวนรูปแนวกว้างกับจำนวนรูปแนวยาว (3,4 อันหลังสุดครับ) จากนั้นก็ใช้คำสั่ง load(); เข้ามาไว้ในหน่วยความจำของเครื่อง
เตรียมรูปตัวละครเสร็จแล้วครับ ต่อไปมาเตรียมตัวอักษรบ้าง เราจะสร้าง ITexture เพื่อเก็บรูปแบบตัวอักษรเช่นเดียวกับรูปครับ จากนั้น set path ของ FontFactory ให้ไปหาที่ folder asset/font
จากนั้นก็จะไปโหลด font มาเก็บไว้ครับ จะมี parameter ชื่อ font ("DroidSans.ttf") ขนาดตัวอักษรที่จะแสดง (24) และสีของตัวอักษร เป็น int นะครับ (Color.WHITE) แล้วก็ใช้คำสั่ง load() ครับ เท่านี้ก็เรียบร้อย
ตอนนี้ก็จะเหลือส่วนสำคัญที่สุดของเรา นั่นคือ การนำทุกอย่างที่เตรียมไว้แสดงขึ้นหน้าจอครับ ด้วย method onCreateScene() นั่นเอง
ภายในมี Code ดังนี้ครับ
// สร้าง scene ใหม่
scene = new Scene();
// สร้าง text
hellotxt = new Text(10, 10, mFont,
"สวัสดี แอนเอ็นจิ้น ภาษาไทย!",
"นับเวลาถอยหลังด้วย แอนเอ็นจิ้น = xxxxxxxxxxxxxx".length(),
this.getVertexBufferObjectManager());
// สร้างตัวละคร
final AnimatedSprite player = new AnimatedSprite(
100, 100,
mPlayerTextureRegion,
this.getVertexBufferObjectManager());
scene.attachChild(player);
scene.attachChild(hellotxt);
// ทำให้ตัวละครเคลื่อนไหว
player.animate( new long[] { 200, 200, 200 }, 6, 8, true);
// ขณะที่ game ทำงานไปเรื่อยๆ
scene.registerUpdateHandler(new TimerHandler(1.0f, true, new ITimerCallback() {
@Override
public void onTimePassed(final TimerHandler pTimerHandler) {
hellotxt.setText("นับเวลาถอยหลังด้วย แอนเอ็นจิ้น = " + countd);
countd--;
if(countd < 0)
countd=10;
}
}));
return scene;
เริ่มจาก สร้าง Scene ใหม่ขึ้นมาก่อนเลยครับ
ถัดมาเตรียม text เพื่อแสดงข้อความบนหน้าจอ 10,10 คือ ตำแหน่ง x,y ที่จะแสดงใน scene ถัดไปเป็นข้อความเริ่มต้น ถัดไปเป็นความยาวตัวอักษรของข้อความ ตรงนี้สำคัญมากนะครับ ถ้าความยาวตัวอักษรที่เราจะแสดง เกินจากความยาวที่ตั้งค่าไว้ตรงนี้แล้ว มันจะ error และ บังคับปิดครับ (อันนี้สำหรับข้อความแบบ Static นะครับ เหมือนกับ Textview ของ Native android) ที่เห็นเขียนแบบนั้น (ข้อความแล้วตามด้วย.length() ) ในส่วนตั้งค่าความยาว คือ เราก็กำหนดรูปแบบไปเลย มันจะได้ง่ายว่า เกินหรือไม่เกิน แทนที่จะไปนั่งนับทีละตัวอักษรเอาน่ะครับ
จากนั้นก็นำตัวละครมาเตรียม ด้วย AnimatedSprite ตั้งชื่อว่า player ค่าที่เห็น 100,100 นั่นคือ ค่าตำแหน่ง x กับ y ใน scene ครับ ตัวรูปเราก็เอามาจาก TextureRegion ที่สร้างไว้แล้วน่ะครับ
แล้วก็เพิ่มพวกที่สร้างลงไปใน scene ครับ ด้วย attachChild
ถ้าเราจบตรงนี้ก็ run ได้แล้วครับ แต่ทุกอย่างก็จะนิ่งๆ เพราะฉะนั้น เรามาเพิ่มการเคลื่อนไหวสักเล็กน้อยครับ
กำหนดให้ตัวละครเคลื่อนไหวด้วย animate จะมี parameter ดังนี้ครับ ค่า 3 ตัวแรก new long[] { 200,200,200 } คือความเร็วในการเปลี่ยนภาพจาก เฟรมหนึ่งไปเฟรมหนึ่งครับ อันนี้ต้องไปสัมพันธ์กับตอน load รูปนะครับ ว่า TextureRegion ที่เราสร้างนั้น มีภาพในแนวแนวนอน (หรือภาพการเคลื่อนไหวนั่นเอง) กี่ภาพ สำหรับตัวอย่างนี้มี 3 ภาพครับ ถัดไปจะเป็นลำดับของภาพครับ ให้นับจากซ้ายบนสุดคือ 0 ไล่มาทางขวา ถ้าหมดก็นับใหม่ เพราะฉะนั้นตามข้างต้น ผมให้แสดงภาพที่หันหน้าออกครับ ดังรูป
จากนั้นเราจะใช้ คำสั่ง registerUpdateHandler ของ scene เรียก TimerHandler ขึ้นมา จริงๆ แล้ว registerUpdateHandler นั้น มีอีกหลาย Handler ที่เรียกใช้ได้ครับ เช่น อัพเดตแบบตาม frame rate ก็มี แต่ในตอนนี้ เราจะใช้การวนรอบแบบตามเวลาที่ตั้งไว้ก่อน (ให้คิดเสียว่า การอัพเดต scene ก็คือการเปลี่ยนแปลงหน้าจอครั้งหนึ่งนะครับ)
สำหรับ การ Update แบบ Timer ก็จะมี parameter สำคัญดังนี้ครับ 1.0f คือเวลาที่นับในการวนรอบแล้วทำตามคำสั่งครับ ในที่นี้คือ 1 วินาที ถ้าต้องการครึ่งวินาที ก็ 0.5f แบบนี้นะครับ
Method onTimePassed จะทำงานเมื่อเวลาครบตามที่กำหนดครับ ภายในที่เขียนไว้ก็ไม่มีอะไรมากครับ ก็ให้ setText โดยเอาค่า countd มาแสดง วนไปเรื่อยๆ ครับ
ทีนี้เราก็จะได้การนับถอยหลัง ทุกๆ วินาทีล่ะครับ
เสร็จเรียบร้อยแล้วครับ ที่นี้เราก็ Run As ได้เลยครับ จะได้เห็นตามรูปด้านล่างนี้นะครับ (ตัวละครจะหันหน้ามาแล้วกระดุกกระดิกนะครับ)
ใช้เวลาเขียนบทความนี้ 4 ชั่วโมงกว่าเลยทีเดียว...เหนื่อยเอาเรื่องแฮะ
พบกันบทความหน้าครับ ถ้าไม่ขี้เกียจเสียก่อน เราจะมาสร้าง controller ควบคุมตัวละคร พร้อมกับปุ่ม action สัก 2 ปุ่ม เพื่อให้ตัวละครทำโน้นนี่นั่นกันครับ
มีปัญหาคาใจ ฝากคำถามไว้ได้เลยนะครับ อาจจะตอบช้าหน่อย แต่จะเข้ามาดูเรื่อยๆ จนกว่าจะลงบทความใหม่ครับ
ป.ล. บทความนี้ไม่ลงไฟล์ Source Code นะครับ จะได้ลองใส่ Code ดูเอง หากเกิด Error จะได้รู้ว่าเป็นที่จุดไหนครับ
อยากได้ Code ที่ทำให้ มอนเตอร์ที่เรากำหนดให้มันเดินตามเส้นทางที่เรากำหนดอ่ะครับ เหมือนเกม DotA TD อ่ะครับที่สร้างป้อมแล้วยิงมอนอ่ะครับอยาได้โค้ดที่ทำให้มอนวิ่งตามเส้นทางที่กำหนดครับ
ตอบลบAnd Engine มีคำสั่งการเดินตามเส้นทางแบบง่ายๆ อยู่ครับ ประยุกต์ตัวละครเป็น object ก็สามารถสร้างเกมแบบ ป้องกันป้อม ได้ไม่ยากครับ ^^
ลบเขียนต่อนะครับ ผมรอติดตามอยู่ครับ ตอนนี้ผมกำลังทำโปรเจคจบอยู่เรื่องเกมส์ บทความนี้เป็นประโยชน์กับผมมากเลยครับ
ตอบลบขอบคุณมากครับ ยังไงก็จะทยอยเข็นออกมาให้เป็นเกมให้ได้ครับ
ลบขอบคุณครับ ได้อะไรเยอะลย
ตอบลบมือใหม่หัดเขียนเกม ขอบคุณครับ
ตอบลบสุดยอดมากเลยคะ ติดตามและตามทำตาม
ตอบลบขอบคุณมากคะ
ตอบลบขอบคุณสำหรับการ แบ่งปันนะครับ สู้ๆ ครับ :)
ตอบลบเยี่ยมไปเลยครับ
ตอบลบจิ้ม จิ้ม
เยี่ยมครับ
ตอบลบสุดยอด ขอบคุณครับ
ตอบลบขอบคุณครับ
ตอบลบ