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は勉強しよう。