您的位置:首页 > 移动开发 > Cocos引擎

Cocos2D-x A星寻路法

2013-12-31 16:19 281 查看

Cocos2D-x A星寻路法

(2013-05-22 17:43:19)


转载▼

标签:

it

分类:
Cocos2D-x
里面的A星寻路法代码有点坑爹,考虑不是很全面,内存管理也不是很细心.因为它主要目的是为了诠释算法的思路,也没有必要面面俱到.算法是灵魂,理解算法就可以了.
但也花了我半天的时间修改它的bug,下面贴出劈人修改后的代码,节省大家的时间-直接copy它就行了.

//

// AstarItem.h

// AstarAlgorithm

//

// Created by liboxiang on 13-5-21.

//

//

#ifndef __AstarAlgorithm__AstarItem__

#define __AstarAlgorithm__AstarItem__

#include <iostream>

#include "cocos2d.h"

class AstarItem: public cocos2d::CCObject

{

public:

// AstarItem();

// ~AstarItem();

 

  // 行 / 列 setter/getter

  void setPos(const int &col,
const int &row)

  {

      id_col = col;

      id_row = row;

  }

  int getCol(){return id_col;}

  int getRow(){return id_row;}

 

  //实际估价 setter/getter

  void setG(const int &g){id_g = g;}

  int getG(){return id_g;}

 

  //估计代价 setter/getter

  void setH(const int &h){id_h = h;}

  int getH(){return id_h;}

 

  //父节点 setter/getter

  void setFid(const int &fid){id_fid = fid;}

  int getFid(){return id_fid;}

 

  //估价函数 setter/getter

  void setF(const int &f){id_f = f;}

  int getF(){return id_f;}

 

private:

  int id_col;//列

  int id_row;//行

  int id_g;//实际估价

  int id_h;//估计代价

  int id_fid;//父节点
标志close中的index

  int id_f;//估价函数 f = g + h

};

#endif

//

// Astar.h

// AstarAlgorithm

//

// Created by liboxiang on 13-5-21.

//

//

#ifndef __AstarAlgorithm__Astar__

#define __AstarAlgorithm__Astar__

#include <iostream>

namespace cocos2d

{

  class CCArray;

  class CCTMXTiledMap;

}

class Astar

{

private:

  int curCol, curRow, aimCol, aimRow;

// int AimX, AimY, AimW, AimH;

  cocos2d::CCArray *open;

  cocos2d::CCArray *close;

  cocos2d::CCArray *path;

  cocos2d::CCTMXTiledMap *map;

 

  std::string conflictProerty;

int conflictValue;

 

  int getG(const int &col,
const int &row, const int &id);//获得g()

  int getH(const int &col,
const int &row);//获得h()

  void fromOpenToClose();//将open中的元素导入close

  void removeFromOpen();//从open列表中删除元素

  void getPath();//获得整个路径

  void starSearch(const int &fid);//搜索

  void resetSort(int last);//排序

  bool checkClose(const int &col,
const int &row);//检查close

  void addToOpen(const int &col,
const int &row, const int &id);//向open添加元素

  bool checkMap(const int &col,
const int &row);//检查地图

  bool checkOpen(const int &col,
const int &row, const int &id);//检查列表

 

public:

  Astar();

  ~Astar();

  cocos2d::CCArray *findPath(const
int &curX,

                   
        const int &curY,

                   
        const int &aimX,

                   
        const int &aimY,

                   
        cocos2d::CCTMXTiledMap *passMap,

                   
        const std::string &theConflictProerty,

                   
        const int &theConflictValue);//入口函数

};

#endif

//

// Astar.cpp

// AstarAlgorithm

//

// Created by liboxiang on 13-5-21.

//

//

#include "Astar.h"

#include "cocos2d.h"

#include "AstarItem.h"

using namespace cocos2d;

Astar::Astar():map(NULL), conflictProerty("conflict"), conflictValue(1)

{

path = CCArray::create();

  path->retain();

 

  open = CCArray::create();

  open->retain();

 

  close = CCArray::create();

  close->retain();

}

Astar::~Astar()

{

  CC_SAFE_RELEASE(open);

  CC_SAFE_RELEASE(close);

  CC_SAFE_RELEASE(path);

  CC_SAFE_RELEASE(map);

}

int Astar::getG(const int &col,
const int &row, const int &id)//获得g()

{

  AstarItem *closeMember = (AstarItem
*)close->objectAtIndex(id);

int fx = closeMember->getCol();

  int fy = closeMember->getRow();

  int fg = closeMember->getG();

 

  if (col - fx != 0 && row - fy != 0)

  {

      return fg + 14;

  }

  else

  {

      return fg + 10;

  }

}

int Astar::getH(const int &col,
const int &row)//获得h()

{

  //获得该点的h值

  return abs(aimCol - col) *
10 + abs(aimRow - row) * 10;

}

void Astar::fromOpenToClose()//将open中的元素导入close

{

  //把open列表中的点 放到close列表

  AstarItem *temp = (AstarItem *)open->objectAtIndex(1);

  close->addObject(temp);

  removeFromOpen();

}

void Astar::removeFromOpen()//从open列表中删除元素

{

  //最後一个 替换第一个

  open->replaceObjectAtIndex(1, open->lastObject(),
true);

 

  //删除最後一个

  open->removeLastObject();

 

  int last = open->count() -
1;

 

  //对排序

  int head = 1;

  while ( (head * 2) <= last )

  {

      int child1 = head * 2;

      int child2 = child1 + 1;

      int childMin(0);

     

      //找出 childMin

      if (child2 <= last)

      {

          AstarItem *child1AstarItem = (AstarItem *)open->objectAtIndex(child1);

          AstarItem *child2AstarItem = (AstarItem *)open->objectAtIndex(child2);

          childMin = child1AstarItem->getF() < child2AstarItem->getF() ? child1 : child2;

      }

      else

      {

          childMin = child1;

      }

     

      //head > childMin就交换

      AstarItem *headAstarItem = (AstarItem *)open->objectAtIndex(head);

      AstarItem *childMinAstarItem = (AstarItem *)open->objectAtIndex(childMin);

      if (headAstarItem->getF() <= childMinAstarItem->getF())

      {

          break;

      }

      open->exchangeObject(headAstarItem, childMinAstarItem);

     

      head = childMin;

  }

}

void Astar::getPath()//获得整个路径

{

  path->addObject(close->lastObject());

 

  while (true)

  {

      if (((AstarItem *)path->objectAtIndex(0))->getG() ==
0 )

      { //达到终点时,结束循环

          break;

      }

     

      path->insertObject(

                 
      close->objectAtIndex(((AstarItem
*)path->objectAtIndex(0))->getFid()),

                   
    0);

  }

  curCol = aimCol;

  curRow = aimRow;

}

void Astar::starSearch(const int &fid)//搜索

{

  AstarItem *fidAstarItem = (AstarItem
*)close->objectAtIndex(fid);

 

  //view coordinate

  int col = fidAstarItem->getCol();

  int row = fidAstarItem->getRow();

 

  //搜索目前点的上 左 下 右 四个方向

 

  //上

  int myCol = col;

  int myRow = row - 1;

  if (myRow >= 0 && checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //--上左

  myCol = col -1;

  myRow = row - 1;

  if (myCol >= 0 && myRow >= 0 &&
checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //左

  myCol = col - 1;

  myRow = row;

  if (myCol >= 0 && checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //--左下

  myCol = col -1;

  myRow = row + 1;

  if (myCol >= 0 && myRow <= map->getMapSize().height &&
checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //下

  myCol = col;

  myRow = row + 1;

  if (myRow <= map->getMapSize().height &&
checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //--右下

  myCol = col + 1;

  myRow = row + 1;

  if (myCol <=map->getMapSize().width && myRow <=
map->getMapSize().height && checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //右

  myCol = col + 1;

  myRow = row;

  if (myCol <=map->getMapSize().width &&
checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

 

  //--上右

  myCol = col + 1;

  myRow = row - 1;

  if (myCol <=map->getMapSize().width && myRow >=
0 && checkMap(myCol, myRow))

  {

      if (checkOpen(myCol, myRow, fid) &&
checkClose(myCol, myRow))

      {

      addToOpen(myCol, myRow, fid);

      }

  }

}

void Astar::resetSort(int last)//排序

{

  while (last > 1)

  {

      int half = last / 2;

     

      AstarItem *lastAstarItem = (AstarItem *)open->objectAtIndex(last);

      AstarItem *halfAstarItem = (AstarItem *)open->objectAtIndex(half);

      if (halfAstarItem->getF() <= lastAstarItem->getF())
break;

     

      open->exchangeObject(halfAstarItem, lastAstarItem);

     

      last = half;

  }

}

bool Astar::checkClose(const int &col,
const int &row)//检查close

{

  AstarItem *closeMember = NULL;

  CCObject *theObject = NULL;

  CCARRAY_FOREACH_REVERSE(close, theObject)

  {

      closeMember = (AstarItem *)theObject;

      if (closeMember->getCol() == col && closeMember->getRow() == row)

      {

          return false;

      }

  }

  return true;

}

void Astar::addToOpen(const int &col,
const int &row, const int &id)//向open添加元素

{

  AstarItem *temp = new AstarItem();

  temp->setPos(col, row);

  temp->setFid(id);

 

  int g = getG(col, row, id);

  int h = getH(col, row);

 

  temp->setG(g);

  temp->setH(h);

  temp->setF(g + h);

  open->addObject(temp);

  resetSort(open->count() -
1);

}

bool Astar::checkMap(const int &col,
const int &row)//检查地图

{

  CCTMXLayer *layer = map->layerNamed("grass");

  CCAssert(layer, "grass layer is not found at Astar::checkMap");

 

  if (col >= map->getMapSize().width
|| row >= map->getMapSize().height)

  {

      return false;

  }

  unsigned int tileGid = layer->tileGIDAt(ccp(col, row));CCAssert(tileGid >
0, "tileGid is empty");

 

  CCDictionary *tileDic =
map->propertiesForGID(tileGid);CCAssert(tileDic, "tileDic is not found at Astar::checkMap");

 

  CCString *mValue = (CCString *)tileDic->objectForKey(conflictProerty.c_str());CCAssert(mValue,
"mValue is not found at Astar::checkMap");

 

  if (mValue->intValue() == conflictValue)

  {

      return false;

  }

  else

  {

      return true;

  }

}

bool Astar::checkOpen(const int &col,
const int &row, const int &id)//检查列表

{

  AstarItem *openMember = NULL;

  CCObject *theObject = NULL;

  unsigned int index = open->count() -
1;

  CCARRAY_FOREACH_REVERSE(open, theObject)

  {

      openMember = (AstarItem *)theObject;

      if (openMember->getCol() == col && openMember->getRow() == row)

      {

          int tempG = getG(col, row, id);

          if (tempG < openMember->getG())

          {

              openMember->setG(tempG);

              openMember->setFid(id);

              openMember->setF(openMember->getG() + openMember->getH());

              resetSort(index);

          }

         

          return false;

      }

      --index;

  }

 

  return true;

}

CCArray *Astar::findPath(const int &curX,

                   
  const int &curY,

                   
  const int &aimX,

                   
  const int &aimY,

                   
  CCTMXTiledMap *passMap,

                   
  const std::string &theConflictProerty,

                   
  const int &theConflictValue)//入口函数

{

curCol = curX;

  curRow = curY;

aimCol = aimX;

  aimRow = aimY;

 

  conflictProerty = theConflictProerty;

  conflictValue = theConflictValue;

 

  if (map != passMap)

  {

      CC_SAFE_RELEASE(map);

      map = passMap;

      map->retain();

  }

 

  path->removeAllObjects();

 

  // index = 0;

  AstarItem *temp = new AstarItem();

  open->addObject(temp);

 

  //index = 1;

  AstarItem *temp1 = new AstarItem();

  temp1->setPos(curCol, curRow);

  temp1->setG(0);

  int ag = getH(curCol, curRow);

  temp1->setH(ag);

  temp1->setFid(0);

  temp1->setF(0 + ag);

  open->addObject(temp1); 

  //遍历寻找路径

  while (open->count() >
1)

  {

      //open 中 最小的移动啊 close

      //open 中 重新排列

      fromOpenToClose();

      int fatherid = close->count() -
1;

     

      AstarItem *lastAstarItem = (AstarItem *)close->objectAtIndex(fatherid);

      if (abs(aimCol - lastAstarItem->getCol()) ==
0 &&

          abs(aimRow - lastAstarItem->getRow()) ==
0)

      {

          getPath();

          break;

      }

      else

      {

          //搜索

          starSearch(fatherid);

      }

  }

 

  open->removeAllObjects();

  close->removeAllObjects();

 

  //获得路径

  if (path->count() ==
0)

  {

      return NULL;

  }

  else

  {

      AstarItem *lastAstarItem = (AstarItem *)path->lastObject();

      if (lastAstarItem->getCol() !=
aimCol ||

          lastAstarItem->getRow() !=
aimRow)

      {

          AstarItem *temp = new
AstarItem();

          temp->setPos(aimCol,
aimRow);

          path->addObject(temp);

      }

      return path;

  }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: