此次在之前那篇cocos2dx A* + tiledMap文章中新加了些功能并且调整了结构
拥有的功能:
能避开障碍物,搜寻最优路径
优化了行走的路径,使之平滑行走(之前的是瓦片级的, 现在是像素级的, #define PRECISE_SEARCH_PATH 开启精确的路径行走)
添加了人物根据位置会被物体遮住或遮住物体的功能
添加了点击路面, 到达该点. 点击物体, 可以到达该物体的功能
添加了捡拾物体功能
添加了坐椅子功能
添加了人物的骨骼动画(行走和站立)
PathSearchInfo 搜索路径引擎
Player 玩家类
PathSprite 瓦片精灵类
Paddle物体类(桌子,椅子等)
MathLogic 数学逻辑类
#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//精确的寻 路系统, 需要消耗额外的运算(魔兽争霸级的!)