DeveloperFeaturedGame DevelopmentGame DevelopmentiOS DeveloperObject Oriented TechnologyObjective CProgramming Language

เขียนเกม iPhone ด้วย Sprite Kit บังคับตัวละครวิ่งตาม Line ที่วาด

วิธีการพัฒนาเกม สำหรับผู้ที่ต้องการเขียนเกมบน iPhone หรือ iOS7 ด้วย Sprite Kit กับการบังคับให้ตัวละครในเกมวิ่งตาม Line ที่เราวาดบนหน้าจอสมาร์ทโฟนแบบง่ายครับ

เริ่มต้นให้เปิด XCode 5.1 ขึ้นมาครับ (ที่ใช้ปัจจุบันตอนนี้) แล้ว New Project เป็น Sprite Kit สำหรับเขียนเกม 2D บน แพลตฟอร์ม iOS7 ครับ ตั้งชื่อ Project ให้เรียบร้อยเลยครับ

Screen Shot 2557-05-18 at 5.17.51 PM

Screen Shot 2557-05-18 at 5.18.11 PM

ต่อมาให้ไปแก้ไขไฟล์ MyScene.m  ให้เป็นดังนี้ครับ เพื่อล้างค่า Project Sample เครื่องบินก่อนหน้านี้

#import "MyScene.h"

@implementation MyScene

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
}

@end

ลองทำการ “Run” ตัว Project ของเราก่อนครับเพื่อดูว่า ไม่มีอะไรผิดพลาด

Screen Shot 2557-05-18 at 5.22.11 PM

เมื่อทดสอบเสร็จแล้วต่อมา เราต้องมีการประกาศ ตัวแปรสำหรับ BG และ Character ครับ ให้สร้าง Group ชื่อ Graphics ขึ้นมาก่อน

Screen Shot 2557-05-18 at 5.28.34 PM

เอาภาพ BG และ Character ที่เตรียมมาแล้วไปวางใน Group ของ Bundles Project เราครับ แล้วเขียน Code เพิ่มใน MyScene.m ใน เมธอด -(id)initWithSize:(CGSize)size ดังนี้

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:@"BG"];
        bg.anchorPoint = CGPointZero;
        [self addChild:bg];
        
        SKSpriteNode * character = [SKSpriteNode spriteNodeWithImageNamed:@"here"];
        character.position = CGPointMake(self.size.width / 2.0f, self.size.height / 2.0f);
        [self addChild:character];
    }
    return self;
}

โดยเรียก BG.png เป็นฉากหลัง และ here.png เป็น Character ครับ ทดสอบโดยการ “Run” ตัว Project อีกครั้ง ว่าถูกต้องหรือเปล่า?

Screen Shot 2557-05-18 at 5.38.11 PM

นั่นคือสัญญาณที่ดีครับไม่มีปัญหาอะไร ต่อมาก็เริ่ม เขียน Code ให้ตัวละครของเราเดินทางตามเส้นที่เราลากไปมาบนเกมกันครับ เราจะต้องสร้าง Class ขึ้นมาใหม่ ตั้งชื่อว่า Player ครับ

ทำการ New File ขึ้นมาครับ
ทำการ New File ขึ้นมาครับ
ตั้งตามตัวอย่างนี้นะครับ
ตั้งตามตัวอย่างนี้นะครับ

เปิดไฟล์ Player.h ขึ้นมาครับ เพิ่ม เมธอดใหม่ประกาศขึ้นมา คือ เมธอดในการเก็บค่า Point ของตำแหน่งที่เรากดลงหน้าจอ และ เมธอด Walk สำหรับให้ ตัวละครเราเดินตามไป

#import <SpriteKit/SpriteKit.h>

@interface Player : SKSpriteNode
- (void)addNewPoint:(CGPoint)point;
- (void)walk:(NSNumber *)dt;
@end

สำหรับ ไฟล์ Player.m นั้นให้เรากำหนดการเคลื่อนไหวของตัวละครเราหน่อยครับ ประกาศคำสั่งตามนี้

#import "Player.h"

static const int POINTS_PER_SEC = 80;
@implementation Player
{
    NSMutableArray *_wayPoints;
    CGPoint _velocity;
}

- (instancetype)initWithImageNamed:(NSString *)name {
    if(self = [super initWithImageNamed:name]) {
        _wayPoints = [NSMutableArray array];
    }
    
    return self;
}

มีการกำหนด Constant ตัวแปรเป็น ความเร็วการเคลื่อนไหวต่อวินาที 80 ครับ ตามด้วยกำหนด NSMutableArray ขึ้นมา และ CGPoint สำหรับเก็บค่าปลายทางที่เราจะทำการ Touch ที่หน้าจอ

เพิ่ม เมธอดใน Player.m อีกที 2 เมธอด ตามด้วยคำสั่งดังนี้ครับ

- (void)addNewPoint:(CGPoint)point {
    [_wayPoints addObject:[NSValue valueWithCGPoint:point]];
}

- (void)walk:(NSNumber *)dt {
    CGPoint currentPosition = self.position;
    CGPoint newPosition;
    
    //1
    if([_wayPoints count] > 0) {
        CGPoint targetPoint = [[_wayPoints firstObject] CGPointValue];
        
        CGPoint offset = CGPointMake(targetPoint.x - currentPosition.x, targetPoint.y - currentPosition.y);
        CGFloat length = sqrtf(offset.x * offset.x + offset.y * offset.y);
        CGPoint direction = CGPointMake(offset.x / length, offset.y / length);
        _velocity = CGPointMake(direction.x * POINTS_PER_SEC, direction.y * POINTS_PER_SEC);
        
        
        //2 TODO: Add movement logic here
        newPosition = CGPointMake(currentPosition.x + _velocity.x * [dt doubleValue],
                                  currentPosition.y + _velocity.y * [dt doubleValue]);
        self.position = newPosition;
        
        //3
        if(CGRectContainsPoint(self.frame, targetPoint)) {
            [_wayPoints removeObjectAtIndex:0];
        }
    }
}

เป็นการคำนวณ ระยะ ของตำแหน่งที่เราแตะ และ คำนวณต้นทางไป ยังปลายทางเรียบร้อย ต่อมาไปที่ไฟล์ MyScene.m ครับ ทำการ Import Header ของ Player.h ลงไป พร้อมตัวแปรเพิ่มเติมครับ

#import "MyScene.h"
#import "Player.h"

@implementation MyScene
{
    Player *_movingPlayer;
    NSTimeInterval _lastUpdateTime;
    NSTimeInterval _dt;
}

มีการเก็บ Interval ในการรับ เวลาของการเคลื่อนไหวของตัวละครเข้ามา เพื่อใช้กับเมธอด update() ที่มีอยู่ ได้อย่างสมบูรณ์ครับต่อจากนั้น แก้ไข เมธอด -(id)initWithSize() จากเดิมคือ

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:@"BG"];
        bg.anchorPoint = CGPointZero;
        [self addChild:bg];
        
        SKSpriteNode *character = [SKSpriteNode spriteNodeWithImageNamed:@"here"];
        character.position = CGPointMake(self.size.width / 2.0f, self.size.height / 2.0f);
        [self addChild:character];
    }
    return self;
}

ให้เป็น

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:@"BG"];
        bg.anchorPoint = CGPointZero;
        [self addChild:bg];
        
        Player *character = [[Player alloc] initWithImageNamed:@"here"];
        character.name = @"player";
        character.position = CGPointMake(self.size.width / 2.0f, self.size.height / 2.0f);
        [self addChild:character];
    }
    return self;
}

เป็นการจำ Node ของ Player ขึ้นมาว่าชื่อ Player สำหรับอ้างอิงครับ ต่อมาไปแก้ไข เมธอด touchBegan() ดังนี้

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */
    CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
    SKNode *node = [self nodeAtPoint:touchPoint];
    
    if([node.name isEqualToString:@"player"]) {
        [(Player *)node addNewPoint:touchPoint];
        _movingPlayer = (Player *)node;
    }

}

เพิ่มเมธอดใหม่เข้าไปอีกนิดคือ

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
    if(_movingPlayer) {
        [_movingPlayer addNewPoint:touchPoint];
    }
}

อย่าลืมอัพเด็ท Interval ของ เมธอด update() ครับผม

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
    _dt = currentTime - _lastUpdateTime;
    _lastUpdateTime = currentTime;
    
    [self enumerateChildNodesWithName:@"player" usingBlock:^(SKNode *character, BOOL *stop) {
        [(Player *)character walk:@(_dt)];
    }];
}

เอาล่ะ ลองทดสอบ “Run” ตัว Project ของเราหน่อยดีกว่า

Screen Shot 2557-05-18 at 6.06.22 PM

ทำการ Slide หน้าจอไปตาม ตำแหน่งต่างๆ ตัวละครของเราจะเดินตามมันไปครับ ตามเส้นที่เราวาดไว้ ทุกอย่างเลย

Screen Shot 2557-05-18 at 6.06.30 PM

ดาวน์โหลด Source Code : http://adf.ly/nNqrx

หวังว่าคงจะช่วยเหลือเพื่อนๆ ที่ต้องการเขียนเกมบน iOS7 ด้วย Sprite Kit ได้นะครับ

เพิ่มเติม

สำหรับใครที่สนใจพัฒนาแอพพลิเคชัน บน iOS7.1 สามารถซื้อหนังสือของ เว็บไซต์ Daydev ได้แล้วตาม รายละเอียดนี้ครับ

[fb_embed_post href=”https://www.facebook.com/photo.php?fbid=777971808913916&set=a.390784317632669.96833.323517721025996&type=1/” width=”600″/]

Asst. Prof. Banyapon Poolsawas

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

Related Articles

Back to top button

Adblock Detected

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