cocos2d-x中A星算法的实现和实际使用

A星算法经常会用在寻径算法中,是一种典型的启发式搜索算法,属于人工智能算法的一种,能够让物体在游戏中活动起来。今天刚好看到了A星算法这一块,对于其中涉及的原理和实际的运用做了一定的研究,介于自己第一次接触这块算法,文中借用了一些网上看见的知识介绍和模块,并结合自己的实际使用和结合,最后再cocos2d-x中实现A星算法的简单运用。


先来说说A星算法,作为一种寻径算法,使用递归或者循环的方式进行运算。


启发式算法就是在状态空间图中对每个搜索的位置进行评估,得到评估值最优的位置点,逐个对位置点评估直到目标。


文中采用的A星搜索是一种迭代的有序搜索。维护一个状态空间的开发集合。每次使用一个评价函数F(n)评价集合中各个邻接点的状态,选择最小的代价,直到达到终点为止。

其中定义


F(N) = G(n) + H(n)


G(n) :从初始点到第N个点的最短路径

H(n):从第N个点到目标点的估算代价,一般不是一个真实值,而是一个估计值。

F(N):到目前的迭代阶段从初始点经过第N个点到目的点的预计值。


A星算法思考过程如下:

1,首先把整个地图,划分为若干个小块,通常最简单的小块,全部都是正方形,这些小块,有些是障碍,有些是通道。我们把小块都称为节点。

2,在A型算法中有下面几个比较重要的量:

   ①自己的横坐标
   
②自己的纵坐标
   
③自己离起点的距离
   
④自己离终点的距离
   
⑤父节点的横坐标
   
⑥父节点的纵坐标
   
⑦F值,这个F值,就是属性③和属性④相加得到的和,因为可以计算,所以我们暂时不作为一个单独的属性来记录,而是作为描述使用


①②属性很好理解,不解释了;

③属性也很简单,代表的是从起点进过多少步到达此节点;

④属性,由于在获取到完整的路径之前,你并不知道需要经过多少步会达到终点,所以这个属性实际上是一个估算值,估算的方法也有很多,对整个A星的计算效率也会有影响,我们暂时使用一个较为简单的估算方法:采用所在点在最后终点的横纵坐标差的和来计算,体现在最后的代码getH()函数中,如下所示

int Astar::getH(int col,int row)
{
    //获得该点的h值
	return abs(aimCol - col) * 10 + abs(aimRow - row) * 10;
}

⑤⑥属性解释下,这2个坐标是指的你从哪一个节点到达的当前节点,也就是对应的上一个节点。这2个属性可以确保在最终你能找到最短路径。


3、寻路过程中我们会用到3个列表,这3个表,通常被设计为一维数组
   
开放列表。我们在寻路过程中,认为可能符合要求的点,就添加到开放列表中,下面的例子中为open列表;
   
探索列表。我们对开放列表里面所有的节点进行判断,符合要求的,放到这个表中,下面的例子中文close列表;
   
路径列表。从探索列表里面所有符合要求的节点中,找出的最短路径的节点,下面的例子中文path列表;


4、寻路的步骤
   a
)将起点放入探索列表,定义为当前节点
   b
)检测当前节点周围的节点(本例中进行4方向检测),这些周围的点,称为临时节点。如果该临时节点是通道,那么将其加入开放列表

   
将 c 和 d这2步,作为循环来处理

   c
)从开放列表中,选取一个F值最小的节点(就是属性③和属性④相加最小,代表着这个节点在当前看来是符合最短路径的要求的),将它从开放列表中去掉,加入到探索列表中。如果开放列表中,有多个节点的F是相等的,那么我们选取属性③比较小的节点(因为距离起点的值是可靠的,而距离终点的值是估算的),如果属性③仍然相等,那么我们选取最新加入到开放列表的那个节点(这一步在大地图的时候,会增加速度)。
   d
)将这个选出来的点,再次作为当前节点,开始检测它周围的4临时节点,从这个时候开始,如果临时节点是障碍,我们就舍弃;而如果是通道,我们也不能像第 b)步 那样直接把这个临时节点加入到开放列表。我们还需要判断:第一,该临时节点是否已经被加入了探索列表?如果是,那么舍弃它;第二,该临时节点是否已经在开放列表中?如果是,那么代表这个临时节点和保存在开放列表中的节点,属性①②相同,但属性③⑤⑥必定不完全相同(因为是经由不同的父节点进行检测,这一点需要理解),于是我们对临时节点和保存在开放列表中的节点(属性①②相同的这2个节点)进行属性③的对比(这2个点的属性④是相同的),如果临时节点的属性③比较小,那么我们就将临时节点的信息,替换掉已经保存在开放列表中那个节点的所有信息,否则我们就舍弃这个临时节点;第三,该临时节点是个通道,没有保存在探索列表中,也没有在开放列表中,那么我们把这个临时节点加入到开放列表

   
进行 c-d 的循环   

   e
)循环在何时结束?很简单,当终点也被加入到了探索列表中,代表着我们的探索已经完成,这个时候跳出循环

   f
)循环结束之后,我们获得了一个比较庞大的探索列表,里面包含了我们所有探索过的节点,其中,第一个是起点,最后一个是终点。于是我们从终点开始,检测其父节点的坐标,然后再检测父节点的父节点,最终我们得到了一条从终点指向起点的最短路径。


理论清楚以后,下面开始具体的cocos2d-x的实现;


首先是A星算法相关节点信息的定义,如下所示:

#pragma once
#include "cocos2d.h"
using namespace cocos2d;
class AstarItem:public CCNode
{
public:
    AstarItem(void);
	~AstarItem(void);
	void setpos(int col,int row);
	int getcol(){return id_col;};
	int getrow(){return id_row;};
	void setg(int g);
	int getg(){return id_g;};
	void seth(int h);
	int geth(){return id_h;};
	void setfid(int fid);
	int getfid(){return id_fid;};
	void setf(int f);
	int getf(){return id_f;};
private:
	int id_col;//列
	int id_row;//行
	int id_g;// 实际代价
	int id_h;// 估计代价
	int id_fid;// 父节点id
	int id_f;// 估价函数f = g + h
};



接着是相关的实现文件,以简单的存取为内容

#include "Astaritem.h"
AstarItem::AstarItem(void)
{
}
AstarItem::~AstarItem(void)
{
}
void AstarItem::setpos(int col,int row)
{
	id_col = col;
	id_row = row;
}
void AstarItem::setg(int g)
{
	id_g = g;
}
void AstarItem::seth(int h)
{
	id_h = h;
}
void AstarItem::setfid(int fid)
{
	id_fid = fid;
}
void AstarItem::setf(int f)
{
	id_f = f;
}


接着是A星算法的相关头文件定义

#pragma once
#include "cocos2d.h"
#include "AstarItem.h"
using namespace cocos2d;
class Astar
{
private:
	int curCol, curRow, aimCol, aimRow;
	int AimX, AimY, AimW, AimH; 
	CCTMXTiledMap* map;
    CCArray *open;
    CCArray *close;
    CCArray *path;
public:
	Astar(void);
	~Astar(void);
	int getG(int col,int row,int id);
	int getH(int col,int row);
	void fromopentoclose();
	void removefromopen();
	void getpath();
	void starseach(int fid);
	void resetSort(int last);
	bool checkclose(int col,int row);
	void addtoopen(int col,int row,int id);
	bool checkmap(int col,int row);
	bool checkOpen(int col,int row,int id);
    CCArray *findPath(int curX, int curY, int aimX, int aimY, CCTMXTiledMap* passmap);
};


接着是相关的实现文件,算法设计了迭代,最小堆的排序,循环等众多的内容,在具体的实现中,我在代码中加了相关的注释进行说明:

#include "Astar.h"
#include "Astaritem.h"

Astar::Astar(void)
{
}

Astar::~Astar(void)
{
    open->removeAllObjects();
    close->removeAllObjects();
    path->removeAllObjects();
}
CCArray *Astar::findPath(int curX, int curY, int aimX, int aimY, CCTMXTiledMap* passmap)
{
    //参数以及记录路径数组初始化
	curCol = curX;
    curRow = curY;
	aimCol = aimX;
	aimRow = aimY;
	map = passmap;
	<span style="background-color: rgb(51, 255, 51);">path = new CCArray();    </span>
	open = new CCArray();
    AstarItem * temp = new AstarItem();
	<span style="background-color: rgb(51, 255, 51);">open->addObject(temp);       //加入一个空白元素到open列表中是因为头元素设置为空,方便以后的堆排序计算。</span>
	AstarItem * temp1 = new AstarItem();
	temp1->setpos(curCol,curRow);
	temp1->setg(0);
	int ag = getH(curCol,curRow);
	temp1->seth(ag);
	temp1->setfid(0);
	temp1->setf(ag);
	<span style="background-color: rgb(51, 255, 51);">open->addObject(temp1);   //将第一个起点放如open列表</span>
	close = new CCArray();
    //遍历寻找路径
	while(open->count() > 1){
	   <span style="background-color: rgb(255, 255, 0);">fromopentoclose();//open和close列表管理</span>
	  <span style="background-color: rgb(51, 255, 51);"> int fatherid = close->count() - 1;   </span>
	   if(abs(aimCol - ((AstarItem *)close->objectAtIndex(fatherid))->getcol()) <= 1 && abs(aimRow - ((AstarItem *)close->objectAtIndex(fatherid))->getrow()) <= 1){
		   getpath();
		   break;
	   }else{
           //搜索
	       starseach(fatherid);
	   }
	}
	open->removeAllObjects();
	close->removeAllObjects();
    //获得路径
	if(path->count() == 0){
	   return NULL;
	}else{
		if(((AstarItem *)path->lastObject())->getcol() != aimCol || ((AstarItem *)path->lastObject())->getrow() != aimRow){
		   AstarItem * temp = new AstarItem();
	       temp->setpos(aimCol,aimRow);
		   path->addObject(temp);
		}
		return path;
	}
}
void Astar::starseach(int fid)
{
	int col = ((AstarItem *)close->objectAtIndex(fid))->getcol();
	int row = ((AstarItem *)close->objectAtIndex(fid))->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;
	if(mycol >= 0 && checkmap(mycol,myrow)){
		if(checkOpen(mycol,myrow,fid) && checkclose(mycol,myrow)){
		   addtoopen(mycol,myrow,fid);
		}
	}
	mycol = col;
	myrow = row + 1;
	if(myrow < map->getMapSize().width && checkmap(mycol,myrow)){
		if(checkOpen(mycol,myrow,fid) && checkclose(mycol,myrow)){
		   addtoopen(mycol,myrow,fid);
		}
	}
	mycol = col + 1;
	myrow = row;
	if(mycol < map->getMapSize().height && checkmap(mycol,myrow)){
		if(checkOpen(mycol,myrow,fid) && checkclose(mycol,myrow)){
		   addtoopen(mycol,myrow,fid);
		}
	}
}
void Astar::addtoopen(int col,int row,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::checkclose(int col,int row)
{
    //检查close列表
	for(int i = close->count() - 1;i > 0;i --){
        if(((AstarItem *)close->objectAtIndex(i))->getcol() == col && ((AstarItem *)close->objectAtIndex(i))->getrow() == row){
           return false; 
		}
	}
	return true;
}
bool Astar::checkOpen(int col,int row,int id)
{
    //检查open列表中是否有更小的步长,并排序
	for(int i = open->count() - 1;i > 0;i --){
		if(((AstarItem *)open->objectAtIndex(i))->getcol() == col && ((AstarItem *)open->objectAtIndex(i))->getrow() == row){
		    int tempG = getG(col,row,id);
			if(tempG < ((AstarItem *)open->objectAtIndex(i))->getg()){
			   ((AstarItem *)open->objectAtIndex(i))->setg(tempG);
			   ((AstarItem *)open->objectAtIndex(i))->setfid(id);
			   ((AstarItem *)open->objectAtIndex(i))->setf(tempG + ((AstarItem *)open->objectAtIndex(i))->geth());
			   resetSort(i);
			}
			return false;
		}
	}
	return true;
}
bool Astar::checkmap(int col,int row)
{
    //检查地图中是否有碰撞
   if(abs(aimCol - col) > 1 || abs(aimRow - row) > 1){
	  CCTMXLayer* layer = map->layerNamed("grass");
      int tilegid = layer->tileGIDAt(ccp(col,row));
	  CCDictionary *tiledic = map->propertiesForGID(tilegid);
	  CCString *mvalue = (CCString *)tiledic->objectForKey("conflict");
      int mv = mvalue->intValue();
	  if(mv == 1){
	     return false;
	  } 
   }
   return true;
}
void Astar::getpath()
{
    //从整个close数组中找出路径
	if(path->count() == 0){
		path->addObject(close->objectAtIndex(close->count() - 1));
	}else{
	    path->insertObject(close->objectAtIndex(close->count() - 1),path->count() - 1);
	}
	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::fromopentoclose()
{
    //<span style="background-color: rgb(255, 255, 102);">把open列表中的点放到close列表中</span>
	AstarItem * temp = (AstarItem *)open->objectAtIndex(1);
	close->addObject(temp);
	removefromopen();
}
void Astar::removefromopen()
{
	int last = open->count() - 1;
	open->replaceObjectAtIndex(1,open->lastObject(),true);
	open->removeLastObject();
	last = open->count() - 1;
<span style="color:#330033;background-color: rgb(51, 255, 51);"><span style="white-space:pre">	</span>//堆排序
<span style="white-space:pre">	</span>/*int head = 1;
<span style="white-space:pre">	</span>while( ( head*2) <= last){
<span style="white-space:pre">		</span>int child1 = head * 2;
<span style="white-space:pre">		</span>int childe = head*2 + 1;
<span style="white-space:pre">		</span>int childmin;
<span style="white-space:pre">		</span>if ((head*2 + 1) < last )<span style="white-space:pre">		</span>
<span style="white-space:pre">			</span>childmin = (((AstarItem *)open->objectAtIndex(child1))->getf() <( ((AstarItem *)open->objectAtIndex(childe))->getf()) ? child1:childe);
<span style="white-space:pre">		</span>else
<span style="white-space:pre">			</span>childmin = child1;
<span style="white-space:pre">		</span>if ( ((AstarItem *)open->objectAtIndex(head))->getf() <(((AstarItem *)open->objectAtIndex(childmin))->getf()))
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">			</span>head = childmin;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>AstarItem *temp = (AstarItem *)open->objectAtIndex(childmin);
<span style="white-space:pre">		</span>open->replaceObjectAtIndex(childmin, open->objectAtIndex(head), false);
<span style="white-space:pre">		</span>open->replaceObjectAtIndex(head, temp, true);
<span style="white-space:pre">		</span>temp->release();
<span style="white-space:pre">		</span>head = childmin;
<span style="white-space:pre">	</span>}*/                                    内容属于对open中的节点进行相关的堆排序,但实现后出现程序编译通过,运行报堆栈错误,希望有遇见的朋友可以一起解决,不加入这部分的话能够实现,但是人物运动有问题,非常的不智能。属于重点讨论部分</span>

}
void Astar::resetSort(int last)
{
    //根据步长排序,堆排序
	while(last > 1){
	   int half = last / 2;
        
	   if(((AstarItem *)open->objectAtIndex(half))->getf() >= ((AstarItem *)open->objectAtIndex(last))->getf())
		   break;
	   open->exchangeObjectAtIndex(half,last);
       last = half;
	}
}
int Astar::getG(int col,int row,int id)
{
    //获得该点的g函数值
	int fx = ((AstarItem *)close->objectAtIndex(id))->getcol();
	int fy = ((AstarItem *)close->objectAtIndex(id))->getrow();
	int fg = ((AstarItem *)close->objectAtIndex(id))->getg();
	if(fx - col != 0 && fy - row != 0){
	   return fg + 14;
	}else{
	   return fg + 10;
	}
}
int Astar::getH(int col,int row)
{
    //获得该点的h值
	return abs(aimCol - col) * 10 + abs(aimRow - row) * 10;
}

接着是相关的场景文件

#ifndef __MAPSCENE_H__
#define __MAPSCENE_H__
#define LAYER_CREATE_FUNC(layer) static layer* create() { layer *pRet = new layer(); if (pRet && pRet->init()) { pRet->autorelease(); return pRet; } else { delete pRet; pRet = NULL; return NULL; } }
#include "cocos2d.h"

#include "SimpleAudioEngine.h"

#include "Astar.h"
#include "AstarItem.h"

using namespace cocos2d;

class MapScene :public CCLayer
{
private:
	CCArray * path;
	int stepindex;
	int smallstepindex;
public:
	int vmove;
	int hmove;
	Astar * myastar;
	CCSprite*	m_tamara;
	virtual bool init(); 
	void update(float dt);
	//void MapScene::update1(ccTime dt);
	static cocos2d::CCScene* scene();
	CCPoint convertto2d(float x,float y);
	virtual void menuCloseCallback(CCObject* pSender);
	virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
	LAYER_CREATE_FUNC(MapScene);
};

#endif

和实现文件

#include "MapScene.h"
#include "Astar.h"
#include "AstarItem.h"
#include <math.h>

using namespace cocos2d;

enum 
{
	kTagTileMap = 1,
};
CCScene* MapScene::scene()
{
    CCScene *scene = CCScene::create();
    MapScene *layer = MapScene::create();
    scene->addChild(layer);
    return scene;
}

// on "init" you need to initialize your instance
bool MapScene::init()
{
    if ( !CCLayer::init() )
    {
        return false;
    }
    //初始化地图
	CCTMXTiledMap *map = CCTMXTiledMap::create("iso-test-zorder.tmx");
	addChild(map, 0, kTagTileMap);
	CCSize s = map->getContentSize();
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
	----UXLOG("ContentSize: %f, %f", s.width,s.height);
	map->setPosition(ccp(-s.width/2 + winSize.width/2,0));
	//初始化人物
	m_tamara = CCSprite::create("grossinis_sister1.png");
	map->addChild(m_tamara, map->getChildren()->count() );
	m_tamara->retain();
	int mapWidth = map->getMapSize().width * map->getTileSize().width;
	int mapHeight = map->getMapSize().height * map->getTileSize().height;
	m_tamara->setPosition(ccp( mapWidth/2,112));
	m_tamara->setAnchorPoint(ccp(0.5f,0));
	setTouchEnabled(true);
	scheduleUpdate();
	vmove = -1;
	hmove = -1;
	stepindex = -1;
	myastar = new Astar();
    return true;
}
//坐标与地图位置的转换
CCPoint MapScene::convertto2d(float x,float y){
	CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);
	int mapWidth = map->getMapSize().width * map->getTileSize().width;
	int mapHeight = map->getMapSize().height * map->getTileSize().height;
	double distanse;
	double sin1;
	double sin11;
	double sin22;
	double cos11;
	double cos1;
	int d2x;
	int d2y;
	double mystatic5 = sqrt(5.0);//«Û∏˘∫≈5
	double mystatic = 16 * mystatic5;//–°ÕºøÈ¿‚≥§
	//char mch[256];
	if(x > mapWidth/2){
	   distanse = sqrt((x - mapWidth/2) * (x - mapWidth/2) + (mapHeight - y) * (mapHeight - y));
	   sin1 = (mapHeight - y)/distanse;
	   cos1 = (x - mapWidth/2)/distanse;
	   sin11 = (sin1 * 2 - cos1) / mystatic5;
	   cos11 = (sin1 + cos1 * 2) / mystatic5;
	   d2y = distanse * 5 / 4 * sin11 / mystatic;
	   sin22 = (2 * sin1 + cos1) / mystatic5;
	   d2x = distanse * 5 / 4 * sin22 / mystatic;
	   return ccp(d2x,d2y);
	}else{
	   distanse = sqrt((mapWidth/2 - x) * (mapWidth/2 - x) + (mapHeight - y) * (mapHeight - y));
	   sin1 = (mapHeight - y)/distanse;
	   cos1 = (mapWidth/2 - x)/distanse;
	   sin11 = (sin1 * 2 - cos1) / mystatic5;
	   cos11 = (sin1 + cos1 * 2) / mystatic5;
	   d2x = distanse * 5 / 4 * sin11 / mystatic;
	   //sin22 = 4.0 * cos11 / 5 + 3.0 * sin11 / 5;
	   sin22 = (2 * sin1 + cos1) / mystatic5;
	   d2y = distanse * 5 / 4 * sin22 / mystatic;
	   return ccp(d2x,d2y);
	}
}
void MapScene::update(float dt)
{
	CCPoint herop = m_tamara->getPosition();
	CCPoint mapindex = convertto2d(herop.x,herop.y);
    //根据路径移动
	if(stepindex >= 1){
	   if(smallstepindex == 0){
		   int ncol = ((AstarItem *)path->objectAtIndex(stepindex))->getcol();
		   int nrow = ((AstarItem *)path->objectAtIndex(stepindex))->getrow();
		   int pcol = ((AstarItem *)path->objectAtIndex(stepindex - 1))->getcol();
		   int prow = ((AstarItem *)path->objectAtIndex(stepindex - 1))->getrow();
		   if(pcol == ncol){
			   if(prow > nrow){
			      vmove = 2;
			   }else if(prow < nrow){
                  vmove = 3;
			   }else{
			      vmove = -1;
			   }
		   }else if(prow == nrow){
			   if(pcol > ncol){
			      vmove = 1;
			   }else if(pcol < ncol){
                  vmove = 0;
			   }else{
			      vmove = -1;
			   }
		   }else{
               vmove = -1;
		   }
	   }
	   if(vmove == 0){
	      herop.x += 1;
	      herop.y -= 0.5;
	   }else if(vmove == 1){
	      herop.x -= 1;
	      herop.y += 0.5;
	   }else if(vmove == 2){
	      herop.x += 1;
	      herop.y += 0.5;
	   }else if(vmove == 3){
	      herop.x -= 1;
	      herop.y -= 0.5;
	   }else if(vmove == 4){
	      herop.x += 1;
	   }else if(vmove == 5){
	      herop.x -= 1;
	   }else if(vmove == 6){
	      herop.y += 0.5;
	   }else if(vmove == 7){
	      herop.y -= 0.5;
	   }
	   smallstepindex ++;
	   if(smallstepindex >= 32){
	      smallstepindex = 0;
		  if(stepindex >= path->count() - 1){
		     stepindex = -1;
			 vmove = -1;
		  }else{
		     stepindex ++;
			 vmove = -1;
		  }
	   }
	}
	m_tamara->setPosition(herop);
    //地图随主角移动
	CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);
	CCSize s = map->getContentSize();
	int mapWidth = map->getMapSize().width * map->getTileSize().width;
	int mapHeight = map->getMapSize().height * map->getTileSize().height;
	float deltax = herop.x - mapWidth/2;
	float deltay = herop.y - 112;
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    map->setPosition(ccp(-s.width/2 + winSize.width/2 - deltax,-deltay));
}
void MapScene::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
	CCSetIterator it = pTouches->begin();
    CCTouch* touch = (CCTouch*)(*it);

    CCPoint m_tBeginPos = touch->locationInView();    
    m_tBeginPos = CCDirector::sharedDirector()->convertToGL( m_tBeginPos );
    char mch[256];
	CCTMXTiledMap* map = (CCTMXTiledMap*) getChildByTag(kTagTileMap);
	CCPoint mapp = map->getPosition();
    //获得触摸点位置在地图上的索引(行列)
	CCPoint aimmapindex = convertto2d(m_tBeginPos.x - mapp.x,m_tBeginPos.y - mapp.y);
	if(aimmapindex.x < 0 || aimmapindex.y < 0 || aimmapindex.x >= map->getMapSize().width || aimmapindex.y >= map->getMapSize().height)
	{
		return;
	}
	CCPoint herop = m_tamara->getPosition();
	CCPoint mapindex = convertto2d(herop.x,herop.y);
	CCTMXLayer* layer = map->layerNamed("grass");
	int tilegid = layer->tileGIDAt(ccp(aimmapindex.x,aimmapindex.y));
	CCDictionary *tiledic = map->propertiesForGID(tilegid);
	CCString *mvalue = (CCString *)tiledic->objectForKey("conflict");
	int mv = mvalue->intValue();
	if(mv == 1){
	   return;
	}
    //A星搜索
	path = myastar->findPath(mapindex.x,mapindex.y,aimmapindex.x,aimmapindex.y,map);
	stepindex = 1;
	smallstepindex = 0;
}
void MapScene::menuCloseCallback(CCObject* pSender)
{
    // "close" menu item clicked
    CCDirector::sharedDirector()->end();
}


最后注意在AppDelegat文件中做相关的场景替换

    CCScene *pScene = MapScene::scene();

我在实现中把屏幕放大为960*640尺寸,便于观察实际的效果。

    AppDelegate app;
    CCEGLView* eglView = CCEGLView::sharedOpenGLView();
<span style="color:#ff6666;"><span style="background-color: rgb(255, 204, 204);">    eglView->setFrameSize(960, 640);</span>
</span>
    int ret = CCApplication::sharedApplication()->run();
最后的实现效果如图所示:



由于在Sstar::remevefromopen方法中有堆排序部分的确实,造成效果比较差,实现后由会出现堆栈错误的问题,目前正在解决。这几天研究下看看问题所在。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值