cocos2dx A* + tiledMap(改良升级)
此次在之前那篇cocos2dx A* tiledMap文章中新加了些功能并且调整了结构 拥有的功能: 能避开障碍物,搜寻最优路径 优化了行走的路径,使之平滑行走(之前的是瓦片级的, 现在是像素级的, #define PRECISE_SEARCH_PATH 开启精确的路径行走) 添加了人物根据位置会被
此次在之前那篇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> m_moveDone;//移动结束回调 bool m_isSetMoveDoneCallback; std::function<void>)> m_drawPath;//画线回调 调试用 bool m_isSetDrawPathCallback; std::function<void 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>& pFunc);//设置回调 void setDrawPathCallback(function<void>)>& pFunc);//设置回调 void setSelectCallback(function<void 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();//移动实现函数 }; </void></void></void></pathsprite></pathsprite></pathsprite></void></void></void></functional>
#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 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>& pFunc ) { m_moveDone = pFunc; m_isSetMoveDoneCallback = true; } void PathSearchInfo::setDrawPathCallback( function<void>)>& pFunc ) { m_drawPath = pFunc; m_isSetDrawPathCallback = true; } void PathSearchInfo::setSelectCallback( function<void 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 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 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 m_FValue) { _sp = *iter; } } return _sp; } else { return NULL; } } PathSprite* PathSearchInfo::getObjFromInspectArray( int x, int y ) { if (x >=0 && y >=0 && x ::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 float _miny="p1.y<p2.y?p1.y:p2.y;" if p2.x>1) { return false; } float _x = p1.x; for (int _y = _minY; _y 1) { return false; } float _y = p1.y; for (int _x = _minX; _x 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_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 } </pathsprite></p2.x></pathsprite></pathsprite></void></void></void>
#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 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</void></functional>
#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__) */ </stdio.h>
#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__</pathsprite>
#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 point> _fun = std::bind(&HelloWorld::moveDone,this,std::placeholders::_1); m_pathSearch->setMoveDoneCallback(_fun); std::function<void>)> _funDrawPath = std::bind(&HelloWorld::drawPath,this,std::placeholders::_1); m_pathSearch->setDrawPathCallback(_funDrawPath); std::function<void 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; } } } </pathsprite></pathsprite></void></void></void></functional>
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//精确的寻 路系统, 需要消耗额外的运算(魔兽争霸级的!)

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Beberapa kaedah untuk Conda meningkatkan versi Python memerlukan contoh kod khusus: Conda ialah pengurus pakej sumber terbuka dan sistem pengurusan persekitaran untuk menguruskan pakej dan persekitaran Python. Semasa pembangunan menggunakan Python, untuk menggunakan versi baharu Python, kita mungkin perlu menaik taraf daripada versi Python yang lebih lama. Artikel ini akan memperkenalkan beberapa kaedah menggunakan Conda untuk menaik taraf versi Python dan memberikan contoh kod khusus. Kaedah 1: Gunakan arahan condainstall

Cara menaik taraf versi numpy: Tutorial yang mudah diikuti, memerlukan contoh kod konkrit Pengenalan: NumPy ialah perpustakaan Python penting yang digunakan untuk pengkomputeran saintifik. Ia menyediakan objek tatasusunan berbilang dimensi yang berkuasa dan satu siri fungsi berkaitan yang boleh digunakan untuk melaksanakan operasi berangka yang cekap. Apabila versi baharu dikeluarkan, ciri yang lebih baharu dan pembetulan pepijat sentiasa tersedia kepada kami. Artikel ini akan menerangkan cara untuk menaik taraf pustaka NumPy anda yang dipasang untuk mendapatkan ciri terkini dan menyelesaikan isu yang diketahui. Langkah 1: Semak versi NumPy semasa pada permulaan

1. Gunakan kekunci pintasan win+x untuk membuka menu dan pilih [Command Prompt (Administrator) (A)], seperti yang ditunjukkan di bawah: 2. Selepas memasuki antara muka command prompt, masukkan arahan [ipconfig/flushdns] dan tekan Enter , seperti yang ditunjukkan dalam rajah di bawah: 3. Kemudian masukkan arahan [netshwinsockresetcatalog] dan tekan Enter, seperti yang ditunjukkan dalam rajah di bawah: 4. Akhir sekali masukkan arahan [netshintipreset] dan tekan Enter, mulakan semula komputer dan anda boleh mengakses Internet , seperti yang ditunjukkan dalam rajah di bawah:

Dalam bidang teknologi baharu, sistem pengendalian baharu sentiasa menarik perhatian ramai. Baru-baru ini, telefon bimbit Honor mengumumkan bahawa mereka akan dinaik taraf kepada Hongmeng OS, sistem pengendalian baharu yang dibangunkan oleh Huawei. Ini sudah pasti berita baik untuk ramai pengguna telefon bimbit Honor. Walau bagaimanapun, ramai pengguna mungkin masih mempunyai keraguan tentang cara untuk menaik taraf kepada sistem Hongmeng. Artikel ini akan menerangkan secara terperinci cara menaik taraf telefon mudah alih Honor kepada sistem Hongmeng untuk membantu pengguna memahami dan mengendalikannya dengan lebih baik. Pertama, untuk menaik taraf telefon Honor kepada sistem Hongmeng, pengguna perlu memastikan telefon disambungkan ke rangkaian dan mempunyai kuasa yang mencukupi. ini

WPS ialah perisian komputer yang mesti ada untuk ramai pengguna Kemas kini biasa kepada versi baharu boleh membolehkan pengguna mendapatkan pengalaman pengguna yang lebih baik dan lebih banyak ciri. Jadi bagaimana untuk menaik taraf versi wps? Terdapat tiga kaedah utama untuk menaik taraf wpsoffice Mari kita lihat di bawah. Kaedah 1: Muat turun versi baharu daripada tapak web rasmi Anda boleh memuat turun versi terkini pakej pemasangan daripada tapak web rasmi WPSOffice. Selepas memasuki tapak web rasmi WPSOffice (https://www.wps.cn/), klik butang "Muat turun", pilih versi yang anda perlu muat turun, dan kemudian ikut arahan untuk memasangnya. Nota: Apabila memasang versi baharu, anda perlu menyahpasang versi lama, jika tidak, ia akan menyebabkan konflik perisian dan menghalang penggunaan biasa. Kaedah 2: Dalam WPSOf

Pada 21 Jun, Persidangan Pembangun Huawei 2024 (HDC2024) berkumpul semula di Tasik Songshan, Dongguan. Pada persidangan ini, perkara yang paling menarik perhatian ialah HarmonyOSNEXT secara rasminya melancarkan Beta untuk pembangun dan pengguna perintis, dan secara komprehensif menunjukkan tiga ciri inovatif HarmonyOSNEXT yang "menghancurkan raja" dalam semua senario, perisikan asli dan keselamatan asli. Perisikan asli HarmonyOSNEXT: Membuka era AI baharu Selepas meninggalkan rangka kerja Android, HarmonyOSNEXT telah menjadi sistem pengendalian yang benar-benar bebas daripada Android dan iOS, yang boleh dipanggil kelahiran semula yang tidak pernah berlaku sebelum ini. Di antara banyak ciri baharunya, kecerdasan asli tidak diragukan lagi merupakan ciri baharu yang terbaik boleh membawa perasaan intuitif pengguna dan mengalami peningkatan.

Mi 14 Pro ialah telefon terbaharu Xiaomi, dan ThePaper OS ialah sistem pengendalian baharu yang dibangunkan secara bebas oleh Xiaomi, khusus untuk menyediakan pengalaman pengguna yang lebih lancar dan bijak. Dengan perkembangan teknologi yang berterusan, ThePaper OS juga sentiasa dikemas kini dan dinaik taraf. Begitu ramai pengguna yang menggunakan telefon bimbit Xiaomi buat kali pertama bertanya kepada pengguna Xiaomi 14Pro bagaimana untuk menaik taraf OS ThePaper? Bagaimana untuk menaik taraf Xiaomi Mi 14 Pro kepada Thermal OS? Cara mengemas kini model lain yang menyokong ThePaper OS: 1. Buka aplikasi tetapan telefon anda dan cari pilihan kemas kini sistem. 2. Sistem akan secara automatik mengesan versi sistem semasa dan menggesa apabila versi baharu tersedia untuk dikemas kini. 3. Hanya klik "Kemas Kini Sekarang" dan sistem akan mula memuat turun secara automatik.

Ramai rakan menyatakan bahawa mereka ingin tahu bagaimana untuk menaik taraf ke akaun profesional di Xiaohongshu Di sini saya akan memperkenalkan kaedah operasi Jika anda berminat, datang dan lihat dengan saya. Buka APP "Buku Merah Kecil" pada telefon bimbit anda, klik pilihan "Saya" di sudut kanan bawah selepas memasukkannya, kemudian cari ikon "tiga garisan mendatar" di sudut kiri atas halaman Saya dan klik untuk membuka ia. 2. Halaman menu akan muncul, di mana klik untuk memilih item "Pusat Penciptaan" untuk masuk. 3. Seterusnya, cari "Lagi Perkhidmatan" dalam pilihan di bawah "Perkhidmatan Penciptaan" pada halaman yang anda masukkan, dan klik padanya untuk masuk. 4. Selepas halaman melompat, klik "Buka Akaun Profesional" dalam pilihan di bawah "Keupayaan Pengarang". 5. Akhir sekali, Akaun Xiaohongshu Professional akan diperkenalkan pada halaman yang dimasukkan Klik ".
