我正在使用cocos2d-iphone制作简单的iPhone游戏。我有一系列的恶魔,“fiendSet”,它必须在一个充满障碍的场地周围航行。我花了最后三个晚上试图让我的A *寻路工作。我在stackoverflow上找到了实际的A *实现,它的工作非常出色。然而,一旦我试图移动我的恶魔我遇到了麻烦。
我的每个恶魔都有一个名为motionTarget的CGPoint,它包含了魔鬼必须去的地方的x和y值。如果仅将位置x和y设置为每秒一次绝对值,则可以这样工作:
-(void) updateFiendPositions:(ccTime)dt {
for (MSWFiend *currFiend in fiendSet) {
currFiend.position = ccp(currFiend.motionTarget.x,currFiend.motionTarget.y);
}
}
然而,这看起来并不是很好,恶魔只是每秒“跳跃”20px,而不是很好地制作动画。我只将其实现为占位符方法来验证路径查找。现在我想要流畅的动画。这就是我所做的:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
float x,y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.x)-(int)floor(currFiend.motionTarget.x)) < 2) {
x = currFiend.motionTarget.x;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.y)-(int)floor(currFiend.motionTarget.y)) < 2) {
y = currFiend.motionTarget.y;
}
currFiend.position = ccp(x,y);
}
}
}
这对于向一个方向移动的恶魔来说非常有用。一旦恶魔绕过弯道,麻烦就开始了。而不是例如先上升,然后是正确,然后下来;我的恶魔将把上/右动作合二为一,他们是“偷工减料”。我只希望我的恶魔在每个位置更新中向东/向南移动 OR ,而不是两者。换句话说,我不想同时为x和y设置动画。我希望这个解释很清楚......
我很确定我在某个地方有一个逻辑错误..我在工作后的最后三个不眠之夜里找不到它..帮助!
答案 0 :(得分:1)
您必须跟踪目标路径中的每个节点。这样,您只需将动画设置为下一个节点的动画。此外,您可以使用CCMoveTo操作代替自己动画。
答案 1 :(得分:0)
@Aleph感谢你的建议。我发现是代码确定何时分配新的motionTarget,这是错误的,而不是我开始发布的代码。当你提到跟踪每个节点的位置时,我想到了我的motionTarget确定代码,并在2-3小时后发现错误。我最终这样做了:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
int fiendGX,fiendGY,targetGX,targetGY,dGX,dGY;
float x,y,snappedX,snappedY;
BOOL snappedIntoPosition = FALSE;
fiendGX = (int)round(100.0f*(currFiend.position.x/20));
fiendGY = (int)round(100.0f*(currFiend.position.y/20));
targetGX = (int)round(100.0f*(currFiend.motionTarget.x/20));
targetGY = (int)round(100.0f*(currFiend.motionTarget.y/20));
snappedX = currFiend.position.x;
snappedY = currFiend.position.y;
dGX = abs(fiendGX-targetGX);
dGY = abs(fiendGY-targetGY);
float snappingThreshold; //1 = snap when 0.1 from motionTarget.
snappingThreshold = currFiend.speed/10;
if (dGX < snappingThreshold && dGY < snappingThreshold) {
snappingThreshold = currFiend.motionTarget.x;
snappingThreshold = currFiend.motionTarget.y;
int newPathStep;
newPathStep = currFiend.pathStep + 1;
currFiend.pathStep = newPathStep;
}
int gX,gY;
gX = [[currFiend.path objectAtIndex:currFiend.pathStep] nodeX];
gY = (tileMap.mapSize.height-[[currFiend.path objectAtIndex:currFiend.pathStep] nodeY])-1;
currFiend.motionTarget = ccp(gX*20,gY*20); //Assign motion target to the next A* node. This is later used by the position updater.
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
x = currFiend.motionTarget.x;
y = currFiend.motionTarget.y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
//Move right
x = snappedX+(currFiend.speed*dt);
if (x > currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
//Move left
x = snappedX-(currFiend.speed*dt);
if (x < currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
//Move up
y = snappedY+(currFiend.speed*dt);
if (y > currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
//Move down
y = snappedY-(currFiend.speed*dt);
if (y < currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
}
currFiend.position = ccp(x,y);
}
}