2012-09-25 26 views
1

我一直在爭奪這一段時間,我的小白腦子不能完全解決它。我有一個標準的瓦片地圖,目前使用下面的代碼將我的敵人精靈地圖限制精靈運動,水平和垂直

-(void) movePlayer:(ccTime)deltaTime { 

    if (CGPointEqualToPoint(self.position, requestedPosition)) 
     return; 


    float step = kPlayerSpeed * deltaTime; 
    float dist = ccpDistance(self.position, requestedPosition); 
    CGPoint vectorBetweenAB = ccpSub(self.position, requestedPosition); 

    if (dist <= step) { 
     self.position = requestedPosition; 
     [self popPosition]; 
    } else { 
     CGPoint normVectorBetweenAB = ccpNormalize(vectorBetweenAB); 
     CGPoint movementVectorForThisFrame = ccpMult(normVectorBetweenAB, step); 

     if (abs(vectorBetweenAB.x) > abs(vectorBetweenAB.y)) { 
      if (vectorBetweenAB.x > 0) { 
       [self runAnimation:walkLeft]; 
      } else { 
       [self runAnimation:walkRight]; 
      } 
     } else { 
      if (vectorBetweenAB.y > 0) { 
       [self runAnimation:walkDown]; 
      } else { 
       [self runAnimation:walkUp]; 
      } 
     } 

     if (self.position.x > movementVectorForThisFrame.x) { 
      movementVectorForThisFrame.x = -movementVectorForThisFrame.x; 
     } 
     if (self.position.y > movementVectorForThisFrame.y) { 
      movementVectorForThisFrame.y = -movementVectorForThisFrame.y; 
     } 
     self.position = ccpAdd(self.position, movementVectorForThisFrame); 
    } 

} 

movePlayer各地:由類updateWithDeltaTime所謂:方法。 ivar requestedPosition也在updateWithDeltaTime方法中設置,它基本上從隊列中移出的下一個點。這些點可以在地圖上的任何地方,所以如果它們處於敵方對角線方向,敵方精靈將直接移動到該點。但是,如何改變上面的代碼,將運動限制在垂直和水平運動中,以便沿着對角線路徑沿着對角線路線運行敵人運動的「階梯」,並採用曼哈頓距離(我認爲它的名字)。正如我下面的粗略圖所示... S是起點F是終點,數字是沿其路徑的每個中間點以創建階梯式對角線移動。最後,我打算能夠打開和關閉這種行爲,以便我可以選擇是否讓敵人在地圖上自由移動或僅限於此水平/垂直移動。

| | | | | | | | | | 
| | | | | | | | | | 
| |F| | | | | | | | 
| |5|4| | | | | | | 
| | |3|2| | | | | | 
| | | |1|S| | | | | 
| | | | | | | | | | 
| | | | | | | | | | 
| | | | | | | | | | 
| | | | | | | | | | 
+0

進一步,如果有人有任何意見,以幫助優化我目前的移動代碼那麼這將是可怕的...謝謝 –

回答

0

所以,目前的解決方案,我發現是如下...

-(void)pathfind { 
    //Get a reference to the tile map 
    CCTMXTiledMap *tileMap = (CCTMXTiledMap *)[[[[CCDirector sharedDirector] runningScene] getChildByTag:kStartLayer] getChildByTag:kMapNode]; 
    NSAssert(tileMap != nil, @"No Tile map"); 

    //Convert self.position to tile coordinates and set to both vars. stepTileCoord so that we can add a tile in direction of travel. 
    CGPoint selfTileCoord = [tileMap tileCoordFromLocation:self.position]; 
    CGPoint stepTileCoord = [tileMap tileCoordFromLocation:self.position]; 

    //Init this var to keep track of the last tile worked out so the next one can be worked out from it. We start at self.position. 
    CGPoint lastTileCoord = selfTileCoord; 

    //For loop, iterates over each orginal position in the requestedPositionQueue. 
    for (int i=0; i < [requestedPositionQueue count]; i++) { 

     //Get the current original path tile coordinate. 
     CGPoint requestedTileCoord = [[requestedPositionQueue objectAtIndex:i] CGPointValue]; 
     NSMutableArray *tempPoints = [NSMutableArray array]; 

     //While loop interates until it has worked out every intermediate step to the original path tile. 
     while (!CGPointEqualToPoint(requestedTileCoord, stepTileCoord)) { 

      //FIXME: what happens if path takes us back over the orignal start point? 
      if (CGPointEqualToPoint(selfTileCoord, requestedTileCoord)) { 
       //Not sure if this will cause an issue. 
       break; 
      } 

      CGPoint vectorToDest = ccpSub(lastTileCoord, requestedTileCoord); 

      if (abs(vectorToDest.x) > abs(vectorToDest.y)) { 
       if (vectorToDest.x > 0) { 
        stepTileCoord.x -= 1; 
       } else { 
        stepTileCoord.x += 1; 
       } 
      } else { 
       if (vectorToDest.y > 0) { 
        stepTileCoord.y -= 1; 
       } else { 
        stepTileCoord.y += 1; 

       } 
      } 

      //If the tile worked out is the requestedTileCoord then break, no need to add it to tempPoints as it will already be in the requestedPosition Queue. 
      if (CGPointEqualToPoint(requestedTileCoord, stepTileCoord)) { 
       break; 
//    CCLOG(@"%@", [requestedPositionQueue description]); 
      } else { 
       //Save this tile to tempPoints arrway. And save it to lastTileCoord. 
       [tempPoints addObject:[NSValue valueWithCGPoint:stepTileCoord]]; 
       lastTileCoord = stepTileCoord; 
//    CCLOG(@"\n{%f, %f}", lastTileCoord.x, lastTileCoord.y); 
      } 
     } 
     //As we have now got an array, tempPoints, with all the intermediate step points to current point out of requestedPositionQueue we shall add all objects in tempPoints to requestedPositionQueue. NSIndexSet will ensure its added at the correct location in array. 
     NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(i, [tempPoints count])]; 
     [requestedPositionQueue insertObjects:tempPoints atIndexes:indexes]; 
//  CCLOG(@"%@", [requestedPositionQueue description]); 
     //i is updated so the next point pulled out of the array isn't one of the worked out intermediate steps. 
     i += [tempPoints count]; 
    } 
} 

所以,首先,我有瓷磚的路徑保存在伊娃陣列的字符座標例如...

requestedPositionQueue = [NSMutableArray arrayWithObjects: 
             [NSValue valueWithCGPoint:CGPointMake(7, 18)], 
             [NSValue valueWithCGPoint:CGPointMake(11, 18)], 
             [NSValue valueWithCGPoint:CGPointMake(7, 22)], 
             [NSValue valueWithCGPoint:CGPointMake(7, 18)], 
             [NSValue valueWithCGPoint:CGPointMake(11, 22)], 
             nil]; 

因此,您可以看到這有一些點需要這種形式的對角線移動。然後我調用pathfind方法,並遍歷requestedPositionQueue並添加所有中間的tile座標,以確保它始終垂直或水平地選擇一個tile,但從不在對角線旁邊的當前tile直到它完成整個路徑。

然後在更新:方法我遍歷requestedPositionArray,同時從它的下一個圖塊座標,將其轉換爲像素位置然後分配給我的requestedPosition伊娃,然後運行movePlayer:在原崗位方法(代碼)。

我已經把意見在pathfind方法爲我自己的利益,因此可能不是全面,但它們可以幫助你的我的思想的理解。

最後這是最好的我已經提出,它允許我確保我可以不受限制地將我的角色移動到像素位置,或者如果我想將它們移動到那裏但將它們限制爲僅通過平鋪中心垂直或水平移動。所以,如果你能看到一種方法來完善和優化這個代碼請做,或任何建設性的批評將永遠讚賞。

編輯:FIXME:在那裏突出,我還沒有來得及看又一個潛在的漏洞。一旦我需要調查和修復,我會重新發布。

1

所以,我不知道有任何真正簡單的方法來做到這一點。我會建議你計算你離終點有多遠。然後得到y差異和x差異。然後,如果y差異大於x,則將精靈移動到設定的數量上。如果x差異更大,則將精靈移出設定量。這樣,精靈將繼續向上移動並離開,因爲它逐漸減小了與終點的差異。這是我會推薦的邏輯。本質:

CGPoint difference = ccpSub(finishPoint, startPoint); 
//Be aware that this if statement will not work for negative distances. Only for the example you gave! 
if(difference.y>difference.x) { 
    sprite.position = ccp(sprite.position.x, sprite.position.y+tileSize); 
} else { 
    sprite.position = ccp(sprite.position.x+tileSize, sprite.position.y); 
} 
+0

Drenguin,感謝您的答覆。我看到你的答案的問題是,雪碧會移動一個整體瓷磚大小的每個更新,這對我的需求有一點快,所以如果我要包括速度因素以及德爾塔時間因素,這將移動在一個合理的速度。但現在的問題是,如果每次更新都會導致(如果起點和終點完全相差45度),玩家可以在每幀垂直和水平移動之間輕彈一下,否則它會重新評估是否(difference.y> difference.x)。 –

+0

我建議創建一些變量來計算已經過去的時間,然後一旦這個時間達到一定的數字(比如說1秒),那麼你移動精靈並將計數器重新設置爲0.這樣它每秒只移動一次。 – Drenguin

+0

另外,對於45度角問題。如果它是45度角,它將只移動精靈x的位置。看看if語句。在45度角,y值不大於x值(它等於它),所以它轉到else語句。同樣,這對於消極的差異不起作用,但它應該很容易做到這一點。 – Drenguin