cocos2dx A* + tiledMap
前面一章讲了cocos2dx 中使用A星算法 这章中讲 A*结合tiledmap 先看下效果图 图有点丑,忍受下 绿色的块 表示人物的行走的路线(A*算法的结果) 红色部分 表示A*算法搜寻过的点(越少,速度越快) 黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物 这张图是
前面一章讲了cocos2dx 中使用A星算法
这章中讲 A*结合tiledmap
先看下效果图
图有点丑,忍受下
绿色的块 表示人物的行走的路线(A*算法的结果)
红色部分 表示A*算法搜寻过的点(越少,速度越快)
黑色的部分(其实是无色块,因为背景是黑色的) 表示障碍物
这张图是用tiledmap做出来的, 看看里面的内容
可以看到 我把不能通过的地区的图块给删了
tiledmap中有2个层 一个是background, 一个是road. 为了方便, 我把road也用同样的图片, 最好的方法是用一种同样的瓦片拼接出来一条能走的路, 让后把background图层加到road图层上就ok了.
下面直接上源码, 用的时cocos2.2.3, 拷贝到项目中就能用了.当然别忘了自己做个像样的tiledMap .
如果你觉得好用, 就在文章底下顶一个吧 , enjoy it !
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include "vector" using namespace std; USING_NS_CC; #define MAP_WIDTH 200//要比tmx中的map大 #define MAP_HEIGHT 200 class PathSprite { public: PathSprite(CCSprite* sprite) { m_parent = NULL; m_child = NULL; m_costToSource = 0; m_FValue = 0; m_sprite = sprite; }; public: CCSprite* m_sprite;//包含的瓦片精灵 PathSprite* m_parent;//父节点 PathSprite* m_child;//子节点 float m_costToSource;//到起始点的距离 int m_x;//地图坐标 int m_y; float m_FValue; }; class PathSearchInfo//寻路类(主要负责寻路的参数和逻辑) { public: static int m_startX;//开始点 static int m_startY; static int m_endX;//结束点 static int m_endY; static CCSize m_mapSize;//地图大小 static CCSize m_tileSize;//地图的块大小 static vector<pathsprite> m_openList;//开放列表(里面存放相邻节点) static PathSprite* m_inspectArray[MAP_WIDTH][MAP_HEIGHT];//全部需要检测的点 static vector<pathsprite> m_pathList;//路径列表 static vector<pathsprite> m_haveInspectList;//检测过的列表 static float calculateTwoObjDistance(PathSprite* obj1, PathSprite* obj2)//计算两个物体间的距离 { // float _offsetX = obj1->m_x - obj2->m_x; // float _offsetY = obj1->m_y - obj2->m_y; // return sqrt( _offsetX * _offsetX + _offsetY * _offsetY); float _x = abs(obj2->m_x - obj1->m_x); float _y = abs(obj2->m_y - obj1->m_y); return _x + _y; } static void 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 + H2; #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);//加入开放列表 } } static PathSprite* getMinPathFormOpenList()//从开放节点中获取F值最小值的点 { 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; } } static PathSprite* 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; } }; 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 calculatePath();//计算路径 void drawPath();//绘制路径(测试用) void clearPath();//清理路径 void playerMove();//人物走动 void update(float dt);//跟新大地图(行走时, 人不动, 地图跟着人动); public: CCPoint m_orignPoint;//人物的起始点 PathSprite* m_player;//人物点 int m_playerMoveStep;//人物当前的行程的索引 }; #endif // __HELLOWORLD_SCENE_H__ </pathsprite></pathsprite></pathsprite></pathsprite>
#include "HelloWorldScene.h" USING_NS_CC; vector<pathsprite> PathSearchInfo::m_openList; PathSprite* PathSearchInfo::m_inspectArray[MAP_WIDTH][MAP_HEIGHT] = {NULL}; vector<pathsprite> PathSearchInfo::m_pathList; vector<pathsprite> PathSearchInfo::m_haveInspectList; CCSize PathSearchInfo::m_mapSize; CCSize PathSearchInfo::m_tileSize; int PathSearchInfo::m_startX; int PathSearchInfo::m_startY; int PathSearchInfo::m_endX; int PathSearchInfo::m_endY; 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, 0, true); CCLayer::onEnter(); } bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); ///////////////////////////// // 2. add a menu item with "X" image, which is clicked to quit the program // you may modify it. 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(); CCTMXTiledMap* map = CCTMXTiledMap::create("gameMap.tmx"); this->addChild(map); map->setPosition(CCPoint()); CCTMXLayer* _road = map->layerNamed("road");//行走路径的地图 CCSize _mapSize = map->getMapSize(); for (int j = 0; j tileAt(CCPoint(i, j)); if (_sp) { PathSprite* _pathSprite = new PathSprite(_sp); _pathSprite->m_x = i; _pathSprite->m_y = j; PathSearchInfo::m_inspectArray[i][j] = _pathSprite;//把地图中所有的点一一对应放入检测列表中 } } } PathSearchInfo::m_mapSize = _mapSize;//获取地图的尺寸 PathSearchInfo::m_tileSize = map->getTileSize();//获取瓦片的尺寸 //设置起始和终点 PathSearchInfo::m_startX =30; PathSearchInfo::m_startY = 75; //创建一个人物 m_player = new PathSprite(CCSprite::create("10001.png")); m_player->m_sprite->setAnchorPoint(CCPoint(0.5,0)); this->addChild(m_player->m_sprite); m_player->m_x = PathSearchInfo::m_startX;//设置人物的起始的地图坐标 m_player->m_y = PathSearchInfo::m_startY; m_orignPoint = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY]->m_sprite->getPosition(); m_player->m_sprite->setPosition(m_orignPoint);//设置人物的起始的世界坐标 return true; } void HelloWorld::calculatePath() { //得到开始点的节点 PathSprite* _startNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY]; //得到结束点的节点 PathSprite* _endNode = PathSearchInfo::m_inspectArray[PathSearchInfo::m_endX][PathSearchInfo::m_endY]; //因为是开始点 把到起始点的距离设为0, F值也为0 _startNode->m_costToSource = 0; _startNode->m_FValue = 0; //把已经检测过的点从检测列表中删除 PathSearchInfo::m_inspectArray[PathSearchInfo::m_startX][PathSearchInfo::m_startY] = NULL; //把该点放入已经检测过点的列表中 PathSearchInfo::m_haveInspectList.push_back(_startNode); //然后加入开放列表 PathSearchInfo::m_openList.push_back(_startNode); PathSprite* _node = NULL; while (true) { //得到离起始点最近的点(如果是第一次执行, 得到的是起点) _node = PathSearchInfo::getMinPathFormOpenList(); if (!_node) { //找不到路径 break; } //把计算过的点从开放列表中删除 PathSearchInfo::removeObjFromOpenList( _node); int _x = _node->m_x; int _y = _node->m_y; // if (_x ==PathSearchInfo::m_endX && _y == PathSearchInfo::m_endY) { break; } //检测8个方向的相邻节点是否可以放入开放列表中 CCLog("%d, %d",_x, _y); PathSprite* _adjacent = PathSearchInfo::getObjFromInspectArray( _x + 1, _y + 1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x +1, _y); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x +1, _y-1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x , _y -1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y - 1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x -1, _y+1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); _adjacent = PathSearchInfo::getObjFromInspectArray( _x , _y+1); PathSearchInfo::inspectTheAdjacentNodes(_node, _adjacent, _endNode); } while (_node) { //把路径点加入到路径列表中 PathSearchInfo::m_pathList.insert(PathSearchInfo::m_pathList.begin(), _node); _node = _node->m_parent; } } void HelloWorld::drawPath( ) { for (vector<pathsprite>::iterator iter = PathSearchInfo::m_pathList.begin(); iter != PathSearchInfo::m_pathList.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) { //清除之前的路径 clearPath(); auto nodePosition = convertToNodeSpace( touch->getLocation() ); CCLog("%f, %f", nodePosition.x, nodePosition.y); // for (int i = 0; i m_sprite->getPositionX(), _sp->m_sprite->getPositionY(), _sp->m_sprite->getContentSize().width, _sp->m_sprite->getContentSize().height); // // if (_rect.containsPoint(nodePosition)) // { PathSprite* _sp = PathSearchInfo::m_inspectArray[(int)(nodePosition.x/PathSearchInfo::m_tileSize.width)][(int)(PathSearchInfo::m_mapSize.height - nodePosition.y/PathSearchInfo::m_tileSize.height)]; if (_sp) { CCLog("%f, %f", _sp->m_sprite->getPositionX(), _sp->m_sprite->getPositionY()); //获取触摸点, 设置为终点 PathSearchInfo::m_endX = _sp->m_x; PathSearchInfo::m_endY = _sp->m_y; //计算路径 calculatePath(); //绘制路径 drawPath( ); //移动物体 playerMove(); } // } // // } return true; } void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event) { } void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event) { } void HelloWorld::menuCloseCallback(CCObject* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); #else CCDirector::sharedDirector()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif #endif } void HelloWorld::clearPath() { for (vector<pathsprite>::iterator iter = PathSearchInfo::m_haveInspectList.begin(); iter != PathSearchInfo::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; PathSearchInfo::m_inspectArray[(*iter)->m_x][(*iter)->m_y] = (*iter); } //把移除了障碍物的地图放入检测列表中 //PathSearchInfo::m_inspectList = PathSearchInfo::m_mapList; PathSearchInfo::m_openList.clear(); PathSearchInfo::m_pathList.clear(); PathSearchInfo::m_haveInspectList.clear(); PathSearchInfo::m_startX = m_player->m_x; PathSearchInfo::m_startY = m_player->m_y; m_player->m_sprite->stopAllActions(); m_playerMoveStep = 0; } void HelloWorld::playerMove() { m_playerMoveStep++; if (m_playerMoveStep >= PathSearchInfo::m_pathList.size()) { return; } m_player->m_x = PathSearchInfo::m_pathList[m_playerMoveStep]->m_x; m_player->m_y = PathSearchInfo::m_pathList[m_playerMoveStep]->m_y; //根据路径列表移动人物 m_player->m_sprite->runAction(CCSequence::create(CCMoveTo::create(1/24.0, PathSearchInfo::m_pathList[m_playerMoveStep]->m_sprite->getPosition()), CCCallFunc::create(this, SEL_CallFunc(&HelloWorld::playerMove)) , NULL)); } void HelloWorld::update(float dt) { this->setPosition(m_orignPoint - m_player->m_sprite->getPosition()); } </pathsprite></pathsprite></pathsprite></pathsprite></pathsprite>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

全表掃描在MySQL中可能比使用索引更快,具體情況包括:1)數據量較小時;2)查詢返回大量數據時;3)索引列不具備高選擇性時;4)複雜查詢時。通過分析查詢計劃、優化索引、避免過度索引和定期維護表,可以在實際應用中做出最優選擇。

InnoDB的全文搜索功能非常强大,能够显著提高数据库查询效率和处理大量文本数据的能力。1)InnoDB通过倒排索引实现全文搜索,支持基本和高级搜索查询。2)使用MATCH和AGAINST关键字进行搜索,支持布尔模式和短语搜索。3)优化方法包括使用分词技术、定期重建索引和调整缓存大小,以提升性能和准确性。

是的,可以在 Windows 7 上安裝 MySQL,雖然微軟已停止支持 Windows 7,但 MySQL 仍兼容它。不過,安裝過程中需要注意以下幾點:下載適用於 Windows 的 MySQL 安裝程序。選擇合適的 MySQL 版本(社區版或企業版)。安裝過程中選擇適當的安裝目錄和字符集。設置 root 用戶密碼,並妥善保管。連接數據庫進行測試。注意 Windows 7 上的兼容性問題和安全性問題,建議升級到受支持的操作系統。

聚集索引和非聚集索引的區別在於:1.聚集索引將數據行存儲在索引結構中,適合按主鍵查詢和範圍查詢。 2.非聚集索引存儲索引鍵值和數據行的指針,適用於非主鍵列查詢。

MySQL是一個開源的關係型數據庫管理系統。 1)創建數據庫和表:使用CREATEDATABASE和CREATETABLE命令。 2)基本操作:INSERT、UPDATE、DELETE和SELECT。 3)高級操作:JOIN、子查詢和事務處理。 4)調試技巧:檢查語法、數據類型和權限。 5)優化建議:使用索引、避免SELECT*和使用事務。

MySQL支持四種索引類型:B-Tree、Hash、Full-text和Spatial。 1.B-Tree索引適用於等值查找、範圍查詢和排序。 2.Hash索引適用於等值查找,但不支持範圍查詢和排序。 3.Full-text索引用於全文搜索,適合處理大量文本數據。 4.Spatial索引用於地理空間數據查詢,適用於GIS應用。

MySQL 數據庫中,用戶和數據庫的關係通過權限和表定義。用戶擁有用戶名和密碼,用於訪問數據庫。權限通過 GRANT 命令授予,而表由 CREATE TABLE 命令創建。要建立用戶和數據庫之間的關係,需創建數據庫、創建用戶,然後授予權限。

MySQL 和 MariaDB 可以共存,但需要謹慎配置。關鍵在於為每個數據庫分配不同的端口號和數據目錄,並調整內存分配和緩存大小等參數。連接池、應用程序配置和版本差異也需要考慮,需要仔細測試和規劃以避免陷阱。在資源有限的情況下,同時運行兩個數據庫可能會導致性能問題。
