taoru's memo

Objective-c,cocos2d,など開発についてのメモ(andoroidも少しだけ)

CCNodeのカテゴリで、他のCCNodeをゆったり追うSoftFollowというのを作ってみた その3

CCNodeのカテゴリで、他のCCNodeをゆったり追うSoftFollowというのを作ってみた その2 - 追記2/26 - taoru's memo
↑の続編になります。

今回はタイトル詐欺になるけど、カテゴリではなくCCActionを継承してTTSoftFollowを作った。
prefixどうしようかな〜と思って、taoru toolsという意味でTTをつけてみました。なんか恥ずかしい。

TTSoftFollow.h

#import "CCNode.h"
#import "CCAction.h"

@interface TTSoftFollow : CCAction <NSCopying>

/**
 *  followedNode: 追いかける対象Node
 *  strength    : 引きよせる強さ。最大値は"1" 小さいほどゆったり追いかける。
 *  distance    : 対象と一定の距離を保ちたい場合に指定
 */
+ (id)actionWithTarget:(CCNode *)followedNode;
+ (id)actionWithTarget:(CCNode *)followedNode strength:(float)strength;
+ (id)actionWithTarget:(CCNode *)followedNode strength:(float)strength distance:(float)distance;

@end

TTSoftFollow.m

#import "TTSoftFollow.h"
#import "CGPointExtension.h"

@interface TTSoftFollow ()

@property (nonatomic, retain) CCNode  *followedNode;
@property (nonatomic, assign) CGFloat strength;
@property (nonatomic, assign) CGFloat distance;

@end

@implementation TTSoftFollow

+ (id)actionWithTarget:(CCNode *)followedNode
{
    return [self actionWithTarget:followedNode strength:1.0f];
}

+ (id)actionWithTarget:(CCNode *)followedNode strength:(float)strength
{
    return [self actionWithTarget:followedNode strength:strength distance:0.0f];
}

+ (id)actionWithTarget:(CCNode *)followedNode strength:(float)strength distance:(float)distance
{
    return [[[self alloc] initWithTarget:followedNode strength:strength distance:distance] autorelease];
}

- (id)initWithTarget:(CCNode *)followedNode strength:(float)strength distance:(float)distance
{
    if (self = [super init]) {
        _followedNode   = [followedNode retain];
        _strength       = strength;
        _distance       = distance;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    CCAction *copy = [[[self class] allocWithZone:zone] init];
    copy.tag = _tag;
    return copy;
}

- (void)dealloc
{
    [_followedNode release];
    [super dealloc];
}

- (void)step:(ccTime)dt
{
    float distX = self.followedNode.position.x - [_target position].x;
    float distY = self.followedNode.position.y - [_target position].y;
    kmVec2 nodeToTargetVec = (kmVec2){distX,distY};
    
    if (kmVec2Length(&nodeToTargetVec) > _distance) {
        // ベクトルをdistanceの大きさまで縮める
        kmVec2 goalToTargetVec;
        kmVec2Scale(&goalToTargetVec, &nodeToTargetVec, _distance/kmVec2Length(&nodeToTargetVec));
        
        // nodeからgoalまでのベクトル
        kmVec2 nodeToGoalVec;
        kmVec2Subtract(&nodeToGoalVec, &nodeToTargetVec, &goalToTargetVec);
        
        // strengthを乗算
        kmVec2 resultVec;
        kmVec2Scale(&resultVec, &nodeToGoalVec, min(_strength,1));
        
        // 単位ベクトル分だけ必ず進むようにする
        if (kmVec2Length(&resultVec) < 1) {
            kmVec2Normalize(&resultVec, &resultVec);
        }
        
        [_target setPosition:ccpAdd([_target position], ccp(resultVec.x, resultVec.y))];
    }
}

- (BOOL)isDone
{
    return !self.followedNode.isRunning;
}

@end

CCFollowとほとんど同じようなコードです。
followedNodeが先にdeallocされたら、isDoneのreturnがYESになるのでstopが呼ばれる。

よく理解せずに使っているblocksよりこっちを使おう。blocksは勉強しよう。

QLOOKアクセス解析