`

45度角地图人物行走寻路

 
阅读更多
iteye的博客太难编辑了,改天要换个地方了。
最近在研究45度地图,写了一个demo,
主要的类有两个,第一个,人物控制的类
package view
{
	import com.friendsofed.isometric.IsoObject;
	
	import constVars.Directions;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	public class SpriteSheet extends IsoObject
	{
		//源图片
		protected var _source:BitmapData;
		//每小格图片的宽
		protected var _frameWidth:Number;
		//每小格图片的高
		protected var _frameHeight:Number;
		//接受拷贝图片的bitmap
		private var _frameBitmap:Bitmap;
		//拷贝源图片的范围
		private var _frameRect:Rectangle;
		//当前人物的方向
		protected var _direction:String;
		//图片所在的行
		protected var _rowNum:int;
		//图片所在列
		private var _col:int = 0;
		//每间隔多少毫秒,图片拷贝一次
		public static const RENDER_INTERVAL:Number = 64;
		//render timer
		protected var _oldTime:Number = 0;
		//每间隔多少毫秒,图片拷贝一次
		protected var _renderInterval:Number;
		//最大图片的列
		protected var _maxCol:int;
		//最大图片的行
		protected var _maxRow:int = 8;//8个方向
		//存放拷贝各个小格图片所占用的rectangle
		protected var _rects:Dictionary;
		//是否静止
		private var _isIdle:Boolean;
		
		
		public function SpriteSheet(source:BitmapData,frameWidth:Number, frameHeight:Number,renderInterval:Number = RENDER_INTERVAL)
		{
			super(size);
			_source = source;
			_frameWidth = frameWidth;
			_frameHeight = frameHeight;
			_maxCol = Math.floor(_source.width/_frameWidth);
			_renderInterval = renderInterval;
			_frameRect = new Rectangle(0, 0, frameWidth, frameHeight);
			_rects = new Dictionary();
			for(var i:int = 0; i < _maxRow; i++)
				for(var j:int = 0; j < _maxCol; j++)
				{
					var rect:Rectangle = new Rectangle(j*_frameWidth, i*_frameHeight, _frameWidth, _frameHeight);
					_rects[j+","+i] = rect;//将各个小格所需的rectangle存在dictrony里面
				}
			_oldTime = getTimer();
			render();
		}
		
		/**
		 * 把状态设为静止
		 */
		public function idle():void
		{
			_isIdle = true;
		};
		
		/**
		 * 把状态设为运动
		 * 
		 */
		public function action():void
		{
			_isIdle = false;
			startRender();
		};
		
		//监听函数,如果过了_renderInterval秒,那么渲染一次
		protected function onEnterFrame(event:Event):void
		{
			var elapsed:Number = getTimer() - _oldTime;
			
			if (elapsed >= _renderInterval)
			{
				render();
				_oldTime = getTimer();
			}
			
		}
		
		//停止渲染
		private function stopRender():void
		{
			removeEventListener(Event.ENTER_FRAME,onEnterFrame);
		}
		
		//开始渲染
		private function startRender():void
		{
			if(!hasEventListener(Event.ENTER_FRAME))
			{
				addEventListener(Event.ENTER_FRAME,onEnterFrame);
			}
		}
		
		public function render():void
		{
			if (_frameBitmap == null)
			{
				//创建bitmap存储从源图片拷贝的bitmapData
				_frameBitmap = new Bitmap(new BitmapData(_frameWidth, _frameHeight, true, 0x00000000));
				addChild(_frameBitmap);
				//图片的片源量
				_frameBitmap.x = -39;
				_frameBitmap.y = -115;
			}
			_frameBitmap.bitmapData.lock();
			if(_isIdle)//如果静止,那么拷贝每一行的第一张图片
			{
				_frameRect = _rects[0 +","+_rowNum] as Rectangle;
				_frameBitmap.bitmapData.copyPixels(_source, _frameRect, new Point(0, 0), null, null, false);
				stopRender();
			}
			else
			{
				if(_col < _maxCol)
				{
					//从_rects取出rectangle
					_frameRect = _rects[_col+","+_rowNum] as Rectangle;
				}
				else
				{
					_col = 0;
				}
				_col++;//每一次渲染图片的列数依次加1
				_frameBitmap.bitmapData.copyPixels(_source, _frameRect, new Point(0, 0), null, null, false);
			}
			_frameBitmap.bitmapData.unlock();

		}
		
		//改变人物行走的方向
		public function setDirection(direction:String):void
		{
			_direction = direction;
			switch (direction)
			{
				case Directions.S:
					_rowNum = 0;
					break;
				case Directions.W:
					_rowNum = 1;
					break;
				case Directions.E:
					_rowNum = 2;
					break;
				case Directions.N:
					_rowNum = 3;
					break;
				case Directions.SW:
					_rowNum = 4;
					break;
				case Directions.SE:
					_rowNum = 5;
					break;
				case Directions.NW:
					_rowNum = 6;
					break;
				case Directions.NE:
					_rowNum = 7;
					break;
				default:
					_rowNum = 0;
			}
		}	
			
	}
}

第二个,主程序的类
package
{
	import com.friendsofed.isometric.DrawnIsoTile;
	import com.friendsofed.isometric.IsoUtils;
	import com.friendsofed.isometric.IsoWorld;
	import com.friendsofed.isometric.Point3D;
	
	import constVars.Directions;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import path.AStar;
	import path.Grid;
	import path.Node;
	
	import view.PathNode;
	import view.SpriteSheet;
	
	[SWF(width="1000",height="600",frameRate="30")]
	public class PlayerTest extends Sprite
	{
		[Embed(source='0001.png')]
		public const SHEET:Class;
		
		//图片每一小格占用的宽和高
		public const SHEET_FRAME_WIDTH:Number = 79;
		public const SHEET_FRAME_HEIGHT:Number = 108;
		
		private var _ss:SpriteSheet;
		private var _world:IsoWorld;
		
		//地图每一个tile的大小
		private static const SIZE:int = 40;
		private static const GIRD_SIZE:int = 20;
		//网格
		private var _grid:Grid;
		//寻路路径,节点数组
		private var _path:Array;
		//寻路路径下标
		private var _index:int;
		//行走速度
		private var _speed:int = 2;
		
		public function PlayerTest()
		{
			createWorld();
			_ss = new SpriteSheet(new SHEET().bitmapData, SHEET_FRAME_WIDTH, SHEET_FRAME_HEIGHT);
			_world.addChildToWorld(_ss);
			//初始化人物位置
			_ss.position = new Point3D(SIZE/2, 0, SIZE/2);
			_world.addEventListener(MouseEvent.CLICK,onClick);
			makeGrid();
		}
		
		//创建网格
		private function makeGrid():void
		{
			// TODO Auto Generated method stub
			_grid = new Grid(GIRD_SIZE, GIRD_SIZE);
			for(var i:int = 0; i < GIRD_SIZE; i++)
			{
				for(var j:int = 0; j < GIRD_SIZE; j++)
				{
					_grid.setWalkable(i,j,true);
				}
			}
		}
		
		//创建地图
		private function createWorld():void
		{
			_world = new IsoWorld();
			_world.x = stage.stageWidth / 2;
			_world.y = 100;
			addChild(_world);
			
			for(var i:int = 0; i < GIRD_SIZE; i++)
			{
				for(var j:int = 0; j < GIRD_SIZE; j++)
				{
					var tile:DrawnIsoTile = new DrawnIsoTile(SIZE, 0xcccccc);
					tile.position = new Point3D(i * SIZE, 0, j * SIZE);
					_world.addChildToFloor(tile);
				}
			}
		}
		
		private function onClick(event:MouseEvent):void
		{
			var pos:Point3D = IsoUtils.screenToIso(new Point(_world.mouseX, _world.mouseY));
			var col:int = Math.round(pos.x/SIZE);
			var row:int = Math.round(pos.z/SIZE);
			//设置起始的node 
			_grid.setStartNode(Math.round(_ss.x/SIZE),Math.round(_ss.z/SIZE));
			//设置目的地的node
			_grid.setEndNode(col,row);//取得网格地图的终点
			//寻路
			findPath();
			//人物开始行走
			_ss.action();
		}
		
		private function findPath():void
		{
			//A*寻路
			var astar:AStar = new AStar();
			if(astar.findPath(_grid))
			{
				_path = astar.path;
				_index = 0;
				showPath();//显示路径提示
				addEventListener(Event.ENTER_FRAME, onEnterFrame);
			}
		}
		
		private function showPath():void
		{
			_world.clearPathTip();//清除之前的提示
			var node:Node;
			for(var i:int = 0; i< _path.length; i++)
			{
				node = _path[i] as Node;
				var pathNode:PathNode = new PathNode();
				//显示人物行走的路线
				pathNode.position = new Point3D(node.x*SIZE,0,node.y*SIZE);
				_world.addChildToPathTip(pathNode);
			}
		}
		
		protected function onEnterFrame(event:Event):void
		{
			var node:Node = _path[_index];
			var targetPoint:Point = IsoUtils.isoToScreen(new Point3D(node.x*SIZE+SIZE/2,0,node.y*SIZE+SIZE/2));
			var playPoint:Point = IsoUtils.isoToScreen(_ss.position);
			var dx:Number = targetPoint.x - playPoint.x;
			var dy:Number = targetPoint.y - playPoint.y;
			var dist:Number = Math.sqrt(dx * dx + dy * dy);
			if(dist < _speed)
			{
				_index++;
				if(_index >= _path.length)//已经到达目的地
				{
					_ss.idle();
					removeEventListener(Event.ENTER_FRAME, onEnterFrame);
				}
			}
			else
			{
				var angle:Number = Math.atan2( dy, dx );//弧度
				var speedX:Number = _speed * Math.cos( angle );
				var speedY:Number = _speed * Math.sin( angle );
				var ang:Number=angle*180/Math.PI;
				
				//判断行走方向,切换不同方向的行走动画
				if(ang > -22.5 && ang <= 22.5)
				{
					_ss.setDirection(Directions.E);
				}
				else if(ang > 22.5 && ang <= 67.5)
				{
					_ss.setDirection(Directions.SE);
				}
				else if(ang > 67.5 && ang <= 112.5)
				{
					_ss.setDirection(Directions.S);
				}
				else if(ang > 112.5 && ang <= 157.5)
				{
					_ss.setDirection(Directions.SW);
				}
				else if(ang > -157.5 && ang <= -112.5)
				{
					_ss.setDirection(Directions.NW);
				}
				else if(ang > -67.5 && ang <= -22.5)
				{
					_ss.setDirection(Directions.NE);
				}
				else if(ang > -112.5 && ang <= -67.5)
				{
					_ss.setDirection(Directions.N);
				}
				else
				{
					_ss.setDirection(Directions.W);
				}
				
				var newX:Number=_ss.screenX+speedX;
				var newY:Number=_ss.screenY+speedY;
				var newPos:Point3D=IsoUtils.screenToIso(new Point(newX,newY));
				_ss.position=newPos;//更新位置
			}
		}
		
	}
}

源代码在附件中
分享到:
评论

相关推荐

    flex 人物行走案例

    为了更好地实现这一案例,我们可以编写一个简单的事件驱动程序,当用户点击地图上的某个位置时,启动寻路算法计算路径,并开始播放人物行走动画。此外,为了提高用户体验,还可以添加暂停、重置和调整行走速度等功能...

    FLASH+php WEBGame 45度地图切换 多人游戏社区(源码+fms服务端)开源项目

    FLASH+php WEBGame 45度地图切换 多人游戏社区 FLASH人物行走 FLASH人物8方向寻路 在线聊天 (源码+fms服务端)开源项目 游戏截图: http://www.365tt1.com/ads/RGP/001.jpg http://www.365tt1.com/ads/RGP/002.jpg...

    一个flex游戏人物行走的源代码

    本资源包含一个Flex游戏人物行走的源代码,这对于理解游戏开发中的角色移动逻辑和碰撞检测至关重要。 源代码的核心部分可能涉及以下几个关键知识点: 1. **ActionScript**:ActionScript是Flash和Flex中的主要编程...

    3D地图编辑器

    5. **导航网格**:用于AI路径规划,生成一个表示可行走区域的网格,以便游戏角色自动寻路。 6. **场景编排**:可以设置触发器、动画、事件等,使地图具备交互性和动态性。 对于初学者来说,3D地图编辑器的教程极具...

    JS/HTML5游戏常用算法之路径搜索算法 随机迷宫算法详解【普里姆算法】

    在这些游戏中,通过鼠标指定行走目的地,人物或者NPC就会自动行走到目标地点,这就是通过路径搜索或者称为寻路算法来实现的。通俗地说,就是在一张地图中,如何让主角自动行走到指定的地点,如图6-21所示,假设主角...

    游戏开发中的经典算法(配图版,百度文库需下载券)

    SLG(策略游戏)中的人物可达范围计算,主要是确定角色能够在地图上的哪些区域自由移动。这涉及到对地图障碍物的分析,以及角色移动规则的设定,例如限制只能在特定地形上行走。通过计算每个节点的可达性,可以生成...

    使用three.js实现室内路径规划demo

    使用three.js基于已有的路径和节点数据 使用d算法实现室内地图点选路径规划 具体效果参见我的博客:https://blog.csdn.net/u014529917/article/details/100424812

    a星算法代码

    a星算法1、A星寻路; 2、支持连续点击,行走动画需要流畅过度; 3、地图不足以一屏显示时,能够自动滚动,到达边界时,不再滚动(人物并不总是在正中); 4、地图需要有障碍层,寻路时跳过;

    基于Unity3D迷宫游戏制作

    1. 地图设计:迷宫地图通常由一系列可行走和不可行走的格子组成。在Unity3D中,我们可以使用Box Collider或者Custom Collider来定义可行走区域。迷宫的墙壁可以通过导入3D模型或者使用Plane GameObject并调整尺寸来...

    JSHTML5游戏常用算法之路径搜索算法随机迷宫算法详解【普里姆算法】随机搜索算法.pdf

    在这些游戏中,通过路径指定目的地,人物或者 NPC 就会自动行走到目的地,这就是通过路径搜索或者称为寻路算法来实现的。 路径搜索算法的基本思想是,给定一个起点和终点,找到从起点到终点的一条路径,使得人物...

Global site tag (gtag.js) - Google Analytics