พัฒนาเกมบน iOS (iPhone/iPod/iPad) ตอนที่ 4 สร้างภาพเคลื่อนไหวจาก Sprite

บทความนี้เป็นบทความที่ตีพิมพ์ในนิตยสาร Pantip Guide ฉบับที่ 53 (ต.ค. – ธ.ค.) โดยเป็นการสอนพัฒนาเกมบนระบบปฏิบัติการ iOS (iPhone / iPod / iPad) ซึ่งในตอนนี้จะอธิบายกล่าวถึงการสร้างภาพเคลื่อนไหวจาก Sprite
สวัสดีท่านผู้อ่านทุกท่านครับ ในบทความตอนที่ผ่านมาผมได้กล่าวถึงการสร้างเกม Shooting ซึ่งเป็นเกมพื้นฐานที่สามารถต่อยอดให้เป็นเกมยอดฮิตในหลายๆ เกม โดยที่ผ่านมาได้พูดถึงเพียงแค่การแสดงผลรูป Sprite ที่เป็นภาพนิ่งเท่านั้น ซึ่งในเกมจริงๆ แล้วจะต้องมีภาพเคลื่อนไหว หรือแอนิเมชัน (Animation) ประกอบเพื่อนให้เกิดความน่าสนใจ ความสวยงาม และความสมจริง โดยในบทความนี้จะกล่าวถึงการสร้างภาพเคลื่อนไหวที่เกิดจากการนำภาพ Sprite ที่เป็นภาพนิ่งหลายๆ ภาพ หรือเราเรียกว่าเฟรม นำมาแสดงผลต่อเนื่องกันกลายเป็นภาพเคลื่อนไหว
ขั้นตอนการทำภาพเคลื่อนไหว เริ่มต้นจากการเตรียมภาพกราฟิกที่เป็นภาพนิ่งต่อเนื่องกัน โดยจะสร้างจากโปรแกรมสร้างรูปภาพอะไรก็ได้ โดยแนะนำว่าภาพควรมีขนาดเท่ากัน โดยตัวอย่างในบทความนี้เป็นรูปปลาทองในท่าเคลื่อนไหวปกติ มีขนาด 230 x 230 พิกเซล จำนวน 40 รูป มีตัวอย่างแสดงดังรูปที่ 1-4

 

รูปที่ 1 Goldfish_normal0001.png

 

รูปที่ 2 Goldfish_normal0002.png

 


รูปที่ 3 Goldfish_normal0003.png

 


รูปที่ 4 Goldfish_normal0004.png

 

เมื่อเราได้ภาพนิ่งต่อเนื่องกันแล้ว จากนั้นเป็นขั้นตอนการนำภาพไปรวมกันเป็นไฟล์เดียวเรียกว่า Sprite โดยการวางภาพต่อๆ กัน และเก็บพิกัดของแต่ละรูปย่อย ซึ่งขั้นตอนนี้จะทำเองด้วย Photoshop ก็สามารถทำได้แต่ยุ่งยาก เรามีโปรแกรมฟรีให้ใช้ผ่านทางเว็บไซต์ นั่นก็คือเว็บ http://zwoptexapp.com/ โดยจะเลือกทำผ่านเว็บเลยหรือดาวน์โหลดซอฟต์แวร์มาใช้ที่เครื่องก็ได้ ในที่นี้ผมใช้ผ่านเว็บเลยละกันสะดวกดีครับ เริ่มต้นด้วยการเข้าเว็บไซต์ http://zwoptexapp.com/flashversion จะได้ดังรูปที่ 5

 


รูปที่ 5 เว็บไซต์สำหรับสร้าง Sprite

 

จากนั้นเลือกเมนู File > Import Images แล้วเลือกภาพนิ่งที่ต่อเนื่องทุกรูป ก็จะพบว่าทุกรูปไปรวมซ้อนกันอยู่ ให้เลือกเมนู Arrange > By Name & Width จะได้ดังรูปที่ 6 ซึ่งแล้วแต่เราว่าต้องการให้เรียงภาพแบบใด ซึ่งมีหลายแบบให้เลือก

 


รูปที่ 6 แสดงภาพที่นำเข้าไปในโปรแกรม

 

จากนั้นเลือกเมนู File > Export Texture แล้วตั้งชื่อ ในที่นี้ผมตั้งชื่อเป็น normal.png โดยจะได้รูปออกมา ดังรูปที่ 7 จากนั้นเลือกเมนู File > Export Coordinates แล้วตั้งชื่อ ในที่นี้ผมตั้งชื่อเป็น normal.plist ซึ่งไฟล์นี้จะเก็บข้อมูลของพิกัดรูปแต่ละรูปไว้ เพื่อที่เวลาเรียกชื่อรูปย่อยไหนแล้วจะได้มาตัดรูปตามพิกัดที่เก็บอยู่ในไฟล์ normal.plist


รูปที่ 7 รูปที่ถูก Export ออกมาในชื่อ normal.png

 

เมื่อเราเตรียมภาพกราฟิกเรียบร้อยแล้ว ขั้นตอนต่อไปก็เป็นการเขียนโปรแกรมเพื่อให้สามารถแสดงผลเป็นภาพเคลื่อนไหวอยู่ใน iPhone หรือ iPad ก็ได้ โดยในตัวอย่างนี้จะให้ภาพเคลื่อนไหวปลาทองว่ายไปจนชนขอบซ้าย แล้วว่ายกลับมาจนชนขอบขวาไปเรื่อย ซึ่งขั้นตอนการเขียนโปรแกรมเริ่มต้นด้วยการสร้างโปรเจคใหม่ โดยบทความนี้ใช้ชื่อว่า iOSGame04 ดังรูปที่ 8-9 เลือก device เป็น iPad โดยในบทความนี้ผมได้เปลี่ยนเป็น XCode 4 แล้วนะครับ ถ้าใครเป็นสมาชิก iOS Developer Program ก็สามารถดาวน์โหลดมาใช้ได้เลย หรือถ้าใครไม่ได้เป็นสมาชิก iOS Developer Program แล้วซื้อระบบปฏิบัติการใหม่คือ Lion ก็สามารถดาวน์โหลด XCode 4 ได้ฟรีเช่นกัน

 


รูปที่ 8 สร้างโปรเจคใหม่ชื่อ iOSGame04

 


รูปที่ 9 หน้าต่าง XCode 4

 

ต่อไปนำรูป normal.png และไฟล์ normal.plist เข้าไปไว้ในโฟวเดอร์ Resources (อย่าลืมเลือกเครื่องหมายถูกในช่อง Copy…)
จากนั้นเริ่มต้นเขียนคำสั่งประกาศตัวแปร sprite เพื่อเก็บรูป ตัวแปร size เพื่อเก็บขนาดของหน้าจอ ตัวแปร flip เพื่อเก็บค่าการกลับซ้าย-ขวาของตัวปลาทอง และตัวแปร dx เก็บค่าการขยับตำแหน่งของปลา โดยประกาศไว้ในไฟล์ HelloWorldLayer.m ดังนี้

 

CCSprite *sprite;
CGSize size;
BOOL flip;
int dx = -1;

 

 

สำหรับคำสั่งที่ใช้ในการแสดงภาพเคลื่อนไหวจะมีอยู่ 4 ส่วนด้วยกันคือ ส่วนแรกนำไฟล์ .plist และไฟล์รูปเก็บไว้ใน CCSpriteFrameCache และ CCSpriteBatchNode ตามลำดับ

 

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"normal.plist"];
CCSpriteBatchNode *sheet = [CCSpriteBatchNode batchNodeWithFile:@"normal.png"];
[self addChild:sheet];

 

 

ส่วนที่สอง กำหนดให้ตัวแปร sprite เก็บไฟล์รูปแรกของภาพเคลื่อนไหว และกำหนดตำแหน่งเริ่มต้นของปลาทอง ดังนี้

 

sprite = [CCSprite spriteWithSpriteFrameName:@"Goldfish_nonmal0001.png"];
sprite.position = ccp(size.width/2, size.height/2);
[sheet addChild:sprite];

 

 

ส่วนที่สาม สร้างอาเรย์เพื่อเก็บไฟล์รูปในแต่ละเฟรม ตามจำนวนเฟรมทั้งหมดที่มีอยู่ ซึ่งในตัวอย่างนี้มีทั้งหมด 40 เฟรม

 

NSMutableArray *animeFrames = [NSMutableArray array];
for(int i=1;i<=40;++i)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:[NSString stringWithFormat:@"Goldfish_nonmal%04d.png",i]];
[animeFrames addObject:frame];
}

 

 

ส่วนสุดท้ายของการทำภาพเคลื่อนไหวคือการสร้าง Action การทำให้ภาพเคลื่อนไหวโดยใช้คลาส CCAnimation โดยแสดงผลเฟรมละ 0.1 วินาที จากนั้นสั่งให้รัน Action วนลูปไปเรื่อยๆ

 

CCAnimation *animation = [CCAnimation animationWithFrames:animeFrames delay:0.1f];
[sprite runAction:[CCRepeatForever actionWithAction:[CCAnimate
actionWithAnimation:animation restoreOriginalFrame:NO]]];

 

ซึ่งคำสั่งทั้งสี่ส่วนนี้เขียนรวมอยู่ในเมธอด init ดังนี้

 

-(id) init
{
if( (self=[super init])) {

size = [[CCDirector sharedDirector] winSize];

flip = NO;

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"normal.plist"];
CCSpriteBatchNode *sheet = [CCSpriteBatchNode batchNodeWithFile:@"normal.png"];
[self addChild:sheet];

sprite = [CCSprite spriteWithSpriteFrameName:@"Goldfish_nonmal0001.png"];
sprite.position = ccp(size.width/2, size.height/2);
[sheet addChild:sprite];

NSMutableArray *animeFrames = [NSMutableArray array];
for(int i=1;i<=40;++i)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:[NSString stringWithFormat:@"Goldfish_nonmal%04d.png",i]];
[animeFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithFrames:animeFrames delay:0.1f];
[sprite runAction:[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation
restoreOriginalFrame:NO]]];

[self schedule:@selector(update:) interval:0.001f];
}
return self;
}

 

 

โดยคำสั่ง [self schedule:@selector(update:) interval:0.001f]; เป็นคำสั่งสำหรับเรียกเมธอด update ทุกๆ 0.001 วินาทีเพื่อให้ตัวปลาทองเปลี่ยนตำแหน่งไปด้วย

 

จากนั้นสร้างเมธอด update เพื่อให้ตัวปลาทองเปลี่ยนตำแหน่งโดยจะเปลี่ยนตำแหน่งทีละ dx เริ่มต้นเปลี่ยนตำแหน่งไปด้านซ้ายจนชนขอบ ก็จะปรับค่า flipX เป็น YES เพื่อให้ปลากลับตัวแล้ววิ่งไปจนชนขอบขวา วนแบบนี้ไปเรื่อยๆ

 

-(void) update:(ccTime) deltaTime
{
if ( (sprite.position.x - sprite.contentSize.width/2) <0) { dx *= -1; sprite.flipX = YES; } if ( (sprite.position.x+sprite.contentSize.width/2) > size.width) {
dx *= -1;
sprite.flipX = NO;
}
sprite.position = ccp(sprite.position.x+dx, sprite.position.y);
}

 

 

สุดท้ายคืนค่าหน่วยความจำในเมธอด dealloc ดังนี้

- (void) dealloc
{
[[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFrames];

[super dealloc];
}

 

 

เป็นอันเสร็จเรียนร้อย ถ้าไม่มีอะไรผิดพลาดเมื่อเรากดรัน ก็จะพบว่ามีปลาทองว่ายวนไปมาใน iOS Simulator – iPad ดังรูปที่ 10-11
รูปที่ 10-11 ผลลัพธ์การสร้างภาพเคลื่อนไหว

 

 

รูปที่ 10-11 ผลลัพธ์การสร้างภาพเคลื่อนไหว

 

จากบทความข้างต้นนี้เราก็สามารถนำไปประยุกต์ต่อกับภาพเคลื่อนไหวอื่นๆ และจากทั้งสี่บทความที่ผ่านมานี้ ลองนำมาประกอบกันเพื่อให้ได้เป็นเกมตามที่เราออกแบบไว้ ไม่แน่นะครับเกมที่เราสรรค์สร้างขึ้นในวันนี้อาจจะมีคนโหลดเล่นเป็นล้าน ใครจะไปรู้!!!

 

มนตรี อินทโชติ
สาขาวิชาคอมพิวเตอร์เกมมัลติมีเดีย
คณะเทคโนโลยีสารสนเทศ
มหาวิทยาลัยรังสิต

Leave a Reply