此次在之前那篇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//精确的寻 路系统, 需要消耗额外的运算(魔兽争霸级的!)