DeveloperGame DevelopmentiOS DeveloperObjective CProgramming LanguageSocial MediaSocial Media Marketing

iOS Game Developer Tutorial: การเรียกใช้ Collision Detect ผ่าน Cocos2D

การเรียกใช้คำสั่ง Collision Detect ด้วย Cocos2D ให้ตัวละครในเกมยิงกระสุน ไปโดนศัตรูให้หายไปได้ผ่าน XCode สำหรับ iOS Developer มือใหม่ที่อยากพัฒนาเกมจากบทความก่อนหน้านี้ “iOS Game Developer Tutorial: วางภาพ Spriteตัวละครลงในเกมด้วย Cocos2D” ที่มีการวางตัวละครลงไปในเกมแล้ว และมีศัตรูปรากฏวิ่งไปมาแล้วต่อไปเราต้องสร้างกระสุนของตัวละครให้ยิงออกไปโดนศัตรู เริ่มต้นสร้างกระสุน และวิธีในการยิงของเรา ให้ไปเพิ่มคำสั่งเล็กน้อยที่ ฟังก์ชัน init() ครับ ก่อนคำสั่งประกาศขนาดหน้าจอของเรา

self.isTouchEnabled = YES;
CGSize winSize = [[CCDirector sharedDirector] winSize];

หาภาพกราฟิก สำหรับสร้างเป็นลูกกระสุนของเรา ตั้งชื่อว่า “Bullet.png”  ขนาดความก้าว และ ความยาว 40×40 pixels

ไฟล์ชื่อ "Bullet.png"
ไฟล์ชื่อ “Bullet.png”

พร้อมทั้งใส่คำสั่งต่อไปนี้ลงไปในไฟล์  PlayScene.m เป็นการเรียกคำสั่งเดียวกับเมนูคือเมื่อมีการแตะแล้วปล่อยที่พิกัดใดๆ กระสุนจะวิ่งไปยังพิกัดดังกล่าว

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    
    // Choose one of the touches to work with
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    
    // Set up initial location of projectile
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    CCSprite *projectile = [CCSprite spriteWithFile:@"Bullet.png" 
    rect:CGRectMake(0, 0, 40, 40)];
    projectile.position = ccp(20, winSize.height/2);
    
    // Determine offset of location to projectile
    int offX = location.x - projectile.position.x;
    int offY = location.y - projectile.position.y;
    
    // Bail out if we are shooting down or backwards
    if (offX <= 0) return;

    [self addChild:projectile];

    int realX = winSize.width + (projectile.contentSize.width/2);
    float ratio = (float) offY / (float) offX;
    int realY = (realX * ratio) + projectile.position.y;
    CGPoint realDest = ccp(realX, realY);
    
    // Determine the length of how far we're shooting
    int offRealX = realX - projectile.position.x;
    int offRealY = realY - projectile.position.y;
    float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
    float velocity = 480/1; // 480pixels/1sec
    float realMoveDuration = length/velocity;
    
    // Move projectile to actual endpoint
    [projectile runAction:[CCSequence actions:
    [CCMoveTo actionWithDuration:realMoveDuration position:realDest],
    [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)],
    nil]];
    
}

ทดลอง "Run” ตัวแอพพลิเคชันดู แล้วทำการ คลิกไปที่ บริเวณใดๆ ของหน้าจอจะพบว่าตัวละครจะยิงกระสุนไป ยังบริเวณที่เราคลิก หรือทำการแตะ

กระสุนยิงกระจุย
กระสุนยิงกระจุย

วิธีการตรวจสอบการชนกันของวัตถุ หรือ Collision Detect
Collision Detect เป็นหลักการเดียวที่ทุกเกม ไม่ว่าจะอยู่บนแพลตฟอร์มใดๆ จะต้องใช้งานเป็นสากลเพราะเป็นการตรวจสอบว่าวัตถุชิ้นหนึ่งเมื่อซ้อนทับหรือชนกับอีกชิ้นหนึ่งแล้วจะเกิดเงื่อนไขอะไรขึ้นซึ่งในเกมของเราจะใช้อยู่ 2 เงื่อนไขหลักๆ คือ

  • กระสุนโดนศัตรู ศัตรก็จะตาย
  • ศัตรูโดนเรา เราก็ตาย “GameOver”

ให้ไปที่ไฟล์ PlayScene.h ครับทำการประกาศ ตัวแปลชนิด NSMutableArray ลงไปดังรูปแบบข้างล่าง

#import 
#import "cocos2d.h"
@interface PlayScene : CCLayer {
    NSMutableArray *_targets;
    NSMutableArray *_projectiles;
}

ต่อมาให้ไปเพิ่มคำสั่งในไฟล์ PlayScene.m ครับในฟังก์ชัน init() บรรทัดต่อจาก คำสั่ง self.isTouchEnabled = YES; ไปเลยครับ

-(id) init
{
 if( (self=[super init] )) {
        
 self.isTouchEnabled = YES;
 _targets = [[NSMutableArray alloc] init];
 _projectiles = [[NSMutableArray alloc] init];

ทำการคืนหน่วยความจำของกระสุนปืน และศัตรูของเราลงไปในฟังก์ชัน dealloc() ครับ

-(void)dealloc
{
    [_targets release];
    _targets = nil;
    [_projectiles release];
    _projectiles = nil;
	[super dealloc];
}

เพิ่มคำสั่งลงไปในฟังก์ชัน addTarget() ในตำแหน่งบรรทัดล่างสุดก่อนปิดฟังก์ชัน

[target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
// Add to targets array
target.tag = 1;
[_targets addObject:target];

ให้เข้าไปเพิ่มที่ฟังก์ชัน ccTouchesEnded เช่นกันในตำแหน่งก่อนปิดฟังก์ชันบรรทัดสุดท้าย

// Add to projectiles array
projectile.tag = 2;
[_projectiles addObject:projectile];

ต่อมาแก้ไข ฟังก์ชัน spriteMoveFinished จากเดิมคือ

-(void)spriteMoveFinished:(id)sender {
    CCSprite *sprite = (CCSprite *)sender;
    [self removeChild:sprite cleanup:YES];
}

ให้กลายเป็น

-(void)spriteMoveFinished:(id)sender {
    CCSprite *sprite = (CCSprite *)sender;
    [self removeChild:sprite cleanup:YES];
    
    if (sprite.tag == 1) { // target
        [_targets removeObject:sprite];
    } else if (sprite.tag == 2) { // projectile
        [_projectiles removeObject:sprite];
    }
}

ทำการ "Run” ตรวจสอบดูอีกครั้งว่ามี Error ปรากฏไหม เพราะว่าเรามากันไกลมากแล้ว, ต่อไปจะเป็นการตรวจสอบเงื่อนไขของการ ชนกันของวัตถุ ที่สำคัญมาก แทรกคำสั่งนี้ลงไปในไฟล์ PlayScene.m เลยครับ

- (void)update:(ccTime)dt {
    
    NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
    for (CCSprite *projectile in _projectiles) {
        CGRect projectileRect = CGRectMake(
                projectile.position.x - (projectile.contentSize.width/2), 
                projectile.position.y - (projectile.contentSize.height/2), 
                projectile.contentSize.width, 
                projectile.contentSize.height);
        
        NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
        for (CCSprite *target in _targets) {
            CGRect targetRect = CGRectMake(
                target.position.x - (target.contentSize.width/2), 
                target.position.y - (target.contentSize.height/2), 
                target.contentSize.width, 
                target.contentSize.height);
            
            if (CGRectIntersectsRect(projectileRect, targetRect)) {
                [targetsToDelete addObject:target];				
            }						
        }
        
        for (CCSprite *target in targetsToDelete) {
            [_targets removeObject:target];
            [self removeChild:target cleanup:YES];									
        }
        
        if (targetsToDelete.count > 0) {
            [projectilesToDelete addObject:projectile];
        }
        [targetsToDelete release];
    }
    
    for (CCSprite *projectile in projectilesToDelete) {
        [_projectiles removeObject:projectile];
        [self removeChild:projectile cleanup:YES];
    }
    [projectilesToDelete release];
}

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

ต่อมาให้แทรกคำสั่งต่อไปนี้ลงไปในฟังก์ชัน init() ต่อจากคำสั่ง Interval ก่อนปิดฟังก์ชัน

[self addChild:bgGame];	
[self addChild:player];		      
[self schedule:@selector(gameLogic:) interval:1.0];
[self schedule:@selector(update:)];

ทำการ "Run” แอพพลิเคชัน แล้วลอง ยิงกระสุนไปยังศัตรูของเราดูจะพบว่า ศัตรูของเราได้หายไปแล้วเมื่อโดนกระสุน

ยิงกระสุนโดนศัตรูกราดให้พอใจ
ยิงกระสุนโดนศัตรูกราดให้พอใจ

ในบทเรียนต่อไปจะเป็นพาไปรู้จักกับการตรวจสอบการชนกันเมื่อศัตรูเลื่อนมาโดนเราแล้วแสดงผลหน้าจอ Game Over และองคฺประกอบเพิ่มเติมต่อไปนี้

  • การใส่ไฟล์เสียงลงไป (Audio)
  • การทำฉากหลังเลื่อนได้ (Paralax BackGround)
  • การหยุดเกม (Pause)
  • การเปลี่ยนหน้า (Winner, Game Over)

Asst. Prof. Banyapon Poolsawas

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

Related Articles

Leave a Reply

Back to top button
Game & Mobile Development AR VR XR
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Adblock Detected

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