首页 数据库 mysql教程 cocos2dx A* + tiledMap(改良升级)

cocos2dx A* + tiledMap(改良升级)

Jun 07, 2016 pm 03:43 PM
升级

此次在之前那篇cocos2dx A* tiledMap文章中新加了些功能并且调整了结构 拥有的功能: 能避开障碍物,搜寻最优路径 优化了行走的路径,使之平滑行走(之前的是瓦片级的, 现在是像素级的, #define PRECISE_SEARCH_PATH 开启精确的路径行走) 添加了人物根据位置会被

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

拥有的功能:

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

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

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

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

添加了捡拾物体功能

添加了坐椅子功能

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

PathSearchInfo 搜索路径引擎

Player 玩家类

PathSprite 瓦片精灵类

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

MathLogic 数学逻辑类

cocos2dx A* + tiledMap(改良升级)


#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>)&gt; 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>&amp; pFunc);//设置回调

	void setDrawPathCallback(function<void>)&gt;&amp; pFunc);//设置回调
	
	void setSelectCallback(function<void point paddle selectobj> &amp;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-&gt;getMapSize();//获取地图的尺寸 地图单位
	m_tileSize = m_map-&gt;getTileSize();//获取瓦片的尺寸  世界单位
	m_road = m_map-&gt;layerNamed("road");//行走路径的地图

	for (int j = 0;  j tileAt(CCPoint(i, j));
			if (_sp) {
				PathSprite* _pathSprite = new PathSprite(_sp);
				_pathSprite-&gt;m_x = i;
				_pathSprite-&gt;m_y = j;

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

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

void PathSearchInfo::setDrawPathCallback( function<void>)&gt;&amp; pFunc )
{
	m_drawPath = pFunc;
	m_isSetDrawPathCallback = true;
}

void PathSearchInfo::setSelectCallback( function<void point paddle selectobj> &amp;pFunc )
{
	m_selectObj = pFunc;
	m_isSetSelectObjCallback = true;
}

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

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

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

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

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

		}
		else
		{
			_parent-&gt;m_terminal = CCPoint(-1, -1);
		}
		_parent-&gt;m_type = _type?  (OBJTYPE)_type-&gt;intValue():NONE_TYPE;
		_parent-&gt;m_enableSit = _enableSit? _enableSit-&gt;boolValue():false;
		_parent-&gt;m_enableTouch = _enableTouch?_enableTouch-&gt;boolValue():false;
		if (_enablePickUp)
		{
			_parent-&gt;m_enablePickUp = _enablePickUp-&gt;boolValue();
			_parent-&gt;m_selectCallback =m_selectObj;
		}
		else
		{
			_parent-&gt;m_enablePickUp =false;
		}
		//设置物体位置
		CCPoint _offset = CCPoint(_x, _y  );//偏移量
		_parent-&gt;setPosition(_offset);
		_parent-&gt;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-&gt;retain();
					_Sprite-&gt;removeFromParent();
					_Sprite-&gt;setPosition(_Sprite-&gt;getPosition()-_offset);
					_parent-&gt;addChild(_Sprite);
					_Sprite-&gt;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-&gt;runAction(CCRepeatForever::create(seq));
#endif

				}

			}
		}

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

	}
} 

void PathSearchInfo::pathFunction( CCPoint point, PathSprite* obj )
{
	if (!m_enableMove)
	{
		return;
	}
	if (point.x m_endX = _sp-&gt;m_x;
		obj-&gt;m_endY = _sp-&gt;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-&gt;m_startX][m_moveObj-&gt;m_startY];
	//得到结束点的节点
	PathSprite*   _startNode = m_inspectArray[m_moveObj-&gt;m_endX][m_moveObj-&gt;m_endY];

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

	//把已经检测过的点从检测列表中删除
	m_inspectArray[m_moveObj-&gt;m_endX][m_moveObj-&gt;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-&gt;m_x;
		int _y = _node-&gt;m_y;

		//
		if (_x ==m_moveObj-&gt;m_startX &amp;&amp; _y == m_moveObj-&gt;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-&gt;m_parent;
	}
#else

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

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

	//把已经检测过的点从检测列表中删除
	m_inspectArray[m_moveObj-&gt;m_startX][m_moveObj-&gt;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-&gt;m_x;
		int _y = _node-&gt;m_y;

		//
		if (_x ==m_moveObj-&gt;m_endX &amp;&amp; _y == m_moveObj-&gt;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-&gt;m_parent;
	}
#endif // PRECISE_SEARCH_PATH


}

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

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

	return _x + _y;
}

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

		float F , G, H1, H2, H3;
		adjacent-&gt;m_costToSource = node-&gt;m_costToSource + calculateTwoObjDistance(node, adjacent);//获得累计的路程
		G = adjacent-&gt;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-&gt;m_FValue = F;

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

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

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

}

PathSprite* PathSearchInfo::getObjFromInspectArray( int x, int y )
{
	if (x &gt;=0 &amp;&amp; y &gt;=0 &amp;&amp; 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)-&gt;m_sprite-&gt;setColor(ccWHITE);
		(*iter)-&gt;m_costToSource = 0;
		(*iter)-&gt;m_FValue = 0;
		(*iter)-&gt;m_parent = NULL;
		(*iter)-&gt;m_child = NULL;

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

bool PathSearchInfo::detectWhetherCanPassBetweenTwoPoints( CCPoint p1, CCPoint p2 )
{ 
	float _maxX = p1.x&gt;p2.x?p1.x:p2.x;
	float _maxY = p1.y&gt;p2.y?p1.y:p2.y;
	float _minX = p1.x<p2.x float _miny="p1.y&lt;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-&gt;getPosition());
	CCSprite* _sp = m_road-&gt;tileAt(_point);

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

	}
#endif // PRECISE
}

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

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

	m_playerMoveStep = 0;
}



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

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

	//根据路径列表移动人物
	CCPoint _terminalPosition =  m_pathList[m_playerMoveStep]-&gt;m_sprite-&gt;getPosition()+m_tileSize/2;
	float _length =  MathLogic::calculateLengthRequiredTwoPoint(_terminalPosition,m_moveObj-&gt;m_sprite-&gt;getPosition());
	m_moveObj-&gt;m_sprite-&gt;runAction(CCSequence::create(CCMoveTo::create(MOVE_SPEED * _length,_terminalPosition), CCCallFunc::create(this, SEL_CallFunc(&amp;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))-&gt;m_x, (*(m_pathList.end()-1))-&gt;m_y));
		}
		return ;
	}

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

			m_moveObj-&gt;m_sprite-&gt;setZOrder(BASE_ZODER - m_pathList[m_playerMoveStep]-&gt;m_sprite-&gt;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()-&gt;addArmatureFileInfo("DemoPlayer/DemoPlayer.ExportJson");
	armature = NULL;
	armature = CCArmature::create("DemoPlayer");//0走路,1开枪,2开枪,3开空枪,4
	armature-&gt;setAnchorPoint(CCPoint(0.7, 0));

	sprite-&gt;addChild(armature);
}

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

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

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

void Player::walking()
{
	if (m_endX - m_startX  &gt;=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-&gt;getContentSize();
	return CCRectMake(this-&gt;getPositionX(),  this-&gt;getPositionY(), s.width, s.height);
}

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

	pPaddle-&gt;autorelease();

	return pPaddle;
}

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

	return true;
}

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

void Paddle::onExit()
{
	CCDirector* pDirector = CCDirector::sharedDirector();
	pDirector-&gt;getTouchDispatcher()-&gt;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-&gt;getParent()-&gt;convertToNodeSpace( touch-&gt;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-&gt;getLocation();

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

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

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

	m_state = kPaddleStateUngrabbed;
} 

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

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

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

		}

	}


}

void Paddle::setOpacity( GLubyte opacity )
{
	CCArray* _array = this-&gt;getChildren();
	CCObject *_obj;
	CCARRAY_FOREACH(_array, _obj )
	{
		CCSprite* _sp = (CCSprite *)_obj;
		_sp-&gt;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-&gt;setAnchorPoint(CCPoint());
			m_playerSprite-&gt;setPosition(CCPoint(-8,-15));
			this-&gt;addChild(m_playerSprite, 100);

			m_chairPartSprite= CCSprite::create(g_chair_left_part);
			m_chairPartSprite-&gt;setAnchorPoint(CCPoint());
			m_chairPartSprite-&gt;setPosition(CCPoint(-15,-5));
			this-&gt;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-&gt;setAnchorPoint(CCPoint());
			m_playerSprite-&gt;setPosition(CCPoint(-15,-5));
			this-&gt;addChild(m_playerSprite);
			break;
		}
	default:
		break;
	}
}

void Paddle::standUp()
{
	if (m_playerSprite)
	{
		m_playerSprite-&gt;removeFromParentAndCleanup(true);
		m_playerSprite = NULL;
	}
	if (m_chairPartSprite)
	{
		m_chairPartSprite-&gt;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 &amp;&amp; point.y == knownPoint1.y) || (point.x == knownPoint2.x &amp;&amp; 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 &amp;&amp; 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&gt;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>&amp; 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-&gt;addChild(layer);

	// return the scene
	return scene;
}

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

}

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

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

	m_pathSearch = new PathSearchInfo(_map);

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

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

	std::function<void point paddle selectobj> _funcSelect = std::bind(&amp;HelloWorld::selectObjCallback,this,std::placeholders::_1,std::placeholders::_2);  
	m_pathSearch-&gt;setSelectCallback(_funcSelect);
	/////////////////////////////
	 
	CCMenuItemSprite* _menuItemSprite = CCMenuItemSprite::create(CCSprite::create("CloseNormal.png"),CCSprite::create("CloseSelected.png"),NULL,this,SEL_MenuHandler(&amp;HelloWorld::menuCloseCallback));
	CCMenu* _menu = CCMenu::create(_menuItemSprite,NULL);
	this-&gt;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-&gt;setPosition(ccp(origin.x + visibleSize.width/2, origin.y + visibleSize.height - pLabel-&gt;getContentSize().height));

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

	this-&gt;scheduleUpdate();

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

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

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

void HelloWorld::drawPath( vector<pathsprite>&amp; vec )
{
	for (vector<pathsprite>::iterator iter = vec.begin(); iter !=  vec.end(); iter++)
	{
		(*iter)-&gt;m_sprite-&gt;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-&gt;getEnableMove())
	{
		m_currentSelect = NULL;
		auto nodePosition = convertToNodeSpace( touch-&gt;getLocation() );
		m_pathSearch -&gt;pathFunction(m_pathSearch-&gt;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-&gt;getEnableMove())
	{
		m_pathSearch-&gt;setEnableMove(true);
		m_currentSelect-&gt;standUp();
		m_player-&gt;m_sprite-&gt;setVisible(true);
	}
}
void HelloWorld::update(float dt)
{
	//移动层
	this-&gt;setPosition(m_orignPoint - m_player-&gt;m_sprite-&gt;getPosition());

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

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

		m_pathSearch -&gt;pathFunction( point ,m_player);
	}
}

void HelloWorld::moveDone(CCPoint point)
{
	//判断是有选择的物体
	if (m_currentSelect)
	{
		//判断是否能坐下
		if (m_currentSelect-&gt;m_enableSit/* &amp;&amp; point.x == m_currentSelect-&gt;m_terminal.x&amp;&amp; point.y ==  m_currentSelect-&gt;m_terminal.y*/)
		{
			m_currentSelect-&gt;sitChair();
			m_pathSearch-&gt;setEnableMove(false);
			m_player-&gt;m_sprite-&gt;setVisible(false);
		}
		//判断是否能捡起
		if (m_currentSelect-&gt;m_enablePickUp)
		{
			m_currentSelect-&gt;m_enablePickUp = false;
			m_currentSelect-&gt;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//精确的寻 路系统, 需要消耗额外的运算(魔兽争霸级的!)
登录后复制



本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章标签

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Conda升级Python版本的几种方法 Conda升级Python版本的几种方法 Feb 18, 2024 pm 08:56 PM

Conda升级Python版本的几种方法

升级numpy版本:详细易学的指南 升级numpy版本:详细易学的指南 Feb 25, 2024 pm 11:39 PM

升级numpy版本:详细易学的指南

win10系统升级后不能上网的处理教程 win10系统升级后不能上网的处理教程 Mar 27, 2024 pm 02:26 PM

win10系统升级后不能上网的处理教程

详解荣耀手机升级到鸿蒙系统的方法 详解荣耀手机升级到鸿蒙系统的方法 Mar 25, 2024 am 11:51 AM

详解荣耀手机升级到鸿蒙系统的方法

怎么升级wps版本?wps office怎么更新版本? 怎么升级wps版本?wps office怎么更新版本? Mar 14, 2024 am 08:43 AM

怎么升级wps版本?wps office怎么更新版本?

小艺升级为智能体!HarmonyOS NEXT鸿蒙原生智能开启全新AI时代 小艺升级为智能体!HarmonyOS NEXT鸿蒙原生智能开启全新AI时代 Jun 22, 2024 am 01:56 AM

小艺升级为智能体!HarmonyOS NEXT鸿蒙原生智能开启全新AI时代

小米14Pro怎么升级澎湃OS? 小米14Pro怎么升级澎湃OS? Mar 18, 2024 pm 07:34 PM

小米14Pro怎么升级澎湃OS?

win10怎么升级到win11 win10怎么升级到win11 Jan 16, 2024 pm 12:06 PM

win10怎么升级到win11

See all articles