CCNodeのカテゴリで、他のCCNodeをゆったり追うSoftFollowというのを作ってみた その2 - 追記2/27
CCNodeのカテゴリで、他のCCNodeをゆったり追うSoftFollowというのを作ってみた - taoru's memo という記事を書いたんだけど、
kmVec2でベクトル計算するのがかっこく見えたので使って書きなおしてみた。
CCNode+SoftFollow.h
#import "CCNode.h" @interface CCNode (SoftFollow) /** * toNode: targetNode * strength: 引きよせる強さ。最大値は"1" * distance: targetNodeと一定の距離を保ちたい場合に指定 */ - (void)followTo:(CCNode *)targetNode strength:(float)strength; - (void)followTo:(CCNode *)targetNode strength:(float)strength distance:(float)distance; - (void)stopFollow; @end
CCNode+SoftFollow.m
#import "CCNode+SoftFollow.h" #import "CCActionInstant.h" #import "CCActionInterval.h" #import "CGPointExtension.h" #define ACTIONTAG_FOLLOWNODE 314159265351234 @implementation CCNode (SoftFollow) - (void)followTo:(CCNode *)targetNode strength:(float)strength { [self followTo:targetNode strength:strength distance:0.0f]; } - (void)followTo:(CCNode *)targetNode strength:(float)strength distance:(float)distance { CCCallBlockN *follow = [CCCallBlockN actionWithBlock:^(CCNode *node) { float distX = targetNode.position.x - node.position.x; float distY = targetNode.position.y - node.position.y; kmVec2 distVec = (kmVec2){distX,distY}; if (kmVec2Length(&distVec) > distance) { // 距離distanceのベクトル kmVec2 scaledVec; kmVec2Scale(&scaledVec, &distVec, distance/kmVec2Length(&distVec)); // [targetNodeまでの距離 - distance]のベクトル kmVec2 subVec; kmVec2Subtract(&subVec, &distVec, &scaledVec); // 単位ベクトル kmVec2 unitVec; kmVec2Fill(&unitVec, subVec.x/kmVec2Length(&subVec), subVec.y/kmVec2Length(&subVec)); // 単位ベクトル分だけ必ず進むようにする kmVec2 resultVec; kmVec2Add(&resultVec, &subVec, &unitVec); node.position = ccpAdd(self.position, ccp(resultVec.x*min(strength,1), resultVec.y*min(strength,1))); } }]; CCSequence *seq = [CCSequence actions:[CCDelayTime actionWithDuration:0.0f],follow, nil]; CCRepeatForever *repeat = [CCRepeatForever actionWithAction:seq]; repeat.tag = ACTIONTAG_FOLLOWNODE; [self runAction:repeat]; } - (void)stopFollow { [self stopActionByTag:ACTIONTAG_FOLLOWNODE]; } @end
ここち良い感じに動く!
作法的にどうなのかってのは分からないけど、概ね満足している。
何か問題がありそうな箇所を発見した優しい方、ぜひコメントで教えてください。
追記 2013/02/25
kmVec2の関数を勉強したらもっともっと簡単に書けそうだった。単位ベクトルとか用意されてるんですね。
kmVec2でのベクトル計算 - taoru's memo
気が向いた時に書きなおしてみよう。
追記 2013/02/26
ということでkmVec2の動きも理解できたし書きなおす。
まず上記コードはblocks内でtargetNodeをcopyしちゃってるからまずいっぽい。
で、書きなおしたのが以下になります。
CCNode+SoftFollow.m
#import "CCNode+SoftFollow.h" #import "CCActionInstant.h" #import "CCActionInterval.h" #import "CGPointExtension.h" #define ACTIONTAG_FOLLOWNODE 314159265351234 @implementation CCNode (SoftFollow) - (void)followTo:(CCNode *)targetNode strength:(float)strength { [self followTo:targetNode strength:strength distance:0.0f]; } - (void)followTo:(CCNode *)targetNode strength:(float)strength distance:(float)distance { __block CCNode *target = targetNode; CCCallBlockN *follow = [CCCallBlockN actionWithBlock:^(CCNode *node) { float distX = target.position.x - node.position.x; float distY = target.position.y - node.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); } node.position = ccpAdd(node.position, ccp(resultVec.x, resultVec.y)); } }]; CCSequence *seq = [CCSequence actions:[CCDelayTime actionWithDuration:0.0f],follow, nil]; CCRepeatForever *repeat = [CCRepeatForever actionWithAction:seq]; repeat.tag = ACTIONTAG_FOLLOWNODE; [self runAction:repeat]; } - (void)stopFollow { [self stopActionByTag:ACTIONTAG_FOLLOWNODE]; }
動くには動く。理想通りに綺麗に動いてくれる。
しかしこのコードには問題があって、targetNodeがdeallocされるとクラッシュしてしまう。
if(targetNode == nil) とかも取れないし、色々試したけど解決できなかった。
__block修飾子をつけたオブジェクトがdeallocされているかどうかって、どうやって判定すればいいの…
普通に考えてCCAction継承して、CCFollowとかを真似して作ればいいんじゃないかと思った。
次回、CCActionのsubclass版を作ってみよう。
追記 -2013/02/27
作ってみた
CCNodeのカテゴリで、他のCCNodeをゆったり追うSoftFollowというのを作ってみた その3 - taoru's memo