2D Game DevelopmentBeginningDeveloperFeaturedGame DevelopmentGame DevelopmentiOS DeveloperNewbieObject Oriented TechnologyObjective CProgramming Language

เขียนเกม iPhone คำสั่งจำเป็นของเกมบน Cocos2D V 3.2.1

บทเรียนเขียนเกมด้วย Cocos2D นั้นในเว็บไซต์นี้มีการแนะนำมาพอประมาณแล้วจนกระทั่ง เวอร์ชัน 3.2.1 ที่รองรับ Xcode6 เรามาแนะนำคำสั่งจำเป็นผ่านตัวอย่างง่ายๆ กัน

ในเวอร์ชัน 3.2.1 ของ Cocos2D นั้นจะไม่มีการ Install Template ผ่าน Command Line เหมือนเวอร์ชันก่อนๆ หน้านี้ครับ ดังนั้นการเริ่มต้นติดตั้งของ Cocos2D V 3.2.1 นั้นจะต้องดาวน์โหลดตัว Installer มาก่อน ซึ่งก็สามารถไปดาวน์โหลดได้ที่ https://s3.amazonaws.com/spritebuilder/Cocos2D+Installer+3.1.0.zip

เมื่อดาวน์โหลดมาแล้วให้คลิกที่ไฟล์ DMG ของมันเลยครับเพื่อทำการติดตั้ง Template ของ Xcode 6 ก็คงไม่น่าอยากอะไรครับ แค่คลิก คลิก คลิก แล้วก็จบ

เริ่มต้นทำการ New Project ขึ้นมาใหม่เลือก Template เป็น Cocos2D iOS ครับ

Screen Shot 2557-11-06 at 9.02.45 AM

ตั้งชื่อ Project ของเราสักหน่อย

Screen Shot 2557-11-06 at 9.03.07 AM

ทดสอบ Project ของเราโดยการ Run ตัว Xcode 6 ไปเลยครับ ว่าใช้งานได้หรือไม่

แปลว่าได้
แปลว่าได้
แบบนี้แปลว่าโอเค
แบบนี้แปลว่าโอเค

อาจารย์ครับ เกิด Error!

หากว่าเกิด Error ขึ้นมามากมายนะครับ ให้ทำการแก้ไขดังนี้ ไปที่ Tab ของ Build Phase ครับทำการ Import ตัว Framework เหล่านี้เข้าไปให้หมด

ตั้งสติแล้วเพิ่ม Framework
ตั้งสติแล้วเพิ่ม Framework

ที่เพิ่ม Param ที่ Other Link Flag เล็กน้อยเหมือนตัวอย่างข้างล่างครับ ใน Tab ชื่อ Build Setting

Screen Shot 2557-11-06 at 9.21.05 AM

ทำการ Clean รอบนึงก่อน ปิด Xcode แล้ว เปิดเรียก Project มาใหม่อีกครั้งครับ แล้วลอง Run ดู

Screen Shot 2557-11-06 at 9.21.26 AM

หากว่ากด Start Game แล้วเราจะพบ Logo เจ้า Cocos2D V3 หมุนไปมา แตะที่ตำแหน่งไหนก็จะเลื่อนไปตำแหน่งนั้น หากกดปุ่ม Menu ก็จะกลับไปหน้า Title ของเกม

เราลองหากราฟิกมาสักหนึ่งภาพ เซฟชื่อว่า players.png ดูครับ แล้วไปแก้ไขที่ File ชื่อ HelloWorldScene.m ส่วนนี้

_sprite = [CCSprite spriteWithImageNamed:@"players.png"];
_sprite.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
[self addChild:_sprite];

ทำการ Run ดูหน่อยจะเห็นว่ากราฟิก Players ของเราจะหมุนๆๆๆๆๆ

หมุนๆ ไป
หมุนๆ ไป

โอเค ทีนี้เรามาจินตนาการถึงเกม สมัยโบราณเครื่อง Famicom 8Bits อย่าง Dragon Ball Z ที่มีการเปิดไพ่ต่อสู้กัน เราจะต้องจินตนาการออกมาว่าเกมของเราจะต้องมีองค์ประกอบต่อไปนี้

  • มีไพ่เรียงกันข้างล่างจอเกม
  • มีตัวละครเหาะขึ้นไปตีกันบนฟ้า
  • ฉากข้างล่าง คือองค์ประกอบต่างๆ
  • เปิดไพ่แล้วจะโจมตี

คิดว่าหลายคนต้องจำได้แน่ๆ ดังนั้นเรามาออกแบบฉาก กันหน่อยดีกว่า เริ่มต้นโดยการหากราฟิกฉากหลังครับตั้งชื่อว่า bg.png

bg.png
bg.png

ประกาศตัวแปรตามนี้ใน HelloWorldScene.m

@implementation HelloWorldScene
{
    CCSprite *_sprite;
    CCSprite *_background;
}

ไปที่ -(id)init ครับเพิ่ม CCSprite ดังนี้

// Add a forgound
    _background = [CCSprite spriteWithImageNamed:@"bg.png"];
    _background.anchorPoint=ccp(1,1);
    _background.position  = ccp(_background.contentSize.width,_background.contentSize.height+100);
    [self addChild:_background];

ต่อมาหาตัวละครครับ ผมหาฉากกำลังเหาะขึ้นตั้งชื่อว่า player-jump.png ขึ้นมา

player-jump.png
player-jump.png

ไม่ต้องทำอะไรมากครับ แก้ไข players.png เป็น player-jump.png แทน ซึ่งอาจจะเขียนแยกตัวแปรของ Frame ตัวละครได้ดังนี้

text1 = @"player-jump.png";
_sprite = [CCSprite spriteWithImageNamed:text1];
_sprite.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
[self addChild:_sprite];

เพิ่มตัวศัตรู หาไฟล์ชื่อ enemy.png มาแล้วทำเหมือนประกาศตัวแปร CCSprite ตัวอื่นๆ ครับ

@implementation HelloWorldScene
{
    CCSprite *_sprite;
    CCSprite *_background;
    CCSprite *_enemy;
}

แก้ไข -(id)init อีกครั้ง

// Add an enemy
_enemy = [CCSprite spriteWithImageNamed:@"enemy.png"];
_enemy.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
[self addChild:_enemy];

สุดท้ายคือไพ่มาตั้งชื่อ ว่า backcards.png ครับ

จำไว้ว่า กว้าง 73px
จำไว้ว่า กว้าง 73px

ให้เปิดไฟล์ HelloWorldScene.m ขึ้นมา เพิ่มตัวแปล _cards เป็นประเภท CCSprite เพื่อตั้งให้มันเป็น Sprite สำหรับใช้ในเกมครับ

@implementation HelloWorldScene
{
    CCSprite *_sprite;
    CCSprite *_background;
    CCSprite *_enemy;
    CCSprite *_cards;
}

แก้ไข -(id)init ของส่วน backcards.png เข้าไป แต่จะต้องเรียงไพ่เหมือนกัน 11 ใบให้ใช้คำสั่ง CCsprite เหมือน Players แต่ให้เอา Loop ของ For มาวนไว้

//Add Card
    int diffY = 11;
    //Add Card Loops
    for (int y = 0; y < diffY; y++){
        _cards = [CCSprite spriteWithImageNamed:@"backcards.png"];
        _cards.anchorPoint=ccp(1,1);
        _cards.position  = ccp(_cards.contentSize.width + (71*y) , _cards.contentSize.height);
        [self addChild:_cards];
        
    }

ทีนี้จะลองทำภาพเคลื่อนไหวขึ้นมาหน่อย คือ ตัวละครบินขึ้น ฉากหลังเลื่อนลง ให้สร้าง Method Function ต่อไปนี้ครับ

-(void)onStartGame
{
    
    CCActionMoveTo *BGMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(_contentSize.width+60,201)];
    CCActionMoveTo *PlayerMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(60,225)];
    CCActionMoveTo *EnemyMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(510,225)];
    
    [_sprite runAction:PlayerMove];
    [_enemy runAction:EnemyMove];
    [_background runAction:BGMove];
}

อธิบาย ฟังก์ชัน onStartGame จะมีการบังคับฉากหลัง BGMove ให้แกน x เลื่อนลงไปที่ 201 เช่นกัน PlayerMove ตัวละครเลื่อนไปทางขวา และบินขึ้น แกน x ไปที่ 60 ชิดซ้าย และ แกน y ไปที่ 225 เลื่อนขึ้น และ EnemyMove เหมือน Player ทุกอย่างต่างกันแค่ แกน x ไปทางขวาที่ 510 ครับ

ลอง Run ตัวเกมของเราหน่อย

เลื่อนตัวละครเมื่อเริ่มเกม
เลื่อนตัวละครเมื่อเริ่มเกม

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

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    
    CGPoint touchLoc = [touch locationInNode:self];
    
    if(touchLoc.y<140){
        //CCLOG(@"%f",(touchLoc.x));
        if(touchLoc.x > 502){
            CCLOG(@"8");
        }else if (touchLoc.x < 502 && touchLoc.x > 431){
            CCLOG(@"7");
        }else if (touchLoc.x < 431 && touchLoc.x > 360){
            CCLOG(@"6");
        }else if (touchLoc.x < 360 && touchLoc.x > 288){
            CCLOG(@"5");
        }else if (touchLoc.x < 288 && touchLoc.x > 215){
            CCLOG(@"4");
        }else if (touchLoc.x < 215 && touchLoc.x > 145){
            CCLOG(@"3");
        }else if (touchLoc.x < 145 && touchLoc.x > 74){
            CCLOG(@"2");
        }else{
            CCLOG(@"1");
            [self Action1];
        }
    }
}

อธิบาย คือ เก็บพิกัด CGPoint ที่นิ้วเราแตะ ในส่วนของแกน y ตำแหน่ง 140 ลงมา จะมีผลต่อเกม แบ่งระยะ แกน x ให้กว้างเท่ากับขนาดของไพ่ 73 pixels แล้ว

ตัวอย่างที่ยกมาคือ แตะที่ไพ่ใบแรกให้เรียกฟังก์ชัน [self Action1]; ดังนั้นเราต้องไปเพิ่มฟังก์ชัน Action1() ครับ

-(void)Action1
{
    CCActionMoveTo *PlayerMove = [CCActionMoveTo actionWithDuration:0.4f position:ccp(470,225)];   
    [_sprite runAction:PlayerMove];
}

ฟังก์ชัน Action1 นั้นจะเป็นการเลื่อนตัวละคร Player เข้าไปโจมตี Enemy ทันที ทดสอบการ Run เกมของเราอีกครั้ง แล้วทำการแตะที่ไพ่ใบแรก

Screen Shot 2557-11-06 at 3.27.26 PM

เท่านี้ก็ได้ไอเดียทำเกม เปิดไพ่แล้วล่ะครับ ที่เหลือที่ต้องทำเพิ่มคือ ระบบ Fuzzy Logic สลับแต้มของไพ่ และเปิดไพ่ขึ้นมา พร้อมกับระบบ AI คำนวณให้ Enemy โจมตีเรากลับ เท่านั้นเอง

Source Code ของไฟล์ HelloWorldScene.m ก็คือ

//
//  HelloWorldScene.m
//  Cocos2D3
//
//  Created by DAYDEV on 11/6/2557 BE.
//  Copyright DAYDEV 2557. All rights reserved.
//
// -----------------------------------------------------------------------

#import "HelloWorldScene.h"
#import "IntroScene.h"

// -----------------------------------------------------------------------
#pragma mark - HelloWorldScene
// -----------------------------------------------------------------------

@implementation HelloWorldScene
{
    CCSprite *_sprite;
    CCSprite *_background;
    CCSprite *_cards;
    CCSprite *_enemy;
    NSString *text1;
    NSString *text2;

}

// -----------------------------------------------------------------------
#pragma mark - Create & Destroy
// -----------------------------------------------------------------------

+ (HelloWorldScene *)scene
{
    return [[self alloc] init];
}

// -----------------------------------------------------------------------

- (id)init
{
    // Apple recommend assigning self with supers return value
    self = [super init];
    if (!self) return(nil);
    
    // Enable touch handling on scene node
    self.userInteractionEnabled = YES;
    
    // Create a colored background (Dark Grey)
    CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f]];
    [self addChild:background];
    
    // Add a forgound
    _background = [CCSprite spriteWithImageNamed:@"bg.png"];
    _background.anchorPoint=ccp(1,1);
    _background.position  = ccp(_background.contentSize.width,_background.contentSize.height+100);
    [self addChild:_background];
    
    // Add an enemy
    _enemy = [CCSprite spriteWithImageNamed:@"enemy.png"];
    _enemy.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
    [self addChild:_enemy];
    
    // Add a sprite
    text1 = @"player-jump.png";
    text2 = @"player_kick.png";
    
    _sprite = [CCSprite spriteWithImageNamed:text1];
    
    
    _sprite.position  = ccp(self.contentSize.width/2,self.contentSize.height/2);
    [self addChild:_sprite];
    
    
    //Add Card
    int diffY = 11;
    //Add Card Loops
    for (int y = 0; y < diffY; y++){
        _cards = [CCSprite spriteWithImageNamed:@"backcards.png"];
        _cards.anchorPoint=ccp(1,1);
        _cards.position  = ccp(_cards.contentSize.width + (71*y) , _cards.contentSize.height);
        [self addChild:_cards];
        
    }
    
    //Create a back button
    CCButton *backButton = [CCButton buttonWithTitle:@"QUIT GAME" fontName:@"Verdana-Bold" fontSize:12.0f];
    backButton.positionType = CCPositionTypeNormalized;
    backButton.position = ccp(0.85f, 0.95f); // Top Right of screen
    [backButton setTarget:self selector:@selector(onBackClicked:)];
    [self addChild:backButton];
    
    [self onStartGame];

    // done
	return self;
}

// -----------------------------------------------------------------------

- (void)dealloc
{
    // clean up code goes here
}

// -----------------------------------------------------------------------
#pragma mark - Enter & Exit
// -----------------------------------------------------------------------

- (void)onEnter
{
    // always call super onEnter first
    [super onEnter];
    
    // In pre-v3, touch enable and scheduleUpdate was called here
    // In v3, touch is enabled by setting userInteractionEnabled for the individual nodes
    // Per frame update is automatically enabled, if update is overridden
    
}

// -----------------------------------------------------------------------

- (void)onExit
{
    // always call super onExit last
    [super onExit];
}

// -----------------------------------------------------------------------
#pragma mark - Touch Handler
// -----------------------------------------------------------------------

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    
    CGPoint touchLoc = [touch locationInNode:self];
    
    if(touchLoc.y<140){
        //CCLOG(@"%f",(touchLoc.x));
        if(touchLoc.x > 502){
            CCLOG(@"8");
        }else if (touchLoc.x < 502 && touchLoc.x > 431){
            CCLOG(@"7");
        }else if (touchLoc.x < 431 && touchLoc.x > 360){
            CCLOG(@"6");
        }else if (touchLoc.x < 360 && touchLoc.x > 288){
            CCLOG(@"5");
        }else if (touchLoc.x < 288 && touchLoc.x > 215){
            CCLOG(@"4");
        }else if (touchLoc.x < 215 && touchLoc.x > 145){
            CCLOG(@"3");
        }else if (touchLoc.x < 145 && touchLoc.x > 74){
            CCLOG(@"2");
        }else{
            CCLOG(@"1");
            [self Action1];
        }
    }
}

-(void)onStartGame
{
    
    CCActionMoveTo *BGMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(_contentSize.width+60,201)];
    CCActionMoveTo *PlayerMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(60,225)];
    CCActionMoveTo *EnemyMove = [CCActionMoveTo actionWithDuration:1.0f position:ccp(510,225)];
    
    [_sprite runAction:PlayerMove];
    [_enemy runAction:EnemyMove];
    [_background runAction:BGMove];
}

-(void)Action1
{
    
    CCActionMoveTo *PlayerMove = [CCActionMoveTo actionWithDuration:0.4f position:ccp(470,225)];
    
    [_sprite runAction:PlayerMove];
}


// -----------------------------------------------------------------------
#pragma mark - Button Callbacks
// -----------------------------------------------------------------------

- (void)onBackClicked:(id)sender
{
    // back to intro scene with transition
    [[CCDirector sharedDirector] replaceScene:[IntroScene scene]
                               withTransition:[CCTransition transitionPushWithDirection:CCTransitionDirectionRight duration:1.0f]];
}

// -----------------------------------------------------------------------
@end

ส่วน Source code ของ Project เกมนี้ก็ดาวน์โหลดที่นี่ครับ https://www.daydev.com/download/Cocos2D3.zip

Asst. Prof. Banyapon Poolsawas

อาจารย์ประจำสาขาวิชาการออกแบบเชิงโต้ตอบ และการพัฒนาเกม วิทยาลัยครีเอทีฟดีไซน์ & เอ็นเตอร์เทนเมนต์เทคโนโลยี มหาวิทยาลัยธุรกิจบัณฑิตย์ ผู้ก่อตั้ง บริษัท Daydev Co., Ltd, (เดย์เดฟ จำกัด)

Related Articles

Back to top button

Adblock Detected

เราตรวจพบว่าคุณใช้ Adblock บนบราวเซอร์ของคุณ,กรุณาปิดระบบ Adblock ก่อนเข้าอ่าน Content ของเรานะครับ, ถือว่าช่วยเหลือกัน