1. 주인공의 위치를 확인한다.
2. 적과 주인공의 거리를 계산한다.
3. 공격할 수 있을 만큼 가까운 거리가 아니면 주인공 쪽으로 이동한다.
4. 공격할 수 있을 만큼 가까운 거리면 공격을 시도한다.
작업할 파일은 다음과 같습니다.
(1) EnemySprite.h
(2) EnemySprite.m
(3) GameLayer.m
//
// EnemySprite.h
// GameDemo
//
// Created by Chang-Min Pak on 6/2/10.
// Copyright 2010 thefirstgood.com. All rights reserved.
//
//#import <Foundation/Foundation.h>
#import "cocos2d.h"
@class GameLayer;
//@interface EnemySprite : NSObject {
@interface EnemySprite : CCSprite {
GameLayer *gameLayer;
CCAnimate *walkAnimate;
CGFloat walkingSpeed;
}
@property(nonatomic, retain) CCAnimate *walkAnimate;
- (id) initWithSpriteFrameName:(NSString*)frameName position:(CGPoint)pos speed:(CGFloat)speed gameLayer:(GameLayer*)layer;
- (void) adjustPosition;
- (void) startWalking;
@end
(1) CCSprite 클래스를 상속받는 클래스를 정의합니다.
//
// EnemySprite.m
// GameDemo
//
// Created by Chang-Min Pak on 6/2/10.
// Copyright 2010 thefirstgood.com. All rights reserved.
//
#import "EnemySprite.h"
#import "GameLayer.h"
@implementation EnemySprite
@synthesize walkAnimate;
// GameLayer에 있는 오브젝트들을 사용하여야 하므로, init 메소드에 gameLayer를 넘겨줍니다.
- (id) initWithSpriteFrameName:(NSString *)frameName position:(CGPoint)pos
speed:(CGFloat)speed gameLayer:(GameLayer*)layer
{
if( (self=[super initWithSpriteFrameName:frameName]) ) {
gameLayer = layer;
walkingSpeed = speed;
// GameLayer에서 만들어 놓은 CCAnimation을 이용하여 CCAnimate 객체를 만듭니다.
CCAnimate *animate = [[CCAnimate alloc] initWithAnimation:gameLayer.enemyWalkAnimation restoreOriginalFrame:NO];
self.walkAnimate = animate;
[animate release];
self.anchorPoint = CGPointMake(0.5, 0);
self.position = pos;
}
return self;
}
// EnemySprite객체가 만들어지면, 바로 걷는 애니메이션을 시작합니다.
- (void) onEnter {
[super onEnter];
[self startWalking];
}
- (void) startWalking {
[self schedule:@selector(walking)];
[self runAction:[CCRepeatForever actionWithAction:self.walkAnimate]];
}
- (void) stopWalking {
[self unschedule:@selector(walking)];
[self stopAllActions];
}
- (void) walking {
// 주인공에 가까이 왔으면(40픽셀 이내) 움직임을 멈춥니다.
if(abs(self.position.x - gameLayer.princeSprite.position.x) <= 40) {
// 걷는 동작을 멈춥니다.
[self stopWalking];
// 0.5에서 1.4초 사이의 랜덤시간만큼 기다렸다가 공격을 합니다.
// (레벨이 올라갈수록 지체하는 시간을 줄이면 그만큼 더 강한 적들이 되겠죠?)
CGFloat delayTime = ((random() % 10) + 5) / 10.0f;
NSLog(@"적 공격 %1.2f초 전...", delayTime);
[self runAction:[CCSequence actions:
// 위에서 계산된 랜덤시간만큼 기다립니다.
[CCDelayTime actionWithDuration:delayTime],
// 주인공을 공격 합니다.
[CCCallFunc actionWithTarget:self selector:@selector(attackPrince)],
nil]];
}
// 아직 주인공과 충분히 가깝지 않다면 계속 이동시킵니다.
CGFloat tmpWalkingSpeed = walkingSpeed;
// 주인공이 왼쪽에 있는지 오른쪽에 있는지 알아봅니다.
if(gameLayer.princeSprite.position.x > self.position.x)
self.flipX = YES;
else {
self.flipX = NO;
tmpWalkingSpeed *= -1.0;
}
// 새로운 위치를 업데이트 합니다.
self.position = CGPointMake(self.position.x + tmpWalkingSpeed, self.position.y);
}
// 이 메소드가 바로 주인공이 이동할 때 적들이 뒤쳐지도록 만드는 부분입니다.
// 주인공의 이동방향과 적의 이동방향에 맞추어 x 좌표의 값을 변경합니다.
- (void) adjustPosition {
if(gameLayer.princeSprite.position.x > self.position.x && gameLayer.princeSprite.flipX == YES)
self.position = CGPointMake(self.position.x + 1.0, self.position.y);
else if(gameLayer.princeSprite.position.x < self.position.x && gameLayer.princeSprite.flipX == NO)
self.position = CGPointMake(self.position.x - 1.0, self.position.y);
else if(gameLayer.princeSprite.flipX == YES && self.flipX == NO)
self.position = CGPointMake(self.position.x + 1.0, self.position.y);
else if(gameLayer.princeSprite.flipX == NO && self.flipX == YES)
self.position = CGPointMake(self.position.x - 1.0, self.position.y);
}
- (void) attackPrince {
// 공격하는 애니매이션을 시작합니다. 다음 강좌에서 실재 에니메이션을 구현해보도록 하겠습니다.
// 주인공과의 거리를 다시 계산합니다. 이렇게 다시 계산하는 이유는 위에서 잠깐 지체하는동안
// 주인공이 이동을 했을 수도 있기 때문입니다.
if(abs(gameLayer.princeSprite.position.x - self.position.x) <= 50) {
NSLog(@"적 공격 성공!");
}else {
NSLog(@"적 공격 실패!");
}
[self startWalking];
}
- (void) dealloc {
[walkAnimate release];
[super dealloc];
}
@end
(1) 캐시에 들어있는 프레임 이름을 베이스(Base) 클래스의 initWithSpriteFrameName에 넘겨주어 스프라이트 객체를 생성합니다.
(2) 각 EnemySprite 객체는 자신만의 schedule을 사용해서 프레임마다 walking 메서드를 호출하게 하여 스프라이트의 좌표를 업데이트 합니다. 애니메이션을 무한반복 합니다.
(3) unschedule 메서드를 사용하여 등록된 스케줄을 스케줄러에서 삭제합니다. 애니메이션을 stopAllActions 메서드로 중지시킵니다.
// GameLayer.m
- (void) createEnemyAndAnimation {
// 위치정보 파일을 읽어들여 바로 CCSpriteFrame을 만들어 캐시에 저장합니다.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"enemy.plist"];
// 위치정보 파일과 같은 이름을 가진 스프라이트 시트로 CCSpriteSheet 객체를 만듭니다.
self.enemySpriteSheet = [CCSpriteSheet spriteSheetWithFile:@"enemy.png"];
[self addChild:self.enemySpriteSheet z:kTag_Enemy];
// 프레임을 담을 Array를 만듭니다.
NSMutableArray *aniFrames = [NSMutableArray array];
// 아주 간단히 프레임을 만들어 배열에 저장할 수 있습니다. 스프라이트 시트를 만들 때 사용된
// 개별 이미지의 파일 이름을 사용하여 개별 프레임을 읽어들입니다.
for(NSInteger idx = 1; idx <= 15; idx++) {
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:[NSString stringWithFormat:@"zombie_walk_%04d.png", idx]];
[aniFrames addObject:frame];
}
// 프레임으로 CCAnimation을 만듭니다. 각 프레임당 시간을 0.15초로 정해줍니다.
CCAnimation *walkAnimation = [[CCAnimation alloc] initWithName:@"enemy_walk" delay:0.15f frames:aniFrames];
self.enemyWalkAnimation = walkAnimation;
[walkAnimation release];
// 임시로 두명의 적을 만들어 주인공 캐릭터의 처음 위치의 왼쪽 오른쪽에 각각 위치시킵니다.
/*for(NSInteger idx = 0; idx < 2; idx++) {
// 첫번째 프레임으로 적 캐릭터 sprite를 만듭니다.
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:@"zombie_walk_0001.png"];
sprite.anchorPoint = ccp(0.5, 0);
if(idx == 0) {
// 첫번째 적은 화면 중앙에서 왼쪽에
sprite.position = ccp(winSize.width / 2 - 100, 13);
sprite.flipX = YES;
}else {
// 두번째 적은 화면 중앙에서 오른쪽에 위치시킵니다.
sprite.position = ccp(winSize.width / 2 + 100, 13);
sprite.flipX = NO;
}
// 만들어진 적 스프라이트를 스프라이트 시트에 넣습니다.
[self.enemySpriteSheet addChild:sprite];
// 걷기 애니메이션을 시작합니다.
CCAnimate *walkAnimate = [CCAnimate actionWithAnimation:self.enemyWalkAnimation restoreOriginalFrame:NO];
[sprite runAction:[CCRepeatForever actionWithAction:walkAnimate]];
}*/
// TEMP
// 움직이는 속도와 위치를 달리하여 적 캐릭터 세개를 만든다.
// 적 캐릭터 1
EnemySprite *enemy = [[EnemySprite alloc] initWithSpriteFrameName:@"zombie_walk_0001.png"
position:CGPointMake(winSize.width / 2 + 100, 13)
speed:0.5f
gameLayer:self];
[self.enemySpriteSheet addChild:(CCSprite*)enemy];
[enemy release];
// 적 캐릭터 2
enemy = [[EnemySprite alloc] initWithSpriteFrameName:@"zombie_walk_0001.png"
position:CGPointMake(winSize.width / 2 - 150, 13)
speed:0.3f
gameLayer:self];
[self.enemySpriteSheet addChild:(CCSprite*)enemy];
[enemy release];
// 적 캐릭터 3 - 화면 바깥에 위치시킨다.
enemy = [[EnemySprite alloc] initWithSpriteFrameName:@"zombie_walk_0001.png"
position:CGPointMake(-100, 13)
speed:0.7f
gameLayer:self];
[self.enemySpriteSheet addChild:(CCSprite*)enemy];
[enemy release];
}