cocos2dx A* + tiledMap(改良升级)

此次在之前那篇cocos2dx A* + tiledMap文章中新加了些功能并且调整了结构

拥有的功能:

能避开障碍物,搜寻最优路径

优化了行走的路径,使之平滑行走(之前的是瓦片级的, 现在是像素级的, #define PRECISE_SEARCH_PATH 开启精确的路径行走)

添加了人物根据位置会被物体遮住或遮住物体的功能

添加了点击路面, 到达该点.   点击物体, 可以到达该物体的功能

添加了捡拾物体功能

添加了坐椅子功能

添加了人物的骨骼动画(行走和站立)

PathSearchInfo 搜索路径引擎

Player 玩家类

PathSprite 瓦片精灵类

Paddle物体类(桌子,椅子等)

MathLogic 数学逻辑类

cocos2dx A* + tiledMap(改良升级)_第1张图片


#pragma once
#include "StaticValue.h"
#include "PathSprite.h"
#include "MathLogic.h"
#include "cocos2d.h"
#include <functional>
#include "paddle.h"
USING_NS_CC;
class PathSearchInfo:public CCNode//寻路类(主要负责寻路的参数和逻辑)
{
public:
	PathSearchInfo(CCTMXTiledMap* tiledMap);

private:
	int m_playerMoveStep;//人物当前的行程的索引
	std::function<void(CCPoint)> m_moveDone;//移动结束回调
	bool m_isSetMoveDoneCallback;

	std::function<void(vector<PathSprite*>)> m_drawPath;//画线回调  调试用
	bool m_isSetDrawPathCallback;

	std::function<void(CCPoint point, Paddle* selectObj)> m_selectObj;//选中物体回调
	bool m_isSetSelectObjCallback;

	CCTMXTiledMap* m_map;//地图
	CCTMXLayer* m_road;//道路
	CCSize m_mapSize;//地图大小
	CCSize m_tileSize;//地图的块大小
	vector<PathSprite*> m_openList;//开放列表(里面存放相邻节点)
	PathSprite* m_inspectArray[MAP_WIDTH][MAP_HEIGHT];//全部需要检测的点
	vector<PathSprite*> m_pathList;//路径列表
	vector<PathSprite*> m_haveInspectList;//检测过的列表
	PathSprite* m_moveObj;//移动的物体
	bool m_enableMove;//是否能移动
	bool m_isMoving;//是否正在移动
public:
	CCTMXTiledMap* getMap()
	{
		return m_map;
	}
	void setEnableMove(bool isEnable)
	{
		m_enableMove = isEnable;
	}

	bool getEnableMove()
	{
		return m_enableMove;
	}

	bool getIsMoving()
	{
		return m_isMoving;
	}
 	void setMoveDoneCallback(function<void(CCPoint)>& pFunc);//设置回调

	void setDrawPathCallback(function<void(vector<PathSprite*>)>& pFunc);//设置回调
	
	void setSelectCallback(function<void(CCPoint point, Paddle* selectObj)> &pFunc);//设置回调

	void initMapObject(const char* layerName, const char* objName);////初始化地图里的物体(设置深度,设置物体回调函数)

	CCPoint getMapPositionByWorldPosition(CCPoint point);//根据世界坐标得到地图坐标

	CCPoint getWorldPositionByMapPosition(CCPoint point);//根据地图坐标得到世界坐标

	void pathFunction( CCPoint point, PathSprite* obj );//计算路径函数

private:
	void calculatePath();//计算路径
	
	float calculateTwoObjDistance(PathSprite* obj1, PathSprite* obj2);//计算两个物体间的距离

	void inspectTheAdjacentNodes(PathSprite* node, PathSprite* adjacent, PathSprite* endNode);//把相邻的节点放入开放节点中
	
	PathSprite* getMinPathFormOpenList();//从开放节点中获取F值最小值的点
	
	PathSprite* getObjFromInspectArray(int x, int y);//根据横纵坐标从检测数组中获取点
	
	bool removeObjFromOpenList( PathSprite* sprite);//从开放列表中移除对象
	
	void resetInspectArray();//重置检测列表
	
	bool detectWhetherCanPassBetweenTwoPoints(CCPoint p1, CCPoint p2);//检测2个位置中是否有障碍物
	
	void resetObjPosition();//重置玩家位置
	
	void clearPath();//清除路径

	void moveObj();//移动实现函数
};

#include "PathSearchInfo.h"


PathSearchInfo::PathSearchInfo( CCTMXTiledMap* tiledMap )
{
	memset(m_inspectArray, NULL, MAP_WIDTH*MAP_HEIGHT*sizeof(PathSprite*));
	m_isSetMoveDoneCallback = false;
	m_isSetDrawPathCallback = false;
	m_isSetSelectObjCallback = false;
	m_enableMove = true;

	m_map = tiledMap;
	m_mapSize = m_map->getMapSize();//获取地图的尺寸 地图单位
	m_tileSize = m_map->getTileSize();//获取瓦片的尺寸  世界单位
	m_road = m_map->layerNamed("road");//行走路径的地图

	for (int j = 0;  j < m_mapSize.height; j++) {
		for (int i = 0;  i < m_mapSize.width; i++) {
			CCSprite* _sp = m_road->tileAt(CCPoint(i, j));
			if (_sp) {
				PathSprite* _pathSprite = new PathSprite(_sp);
				_pathSprite->m_x = i;
				_pathSprite->m_y = j;

				m_inspectArray[i][j] = _pathSprite;//把地图中所有的点一一对应放入检测列表中
			}
		}
	}	
}

void PathSearchInfo::setMoveDoneCallback( function<void(CCPoint)>& pFunc )
{
	m_moveDone = pFunc;
	m_isSetMoveDoneCallback = true;
}

void PathSearchInfo::setDrawPathCallback( function<void(vector<PathSprite*>)>& pFunc )
{
	m_drawPath = pFunc;
	m_isSetDrawPathCallback = true;
}

void PathSearchInfo::setSelectCallback( function<void(CCPoint point, Paddle* selectObj)> &pFunc )
{
	m_selectObj = pFunc;
	m_isSetSelectObjCallback = true;
}

void PathSearchInfo::initMapObject( const char* layerName, const char* objName )
{
	//图片层
	CCTMXLayer* _layer = m_map->layerNamed(layerName);
	if (!_layer)
	{
		return;
	}
	//对象层
	CCTMXObjectGroup* pipeGroup = m_map->objectGroupNamed(objName);
	if (!pipeGroup)
	{
		return;
	}
	//得到所有的对象
	CCArray* _array = pipeGroup->getObjects();
	CCObject *_obj;
	CCARRAY_FOREACH(_array, _obj )
	{
		//得一个
		CCDictionary* _dictionary  = (CCDictionary*)_obj;

		//得到属性
		float _x = ((CCString*)_dictionary->objectForKey("x"))->floatValue();//世界单位
		float _y= ((CCString*)_dictionary->objectForKey("y"))->floatValue();
		float _widht = ((CCString*)_dictionary->objectForKey("width"))->floatValue();//世界单位
		float _height = ((CCString*)_dictionary->objectForKey("height"))->floatValue();

		CCString* _terminalX = ((CCString*)_dictionary->objectForKey("terminalX"));//终点x坐标
		CCString* _terminalY = ((CCString*)_dictionary->objectForKey("terminalY"));//终点y坐标
		CCString* _type = ((CCString*)_dictionary->objectForKey("type"));//物体类型
		CCString* _enableSit = ((CCString*)_dictionary->objectForKey("enableSit"));//是否能坐下
		CCString* _enableTouch =(( CCString*)_dictionary->objectForKey("enableTouch"));//是否能触摸
		CCString* _enablePickUp =(( CCString*)_dictionary->objectForKey("enablePickUp"));//是否能触摸

		Paddle* _parent = Paddle::paddleWithContentSize(CCSize(_widht, _height));//创建一个物体类

		//设置物体属性
		if (_terminalX && _terminalY)
		{
			_parent->m_terminal = CCPoint( _terminalX->floatValue(), _terminalY->floatValue());
			if (m_isSetSelectObjCallback)
			{
				_parent->m_selectCallback =m_selectObj;
			}

		}
		else
		{
			_parent->m_terminal = CCPoint(-1, -1);
		}
		_parent->m_type = _type?  (OBJTYPE)_type->intValue():NONE_TYPE;
		_parent->m_enableSit = _enableSit? _enableSit->boolValue():false;
		_parent->m_enableTouch = _enableTouch?_enableTouch->boolValue():false;
		if (_enablePickUp)
		{
			_parent->m_enablePickUp = _enablePickUp->boolValue();
			_parent->m_selectCallback =m_selectObj;
		}
		else
		{
			_parent->m_enablePickUp =false;
		}
		//设置物体位置
		CCPoint _offset = CCPoint(_x, _y  );//偏移量
		_parent->setPosition(_offset);
		_parent->setAnchorPoint(CCPoint(0,0));

		for (int i = 0; i < _widht/m_tileSize.width; i++)
		{
			for (int j = 0; j < _height/m_tileSize.height; j++)
			{
				CCSprite* _Sprite = _layer->tileAt(CCPoint(_x/m_tileSize.width+i,m_mapSize.height-1-_y/m_tileSize.height-j));
				if (_Sprite)
				{

					_Sprite->retain();
					_Sprite->removeFromParent();
					_Sprite->setPosition(_Sprite->getPosition()-_offset);
					_parent->addChild(_Sprite);
					_Sprite->release();

#if 0//测试该物体
					CCMoveBy* action = CCMoveBy::create(1,CCPoint(0,50));
					CCMoveBy* actionR = CCMoveBy::create(1,CCPoint(0,-50));
					CCSequence* seq = CCSequence::create(action, actionR, NULL);
					_Sprite->runAction(CCRepeatForever::create(seq));
#endif

				}

			}
		}

		//设置对象深度
		if (_parent->m_enablePickUp)
		{
			m_map->addChild(_parent, BASE_ZODER - getWorldPositionByMapPosition(m_mapSize).y  );
		}
		else
		{
			m_map->addChild(_parent, BASE_ZODER - _y );
		}
		

	}
} 

void PathSearchInfo::pathFunction( CCPoint point, PathSprite* obj )
{
	if (!m_enableMove)
	{
		return;
	}
	if (point.x <0 || point.y<0)
	{
		return;
	}
	// 		if (m_moveDone())//判断是否到达目的地
	// 		{
	// 			return;
	// 		}
	//m_moveDone();//判断是否到达目的地
	m_moveObj = obj;
	resetObjPosition();
	clearPath();

	PathSprite*_sp = m_inspectArray[(int)point.x][(int)(point.y)];
	if (_sp) {

		//获取触摸点, 设置为终点
		obj->m_endX = _sp->m_x;
		obj->m_endY = _sp->m_y;
		//计算路径
		calculatePath();

		resetInspectArray();
		//移动物体
		moveObj();

		//绘制路径
		if (m_isSetDrawPathCallback)
		{
			m_drawPath(m_pathList);
		}
	}

}

void PathSearchInfo::calculatePath()
{
#ifdef PRECISE_SEARCH_PATH
	//得到开始点的节点
	PathSprite*    _endNode= m_inspectArray[m_moveObj->m_startX][m_moveObj->m_startY];
	//得到结束点的节点
	PathSprite*   _startNode = m_inspectArray[m_moveObj->m_endX][m_moveObj->m_endY];

	//因为是开始点 把到起始点的距离设为0, F值也为0
	_startNode->m_costToSource = 0;
	_startNode->m_FValue = 0;

	//把已经检测过的点从检测列表中删除
	m_inspectArray[m_moveObj->m_endX][m_moveObj->m_endY] = NULL;
	//把该点放入已经检测过点的列表中
	m_haveInspectList.push_back(_startNode);
	//然后加入开放列表
	m_openList.push_back(_startNode);

	PathSprite* _node = NULL;
	while (true)
	{
		//得到离起始点最近的点(如果是第一次执行, 得到的是起点)
		_node = getMinPathFormOpenList();
		if (!_node)
		{
			//找不到路径
			break;
		}
		//把计算过的点从开放列表中删除
		removeObjFromOpenList( _node);
		int _x = _node->m_x;
		int _y = _node->m_y;

		//
		if (_x ==m_moveObj->m_startX && _y == m_moveObj->m_startY)
		{
			break;
		}

		//检测8个方向的相邻节点是否可以放入开放列表中


		PathSprite* _adjacent = NULL;




		_adjacent = getObjFromInspectArray(  _x +1, _y);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x , _y -1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x , _y+1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);


		_adjacent = getObjFromInspectArray( _x + 1, _y + 1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x +1, _y-1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y - 1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y+1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);


	}

	while (_node)
	{
		//把路径点加入到路径列表中
		//m_pathList.insert(m_pathList.begin(), _node);
		m_pathList.push_back(_node);
		_node = _node->m_parent;
	}
#else

	//得到开始点的节点
	PathSprite*   _startNode = m_inspectArray[m_moveObj->m_startX][m_moveObj->m_startY];
	//得到结束点的节点
	PathSprite*  _endNode = m_inspectArray[m_moveObj->m_endX][m_moveObj->m_endY];

	//因为是开始点 把到起始点的距离设为0, F值也为0
	_startNode->m_costToSource = 0;
	_startNode->m_FValue = 0;

	//把已经检测过的点从检测列表中删除
	m_inspectArray[m_moveObj->m_startX][m_moveObj->m_startY] = NULL;
	//把该点放入已经检测过点的列表中
	m_haveInspectList.push_back(_startNode);
	//然后加入开放列表
	m_openList.push_back(_startNode);

	PathSprite* _node = NULL;
	while (true)
	{
		//得到离起始点最近的点(如果是第一次执行, 得到的是起点)
		_node = getMinPathFormOpenList();
		if (!_node)
		{
			//找不到路径
			break;
		}
		//把计算过的点从开放列表中删除
		removeObjFromOpenList( _node);
		int _x = _node->m_x;
		int _y = _node->m_y;

		//
		if (_x ==m_moveObj->m_endX && _y == m_moveObj->m_endY)
		{
			break;
		}

		//检测8个方向的相邻节点是否可以放入开放列表中


		PathSprite* _adjacent = NULL;




		_adjacent = getObjFromInspectArray(  _x +1, _y);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x , _y -1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x , _y+1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);


		_adjacent = getObjFromInspectArray( _x + 1, _y + 1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x +1, _y-1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y - 1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);

		_adjacent = getObjFromInspectArray(  _x -1, _y+1);
		inspectTheAdjacentNodes(_node, _adjacent, _endNode);


	}

	while (_node)
	{
		//把路径点加入到路径列表中
		m_pathList.insert(m_pathList.begin(), _node);
		//m_pathList.push_back(_node);
		_node = _node->m_parent;
	}
#endif // PRECISE_SEARCH_PATH


}

float PathSearchInfo::calculateTwoObjDistance( PathSprite* obj1, PathSprite* obj2 )
{

	float _x = abs(obj2->m_x - obj1->m_x);
	float _y = abs(obj2->m_y - obj1->m_y);

	return _x + _y;
}

void PathSearchInfo::inspectTheAdjacentNodes( PathSprite* node, PathSprite* adjacent, PathSprite* endNode )
{
	if (adjacent)
	{
		float _x = abs(endNode->m_x - adjacent->m_x);
		float _y = abs(endNode->m_y - adjacent->m_y);

		float F , G, H1, H2, H3;
		adjacent->m_costToSource = node->m_costToSource + calculateTwoObjDistance(node, adjacent);//获得累计的路程
		G = adjacent->m_costToSource;

		//三种算法, 感觉H2不错
		H1 = _x + _y;
		H2 = hypot(_x, _y);
		H3 = max(_x, _y);

#if 1 //A*算法 = Dijkstra算法 + 最佳优先搜索
		F = G + H1;
#endif
#if 0//Dijkstra算法
		F = G;
#endif
#if 0//最佳优先搜索
		F = H2;
#endif
		adjacent->m_FValue = F;

		adjacent->m_parent = node;//设置父节点
		adjacent->m_sprite->setColor(ccORANGE);//搜寻过的节点设为橘色(测试用)
		m_haveInspectList.push_back(adjacent);
		node->m_child = adjacent;//设置子节点

		PathSearchInfo::m_inspectArray[adjacent->m_x][adjacent->m_y] = NULL;//把检测过的点从检测列表中删除
		PathSearchInfo::m_openList.push_back(adjacent);//加入开放列表
	}
}

PathSprite* PathSearchInfo::getMinPathFormOpenList()
{
	if (m_openList.size()>0) {
		PathSprite* _sp =* m_openList.begin();
		for (vector<PathSprite*>::iterator iter = m_openList.begin(); iter !=  m_openList.end(); iter++)
		{
			if ((*iter)->m_FValue < _sp->m_FValue)
			{
				_sp = *iter;
			}
		}
		return _sp;
	}
	else
	{
		return NULL;
	}

}

PathSprite* PathSearchInfo::getObjFromInspectArray( int x, int y )
{
	if (x >=0 && y >=0 && x < m_mapSize.width && y < m_mapSize.height) {
		return m_inspectArray[x][y];
	}
	return  NULL;
}

bool PathSearchInfo::removeObjFromOpenList( PathSprite* sprite )
{
	if (!sprite) {
		return  false;
	}
	for (vector<PathSprite*>::iterator iter = m_openList.begin(); iter !=  m_openList.end(); iter++)
	{
		if (*iter == sprite)
		{
			m_openList.erase(iter);
			return true;
		}
	}
	return false;

}  

cocos2d::CCPoint PathSearchInfo::getMapPositionByWorldPosition( CCPoint point )
{
	return CCPoint((int)(point.x/PathSearchInfo::m_tileSize.width),(int)(PathSearchInfo::m_mapSize.height - point.y/PathSearchInfo::m_tileSize.height) );
}

cocos2d::CCPoint PathSearchInfo::getWorldPositionByMapPosition( CCPoint point )
{
	return CCPoint(PathSearchInfo::m_tileSize.width * point.x, (PathSearchInfo::m_mapSize.height + point.y)*PathSearchInfo::m_tileSize.height);
}

void PathSearchInfo::resetInspectArray()
{
	for (vector<PathSprite*>::iterator iter = m_haveInspectList.begin(); iter != m_haveInspectList.end(); iter++)
	{
		//(*iter)->m_sprite->setColor(ccWHITE);
		(*iter)->m_costToSource = 0;
		(*iter)->m_FValue = 0;
		(*iter)->m_parent = NULL;
		(*iter)->m_child = NULL;

		m_inspectArray[(*iter)->m_x][(*iter)->m_y] = (*iter);
	}
}

bool PathSearchInfo::detectWhetherCanPassBetweenTwoPoints( CCPoint p1, CCPoint p2 )
{ 
	float _maxX = p1.x>p2.x?p1.x:p2.x;
	float _maxY = p1.y>p2.y?p1.y:p2.y;
	float _minX = p1.x<p2.x?p1.x:p2.x;
	float _minY = p1.y<p2.y?p1.y:p2.y;

	if (p1.x == p2.x)
	{
		if (_maxY - _minY >1)
		{
			return false;
		}
		float _x = p1.x;
		for (int _y = _minY; _y <=_maxY; _y++)
		{
			PathSprite*_sp = m_inspectArray[(int)_x][(int)(_y)];
			if (!_sp)
			{
				return false;
			} 
		}

	}
	else if (p1.y == p2.y)
	{
		if (_maxX - _minX > 1)
		{
			return false;
		}
		float _y = p1.y;
		for (int _x = _minX; _x <=_maxX; _x++ )
		{
			PathSprite*_sp = m_inspectArray[(int)_x][(int)(_y)];
			if (!_sp)
			{
				return false;
			} 
		}
	}
	else
	{
		for (int _y = _minY; _y <= _maxY; _y++)
		{
			for (int _x = _minX; _x <= _maxX; _x++)
			{
				float _length = MathLogic::linearEquationWithOneUnknown_solveShortLenghtRequiredPoint(p1, p2, CCPoint(_x, _y));
				float _maxLength = MathLogic::calculateLengthRequiredTwoPoint(CCPoint(0,0), CCPoint(0.5,0.5));
				if (_length < _maxLength)
				{
					PathSprite*_sp = m_inspectArray[(int)_x][(int)(_y)];
					if (!_sp)
					{
						return false;
					} 
				}

			}
		}
	}

	return true;
}

void PathSearchInfo::resetObjPosition(  )
{
#ifdef PRECISE_SEARCH_PATH

	CCPoint _point = getMapPositionByWorldPosition(m_moveObj->m_sprite->getPosition());
	CCSprite* _sp = m_road->tileAt(_point);

	if (_sp)
	{
		m_moveObj->m_x = _point.x;
		m_moveObj->m_y = _point.y;
	} 
	else
	{
		CCSprite* _up = m_road->tileAt(_point + CCPoint(0, -1));
		if (_up)
		{
			m_moveObj->m_x = _point.x;
			m_moveObj->m_y = _point.y - 1;
			return;
		}
		CCSprite* _down = m_road->tileAt(_point + CCPoint(0, 1));
		if (_down)
		{
			m_moveObj->m_x = _point.x;
			m_moveObj->m_y = _point.y +1;
			return;
		}
		CCSprite* _left = m_road->tileAt(_point + CCPoint(-1, 0));
		if (_left)
		{
			m_moveObj->m_x = _point.x -1;
			m_moveObj->m_y = _point.y ;
			return;
		}
		CCSprite* _right = m_road->tileAt(_point + CCPoint(1, 0));
		if (_right)
		{
			m_moveObj->m_x = _point.x + 1;
			m_moveObj->m_y = _point.y ;
			return;
		}

	}
#endif // PRECISE
}

void PathSearchInfo::clearPath(  )
{
	
	for (vector<PathSprite*>::iterator iter = m_haveInspectList.begin(); iter !=  m_haveInspectList.end(); iter++)
	{
		(*iter)->m_sprite->setColor(ccWHITE);
	}
	resetInspectArray();

	//把移除了障碍物的地图放入检测列表中
	//m_inspectList = m_mapList;
	m_openList.clear();
	m_pathList.clear();
	m_haveInspectList.clear();
	m_moveObj->m_startX = m_moveObj->m_x;
	m_moveObj->m_startY = m_moveObj->m_y;
	m_moveObj->m_sprite->stopAllActions();

	m_playerMoveStep = 0;
}



void PathSearchInfo::moveObj()
{
#ifndef PRECISE_SEARCH_PATH
	m_playerMoveStep++;
	m_isMoving = true;
	//如果运动完毕
	if (m_playerMoveStep >= m_pathList.size())
	{
		if (m_isSetMoveDoneCallback)
		{
			m_isMoving = false;
			m_moveDone(CCPoint((*(m_pathList.end()-1))->m_x, (*(m_pathList.end()-1))->m_y));
		}
		return;
	}
	//存储当前的移动进程
	m_moveObj->m_x = m_pathList[m_playerMoveStep]->m_x;
	m_moveObj->m_y = m_pathList[m_playerMoveStep]->m_y;

	//设置深度
	m_moveObj->m_sprite->setZOrder(BASE_ZODER - m_pathList[m_playerMoveStep]->m_sprite->getPositionY());

	//根据路径列表移动人物
	CCPoint _terminalPosition =  m_pathList[m_playerMoveStep]->m_sprite->getPosition()+m_tileSize/2;
	float _length =  MathLogic::calculateLengthRequiredTwoPoint(_terminalPosition,m_moveObj->m_sprite->getPosition());
	m_moveObj->m_sprite->runAction(CCSequence::create(CCMoveTo::create(MOVE_SPEED * _length,_terminalPosition), CCCallFunc::create(this, SEL_CallFunc(&PathSearchInfo::moveObj)), NULL));
#else
	m_isMoving = true;
	
	if (m_playerMoveStep == m_pathList.size()-1)
	{
		//sitChairJudge();
		if (m_isSetMoveDoneCallback)
		{
			m_isMoving = false;
			m_moveDone(CCPoint((*(m_pathList.end()-1))->m_x, (*(m_pathList.end()-1))->m_y));
		}
		return ;
	}

	for (int i = 1;i <= m_pathList.size() ;i++)
	{
		m_playerMoveStep = m_pathList.size()-i;

		if(detectWhetherCanPassBetweenTwoPoints(CCPoint(m_moveObj->m_x, m_moveObj->m_y), CCPoint(m_pathList[m_playerMoveStep]->m_x,m_pathList[m_playerMoveStep]->m_y)))
		{
			CCPoint _terminalPosition = m_pathList[m_playerMoveStep]->m_sprite->getPosition()+m_tileSize/2;
			float _length = MathLogic::calculateLengthRequiredTwoPoint(_terminalPosition,m_moveObj->m_sprite->getPosition());
			m_moveObj->m_sprite->runAction(CCSequence::create(CCMoveTo::create(MOVE_SPEED * _length,_terminalPosition), CCCallFunc::create(this, SEL_CallFunc(&PathSearchInfo::moveObj)), NULL));
			//存储当前的移动进程
			m_moveObj->m_x = m_pathList[m_playerMoveStep]->m_x;
			m_moveObj->m_y = m_pathList[m_playerMoveStep]->m_y;

			m_moveObj->m_sprite->setZOrder(BASE_ZODER - m_pathList[m_playerMoveStep]->m_sprite->getPositionY());

			break;
		}
	}


#endif
}



#pragma once

#include "cocos2d.h"
#include "vector"
#include "cocos-ext.h"
using namespace std;
USING_NS_CC;
USING_NS_CC_EXT;
class PathSprite 
{
public:
	PathSprite(CCSprite* sprite):m_parent(NULL),
												m_child(NULL),
												m_costToSource(0),
												m_FValue(0),
												m_sprite(sprite),
												m_startX(0),
												m_startY(0),
												m_endX(0),
												m_endY(0)
	{

	};
public:
	CCSprite* m_sprite;//包含的瓦片精灵
	PathSprite* m_parent;//父节点
	PathSprite* m_child;//子节点
	float m_costToSource;//到起始点的距离
	int m_x;//地图坐标
	int m_y;
	float m_FValue;

	int m_startX;//开始点
	int m_startY;

	int m_endX;//结束点
	int m_endY;

};

#pragma once
#include "PathSprite.h"
enum WalkState
{
	WALK_LEFT,
	WALK_RIGHT,
	WALK_STAND
};

class Player:public PathSprite
{
public:
	CCArmature *armature;
	WalkState m_walkState;
public:
	Player(CCSprite* sprite);
public:
	void walkLeft();
	
	void walkRight();

	void stand();
	
	void walking();
};

#include "Player.h"

Player::Player(CCSprite* sprite):PathSprite(sprite)
{
	//创建一个人物
	CCArmatureDataManager::sharedArmatureDataManager()->addArmatureFileInfo("DemoPlayer/DemoPlayer.ExportJson");
	armature = NULL;
	armature = CCArmature::create("DemoPlayer");//0走路,1开枪,2开枪,3开空枪,4
	armature->setAnchorPoint(CCPoint(0.7, 0));

	sprite->addChild(armature);
}

void Player::walkLeft()
{
	if (m_walkState == WALK_LEFT)
	{
		return;
	}
	armature->getAnimation()->playWithIndex(1);
	armature->setScaleX(1);
	m_walkState = WALK_LEFT;
}

void Player::walkRight()
{
	if (m_walkState == WALK_RIGHT)
	{
		return;
	}
	armature->getAnimation()->playWithIndex(1);
	armature->setScaleX(-1);
	m_walkState = WALK_RIGHT;
}

void Player::stand()
{
	if (m_walkState == WALK_STAND)
	{
		return;
	}
	if (m_walkState == WALK_LEFT)
	{
		armature->getAnimation()->playWithIndex(2);
		armature->setScaleX(1);
	}
	if (m_walkState == WALK_RIGHT)
	{
		armature->getAnimation()->playWithIndex(2);
		armature->setScaleX(-1);
	}
	m_walkState = WALK_STAND;
}

void Player::walking()
{
	if (m_endX - m_startX  >=0)
	{
		walkRight();
	}
	else
	{
		walkLeft();
	}
}

#ifndef _PADDLE_H_
#define _PADDLE_H_

#include "cocos2d.h"
#include <functional>
//#include "stdafx.h"
//using namespace std;

USING_NS_CC;

typedef enum tagPaddleState 
{
	kPaddleStateGrabbed,
	kPaddleStateUngrabbed
} PaddleState; 
enum OBJTYPE
{
	NONE_TYPE = 0,
	CHAIR_LEFT = 1,
	CHAIR_FRON = 2 ,
	CHAIR_RIGHT = 3,
	CHAIR_BACK = 4
};
class Paddle : public CCSprite, public CCTargetedTouchDelegate
{
public:
	PaddleState        m_state;
	bool m_isSelect;
	bool m_enableSit;
	bool m_enableTouch;
	bool m_enablePickUp;
	CCPoint m_terminal;
	std::function<void(CCPoint, Paddle* )> m_selectCallback;
	OBJTYPE m_type;
	CCSprite* m_playerSprite;
	CCSprite* m_chairPartSprite;
public:
	Paddle(void);
	virtual ~Paddle(void);

	CCRect rect();
	bool initWithTexture();
	virtual void onEnter();
	virtual void onExit();
	bool containsTouchLocation(CCPoint point);
	virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
	virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
	virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
	virtual CCObject* copyWithZone(CCZone *pZone);

	virtual void touchDelegateRetain();
	virtual void touchDelegateRelease();

	static Paddle* paddleWithContentSize(CCSize);//创建物体

	void setSelect(bool isSelect);//选中时
	void setOpacity(GLubyte opacity);
	void sitChair();//坐下
	void standUp();//站起
	
};

#endif

#include "Paddle.h"
#include "FilePath.h"
using namespace std;
Paddle::Paddle(void):m_chairPartSprite(NULL), m_playerSprite(NULL),m_enableSit(false)
{
}

Paddle::~Paddle(void)
{
}

CCRect Paddle::rect()
{
	CCSize s = this->getContentSize();
	return CCRectMake(this->getPositionX(),  this->getPositionY(), s.width, s.height);
}

Paddle* Paddle::paddleWithContentSize(CCSize size)
{
	Paddle* pPaddle = new Paddle();
	pPaddle->initWithTexture();
	pPaddle->setContentSize(size);

	pPaddle->autorelease();

	return pPaddle;
}

bool Paddle::initWithTexture()
{
	if( CCSprite::init() )
	{
		m_state = kPaddleStateUngrabbed;
	}

	return true;
}

void Paddle::onEnter()
{
	CCDirector* pDirector = CCDirector::sharedDirector();
	pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
	CCSprite::onEnter();
}

void Paddle::onExit()
{
	CCDirector* pDirector = CCDirector::sharedDirector();
	pDirector->getTouchDispatcher()->removeDelegate(this);
	CCSprite::onExit();
}    

bool Paddle::containsTouchLocation(CCPoint point)
{
	//CCLog("%f, %f", convertToNodeSpaceAR(point).x, convertToNodeSpaceAR(point).y);
	return rect().containsPoint((point));

}

bool Paddle::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
	if (m_isSelect) {
		setSelect(false);

	}
	auto nodePosition = this->getParent()->convertToNodeSpace( touch->getLocation() );
	CCLog("%f, %f", nodePosition.x, nodePosition.y);
	if (m_state != kPaddleStateUngrabbed) return false;
	if ( !containsTouchLocation(nodePosition) ) return false;
	CCLog("touchSuccess")  ;
	m_state = kPaddleStateGrabbed;

	setSelect(true);

	if (m_selectCallback)
	{
		m_selectCallback(m_terminal, this);
	}
	
	//sitChair();
	

	return true;
}

void Paddle::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
	// If it weren't for the TouchDispatcher, you would need to keep a reference
	// to the touch from touchBegan and check that the current touch is the same
	// as that one.
	// Actually, it would be even more complicated since in the Cocos dispatcher
	// you get CCSets instead of 1 UITouch, so you'd need to loop through the set
	// in each touchXXX method.

	CCAssert(m_state == kPaddleStateGrabbed, "Paddle - Unexpected state!");    

	// CCPoint touchPoint = touch->getLocation();

	//setPosition( ccp(touchPoint.x, getPosition().y) );
}

CCObject* Paddle::copyWithZone(CCZone *pZone)
{
	this->retain();
	return this;
}

void Paddle::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
	CCAssert(m_state == kPaddleStateGrabbed, "Paddle - Unexpected state!");    

	m_state = kPaddleStateUngrabbed;
} 

void Paddle::touchDelegateRetain()
{
	this->retain();
}

void Paddle::touchDelegateRelease()
{
	this->release();
}

void Paddle::setSelect(bool isSelect)
{
	CCArray* _array = this->getChildren();
	CCObject *_obj;
	m_isSelect = isSelect;
	CCARRAY_FOREACH(_array, _obj )
	{
		CCSprite* _sp = (CCSprite *)_obj;
		if (isSelect)
		{
			_sp->setColor(ccRED);
		}
		else
		{
			_sp->setColor(ccWHITE);

		}

	}


}

void Paddle::setOpacity( GLubyte opacity )
{
	CCArray* _array = this->getChildren();
	CCObject *_obj;
	CCARRAY_FOREACH(_array, _obj )
	{
		CCSprite* _sp = (CCSprite *)_obj;
		_sp->setOpacity(opacity);
	}
}

void Paddle::sitChair()
{
	switch (m_type)
	{
	case NONE_TYPE:
		break;
	case CHAIR_LEFT:
		{
			m_playerSprite = CCSprite::create(g_chair_left_player);
			m_playerSprite->setAnchorPoint(CCPoint());
			m_playerSprite->setPosition(CCPoint(-8,-15));
			this->addChild(m_playerSprite, 100);

			m_chairPartSprite= CCSprite::create(g_chair_left_part);
			m_chairPartSprite->setAnchorPoint(CCPoint());
			m_chairPartSprite->setPosition(CCPoint(-15,-5));
			this->addChild(m_chairPartSprite, 100);
			break;
		}
	case CHAIR_FRON:
		break;
	case CHAIR_RIGHT:
		break;
	case CHAIR_BACK:
		{

			m_playerSprite = CCSprite::create(g_chair_back_player);
			m_playerSprite->setAnchorPoint(CCPoint());
			m_playerSprite->setPosition(CCPoint(-15,-5));
			this->addChild(m_playerSprite);
			break;
		}
	default:
		break;
	}
}

void Paddle::standUp()
{
	if (m_playerSprite)
	{
		m_playerSprite->removeFromParentAndCleanup(true);
		m_playerSprite = NULL;
	}
	if (m_chairPartSprite)
	{
		m_chairPartSprite->removeFromParentAndCleanup(true);
		m_chairPartSprite = NULL;
	}
}

//
//  MathLogic.h
//  MapGame
//
//  Created by TinyUlt on 14/10/11.
//
//

#ifndef __MapGame__MathLogic__
#define __MapGame__MathLogic__

#include <stdio.h>
#include "cocos2d.h"
USING_NS_CC;
class MathLogic
{
public:
	//线性方程 一元二次方法 求y
	static float linearEquationWithOneUnknown_solveYRequiredX(CCPoint knownPoint1, CCPoint knownPoint2, float x)
	{
		float _x1 = knownPoint1.x;
		float _y1 = knownPoint1.y;
		float _x2 = knownPoint2.x;
		float _y2 = knownPoint2.y;
		float m_p1 = (_y1 -_y2)/(_x1-_x2);
		float m_p2 = _y1 - m_p1 * _x1;
		//         float m_p1 = (knownPoint1.y -knownPoint2.y)/(knownPoint1.x-knownPoint2.x);
		//         float m_p2 = knownPoint1.y - m_p1 * knownPoint1.x;

		return m_p1* x + m_p2;
	}

	//线性方程 一元二次方法 求x
	static float linearEquationWithOneUnknown_solveXRequiredY(CCPoint knownPoint1, CCPoint knownPoint2, float y)
	{
		float _x1 = knownPoint1.x;
		float _y1 = knownPoint1.y;
		float _x2 = knownPoint2.x;
		float _y2 = knownPoint2.y;
		float m_p1 = (_y1 -_y2)/(_x1-_x2);
		float m_p2 = _y1 - m_p1 * _x1;
		//         float m_p1 = (knownPoint1.y -knownPoint2.y)/(knownPoint1.x-knownPoint2.x);
		//         float m_p2 = knownPoint1.y - m_p1 * knownPoint1.x;

		return (y - m_p2)/m_p1;
	}

	//求点到直线最短路径长度
	static float linearEquationWithOneUnknown_solveShortLenghtRequiredPoint(CCPoint knownPoint1, CCPoint knownPoint2, CCPoint point)
	{
		if ((point.x == knownPoint1.x && point.y == knownPoint1.y) || (point.x == knownPoint2.x && point.y == knownPoint2.y))
		{
			return 0;
		}

		float _x1 = knownPoint1.x;
		float _y1 = knownPoint1.y;
		float _x2 = knownPoint2.x;
		float _y2 = knownPoint2.y;
		float m_p1 = (_y1 -_y2)/(_x1-_x2);
		float m_p2 = _y1 - m_p1 * _x1;

		CCPoint p1((point.y - m_p2)/m_p1, point.y);
		CCPoint p2(point.x, m_p1* point.x + m_p2);
		float offsetY = abs( p2.y - point.y);
		float offsetX = abs(p1.x - point.x);

		if (offsetX == 0 && offsetY == 0)
		{
			return 0;
		}


		return offsetX * offsetY / calculateLengthRequiredTwoPoint(p1, p2);
	}

	//计算2点距离
	static float calculateLengthRequiredTwoPoint(CCPoint p1, CCPoint p2)
	{
		float _offsetX = abs( p1.x - p2.x);
		float _offsetY =abs(  p1.y - p2.y);
		return sqrt(_offsetX * _offsetX + _offsetY * _offsetY);
	}

	//绝对值
	static float abs(float value)
	{
		return value>0?value:-value;
	}
};
#endif /* defined(__MapGame__MathLogic__) */

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "PathSearchInfo.h"
#include "Player.h"
class Paddle;
class HelloWorld : public cocos2d::CCLayer
{
public:
	// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
	virtual bool init();  

	// there's no 'id' in cpp, so we recommend returning the class instance pointer
	static cocos2d::CCScene* scene();

	// a selector callback
	void menuCloseCallback(CCObject* pSender);

	// implement the "static node()" method manually
	CREATE_FUNC(HelloWorld);
	void onEnter();
	virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
	virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
	virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);

	void drawPath(vector<PathSprite*>& vec);//绘制路径(测试用)

	void update(float dt);//跟新大地图(行走时, 人不动, 地图跟着人动);

	void selectObjCallback(CCPoint point, Paddle* selectObj);//选择物体回调

	void moveDone(CCPoint point);//移动结束回调

public:
	PathSearchInfo* m_pathSearch;//寻路引擎类

	CCPoint m_orignPoint;//人物的起始点

	Player* m_player;//人物

	Paddle* m_currentSelect;//当前选中的物品
};
#endif // __HELLOWORLD_SCENE_H__

#include "HelloWorldScene.h"
#include "Paddle.h"
#include "MathLogic.h"
#include <functional>
USING_NS_CC;


CCScene* HelloWorld::scene()
{
	// 'scene' is an autorelease object
	CCScene *scene = CCScene::create();

	// 'layer' is an autorelease object
	HelloWorld *layer = HelloWorld::create();

	// add layer as a child to scene
	scene->addChild(layer);

	// return the scene
	return scene;
}

// on "init" you need to initialize your instance
void HelloWorld::onEnter()
{
	CCDirector* pDirector = CCDirector::sharedDirector();
	pDirector->getTouchDispatcher()->addTargetedDelegate(this, -1, false);
	CCLayer::onEnter();

}

bool HelloWorld::init()
{
	//////////////////////////////
	// 1. super init first
	if ( !CCLayer::init() )
	{
		return false;
	}
	
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
	CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

	CCTMXTiledMap* _map = CCTMXTiledMap::create("gameMap.tmx");
	_map->setPosition(CCPoint());
	this->addChild(_map);

	m_pathSearch = new PathSearchInfo(_map);

	std::function<void (CCPoint point)> _fun = std::bind(&HelloWorld::moveDone,this,std::placeholders::_1);
	m_pathSearch->setMoveDoneCallback(_fun);

	std::function<void (vector<PathSprite*>)> _funDrawPath = std::bind(&HelloWorld::drawPath,this,std::placeholders::_1);
	m_pathSearch->setDrawPathCallback(_funDrawPath);

	std::function<void(CCPoint point, Paddle* selectObj)> _funcSelect = std::bind(&HelloWorld::selectObjCallback,this,std::placeholders::_1,std::placeholders::_2);  
	m_pathSearch->setSelectCallback(_funcSelect);
	/////////////////////////////
	 
	CCMenuItemSprite* _menuItemSprite = CCMenuItemSprite::create(CCSprite::create("CloseNormal.png"),CCSprite::create("CloseSelected.png"),NULL,this,SEL_MenuHandler(&HelloWorld::menuCloseCallback));
	CCMenu* _menu = CCMenu::create(_menuItemSprite,NULL);
	this->addChild(_menu, 1000);

	m_currentSelect = NULL;

	//m_isMoving = false;
	CCLabelTTF* pLabel = CCLabelTTF::create("A* + tiledMap", "Arial", 24);

	// position the label on the center of the screen
	pLabel->setPosition(ccp(origin.x + visibleSize.width/2, origin.y + visibleSize.height - pLabel->getContentSize().height));

	// add the label as a child to this layer
	this->addChild(pLabel, 1);

	this->scheduleUpdate();

	//设置起始和终点
	m_orignPoint = CCDirector::sharedDirector()->getWinSize()/2 ;//+ CCSize(0, 100);
	
	//创建一个人物
	CCSprite* _sp = CCSprite::create();
	_sp->setScale(0.08);

	m_player = new Player(_sp);
	m_player->m_sprite->setOpacity(100);
	m_pathSearch->getMap()->addChild(m_player->m_sprite, BASE_ZODER);
	m_player->m_sprite->setPosition(m_orignPoint);//设置人物的起始的世界坐标
	m_player->m_startX =m_pathSearch->getMapPositionByWorldPosition(m_orignPoint).x;
	m_player->m_startY =m_pathSearch->getMapPositionByWorldPosition(m_orignPoint).y;
	m_player->m_x = m_player->m_startX;
	m_player->m_y = m_player->m_startY;

	m_pathSearch->initMapObject("desk", "desk");
	m_pathSearch->initMapObject("chairLeft", "chairLeft");
	m_pathSearch->initMapObject("chairFront", "chairFront");
	m_pathSearch->initMapObject("chairBack", "chairBack");
	m_pathSearch->initMapObject("zhuzi", "zhuzi");
	m_pathSearch->initMapObject("goods", "goods");
	return true;
}

void HelloWorld::drawPath( vector<PathSprite*>& vec )
{
	for (vector<PathSprite*>::iterator iter = vec.begin(); iter !=  vec.end(); iter++)
	{
		(*iter)->m_sprite->setColor(ccGREEN);
	}
}

CCRect getBoundingBox(float x, float y, float width, float height)
{
	return CCRect(x - width/2, y - height/2, width, height);
}

bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
	if (m_pathSearch->getEnableMove())
	{
		m_currentSelect = NULL;
		auto nodePosition = convertToNodeSpace( touch->getLocation() );
		m_pathSearch ->pathFunction(m_pathSearch->getMapPositionByWorldPosition(nodePosition),m_player);
	}
	return true;
}

void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{

}

void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{

}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
	if (!m_pathSearch->getEnableMove())
	{
		m_pathSearch->setEnableMove(true);
		m_currentSelect->standUp();
		m_player->m_sprite->setVisible(true);
	}
}
void HelloWorld::update(float dt)
{
	//移动层
	this->setPosition(m_orignPoint - m_player->m_sprite->getPosition());

	if(m_pathSearch->getIsMoving())
	{
		m_player->walking();
	}
	else
	{
		m_player->stand();
	}
}

void HelloWorld::selectObjCallback( CCPoint point, Paddle* selectObj )
{
	//如果不能移动物体的话, 不能点击其他物体
	if (m_pathSearch->getEnableMove())
	{
		m_currentSelect = selectObj;

		m_pathSearch ->pathFunction( point ,m_player);
	}
}

void HelloWorld::moveDone(CCPoint point)
{
	//判断是有选择的物体
	if (m_currentSelect)
	{
		//判断是否能坐下
		if (m_currentSelect->m_enableSit/* && point.x == m_currentSelect->m_terminal.x&& point.y ==  m_currentSelect->m_terminal.y*/)
		{
			m_currentSelect->sitChair();
			m_pathSearch->setEnableMove(false);
			m_player->m_sprite->setVisible(false);
		}
		//判断是否能捡起
		if (m_currentSelect->m_enablePickUp)
		{
			m_currentSelect->m_enablePickUp = false;
			m_currentSelect->runAction(CCSequence::create(CCFadeOut::create(0.5), CCRemoveSelf::create(true), NULL));
			m_currentSelect = NULL;
		}
	}
}






static char* g_chair_left_player = "player_1/chair_left_player.png";
static char* g_chair_back_player = "player_1/chair_back_player.png";
static char* g_chair_left_part = "player_1/chair_left_part.png";

#define MAP_WIDTH 600//要比tmx中的map大1
#define MAP_HEIGHT 600
#define BASE_ZODER 100000
#define MOVE_SPEED 1/200.0

#define PRECISE_SEARCH_PATH//精确的寻 路系统, 需要消耗额外的运算(魔兽争霸级的!)



你可能感兴趣的:(cocos2dx A* + tiledMap(改良升级))