AS3 高級動畫教程學習之:等角投影筆記

IsoUitls類,實現空間座標與平面座標之間的轉換。具體原理可參考《Flash actionScript 3.0高級動畫教程》第三章 等角投影

IsoUitls源代碼

package com.hope.isometric
{
	import flash.geom.Point;

	public class IsoUtils
	{
		public static const Y_CORRECT: Number = Math.cos( -Math.PI / 6 )*Math.SQRT2
			
		public function IsoUtils()
		{
		}
		
		/**
		 * 把等角座標中的3D座標轉換成屏幕上的2D座標
		 * @param pos Point3D
		 * @return 
		 * 
		 */		
		public static function isoToScreen( pos: Point3D ): Point
		{
			var screenX:Number= pos.x - pos.z; 	
			var screenY:Number= pos.y * Y_CORRECT + ( pos.x + pos.z ) * 0.5; 
			//var screenZ:Number = ( pos.x + pos.z ) * 0.800 - pos.y * 0.707;
			
			return new Point( screenX, screenY );
		}
		
		public static function screenToIso( point: Point ): Point3D
		{
			var xpos:Number = point.y + point.x * .5;
			var ypos:Number = 0;
			var zpos:Number = point.y - point.x * .5;
			
			return new Point3D( xpos, ypos, zpos );
		}
	}
}


 Point3D類,三維空間座標

package com.hope.isometric
{
	public class Point3D
	{
		public var x: Number;
		public var y: Number;
		public var z: Number;
		
		public function Point3D( x: Number = 0, y: Number = 0, z: Number = 0 )
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}
	}
}


IsoObject類

package com.hope.isometric
{
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.getDefinitionByName;
	
	public class IsoObject extends Sprite
	{
		protected var _position: Point3D;
		protected var _size: Number;
		protected var _walkable: Boolean = false;
		
		protected var _color: uint;
		protected var _height: Number;
		
		public static const TILE: String = "Tile"	;
		public static const BOX: String = "Box";
		
			
		public function IsoObject()
		{
			_position = new Point3D();
			updateScreenPosition();
		}
		
		static public function create( type: Object): IsoObject
		{
			switch( type ){	
				case IsoObject.TILE:
					return new Tile();
					break;
				
				case IsoObject.BOX:
					return new Box();
					break;
				
				default:
					return new IsoObject();	
			}	
		}
		
		protected function updateScreenPosition(): void
		{
			var screenPos: Point = IsoUtils.isoToScreen( _position );
			super.x = screenPos.x;
			super.y = screenPos.y;
		}
		
		public function get rect(): Rectangle
		{
			return new Rectangle( x - size / 2, z - size / 2, size, size );
		}
		
		public function draw( size: Number, color: uint, height: Number = 0 ): void
		{
			this.size = size;
			this.color = color;
			this.height = height;
		}
		
		public function dispose(): void
		{
			graphics.clear();
			parent.removeChild( this );
		}
		
		override public function toString():String
		{
			return "[IsoObject( x:" + _position.x + " y:" + _position.y + " z:" + _position.z + ")]";
		}	
		
		/**
		 * 讀取/設置3D空間中的x座標
		 */
		override public function set x(value:Number):void
		{
			_position.x = value;
			updateScreenPosition();
		}
		
		override public function get x():Number
		{
			return _position.x;
		}
		
		/**
		 * 讀取/設置3D空間中的y座標
		 */
		override public function set y(value:Number):void
		{
			_position.y = value;
			updateScreenPosition();
		}
		
		override public function get y():Number
		{
			return _position.y;
		}
		
		/**
		 * 讀取/設置3D空間中的z座標
		 */
		override public function set z(value:Number):void
		{
			_position.z = value;
			updateScreenPosition();
		}
		
		override public function get z():Number
		{
			return _position.z;
		}
		
		public function set position( position: Point3D ): void
		{
			this._position = position;
			updateScreenPosition();
		}
		
		public function get position(): Point3D
		{
			return _position;
		}
		
		public function get depth(): Number
		{
			return ( _position.x + _position.z ) * 0.866 - _position.y * 0.707;
		}
		
		/**
		 * 指定其他對對象是否可以通過所佔的位置
		 * @param value
		 * 
		 */		
		public function set walkable( value: Boolean ): void
		{
			_walkable = value;
		}
		
		public function get walkable(): Boolean
		{
			return _walkable;
		}
		
		/**
		 * 返回尺寸
		 * @return 
		 * 
		 */		
		public function get size(): Number
		{
			return _size;
		}
		
		public function set size( value: Number ): void
		{
			_size = value;	
		}
		/**
		 * set/get the height of this tile 
		 * @param value
		 * 
		 */		
		override public function set height(value:Number):void
		{
			_height = value;
		}
		
		override public function get height():Number
		{
			return _height;
		}
		
		/**
		 * Set/get the color of this tile 
		 * @return 
		 * 
		 */	
		public function set color( value: uint ): void
		{
			_color = value;
		}
		
		public function get color(): uint
		{
			return _color;
		}
	}
}

IsoObject類,這個類所實現的是 對象的3D狀態到屏幕狀態的轉換,繼承之sprite。與書上的相比,添加了create工廠方法,根據參數(type )返回相對應的子類實例對象。

這個類有兩個子類tile, box。IsoObject不包函任何圖形,圖形由子類通過draw方法完成,稍後介紹。
 

Title類

package com.hope.isometric
{
	import flash.display.Sprite;
	import flash.geom.Point;
	
	public class Tile extends IsoObject
	{
		
		public function Tile()
		{
			super();
		}
		
		/**
		 * 
		 * 繪製圖形 
		 */		
		override public function draw( size: Number, color: uint, height: Number = 0 ): void
		{
			super.draw( size, color, height );

			graphics.clear();
			graphics.lineStyle(0, 0, .5);
			graphics.beginFill( _color );
					
			graphics.moveTo(-size, 0);
			
			graphics.lineTo(0, -size * .5);
			graphics.lineTo(size, 0);
			graphics.lineTo(0, size * .5);
			graphics.lineTo( -size, 0 );
		}
	}
}


Tile繼承IsoObject, 重寫了draw函數,繪製一個自定義大小,顏色,高度,長寬比爲2:1的菱形。

 

Box類

package com.hope.isometric
{
	public class Box extends IsoObject
	{
		public function Box()
		{
			super();
		}
		
		override public function draw( size: Number, color: uint, height: Number = 0 ):void
		{
			super.draw( size, color, height );
			
			var red: uint = color >> 16;
			var green: uint = color >> 8 && 0xff;
			var blue: uint = color && 0xff;
			
			var leftShadow:uint = (red * .5) << 16 |(green * .5) << 8 |(blue * .5);
			var rightShadow:uint = (red * .75) << 16 |(green * .75) << 8 | (blue * .75);
			
			var h:Number = height * IsoUtils.Y_CORRECT;
			
			graphics.clear();
			
			drawTop( color, h );
			drawLeft( leftShadow, h );
			drawRight( rightShadow, h );
		}
		
		private function drawTop( color: uint, h: Number ): void
		{
			graphics.beginFill( color );
			graphics.lineStyle( 0, 0, 0.5 );
			
			graphics.moveTo(-size, -h);
			
			graphics.lineTo(0, -size * .5 - h);
			graphics.lineTo(size, -h);
			graphics.lineTo(0, size * .5 - h);
			graphics.lineTo(-size, -h);
			
			graphics.endFill();
		}
		
		private function drawLeft( color: uint, h: Number ): void
		{
			graphics.beginFill(color );
			graphics.lineStyle(0, 0, .5);
			
			graphics.moveTo(-size, -h);
			
			graphics.lineTo(0, size * .5 - h);
			graphics.lineTo(0, size * .5);
			graphics.lineTo( -size, 0 );
			graphics.lineTo( -size, -h );
			
			graphics.endFill();
			
		}
		
		private function drawRight( color: uint, h: Number ): void
		{
			graphics.beginFill( color );
			graphics.lineStyle(0, 0, .5);
			
			graphics.moveTo(size, -h);
			
			graphics.lineTo(0, size * .5 - h);
			graphics.lineTo(0, size * .5);
			graphics.lineTo(size, 0);
			graphics.lineTo(size, -h);
			
			graphics.endFill();
		}
	}
}


Box類與Tile類一樣,同樣是繼類IsoObject類,重寫draw函數,繪製一個方盒子。

 

 IsoWorld類

package com.hope.isometric
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;

//	http://www.java3z.com/cwbwebhome/article/article2/2825.html
	public class IsoWorld extends Sprite
	{
		private var grid: Grid;
		private var cellSize: Number;
		
		private var floor: Sprite;
		private var world: Sprite;
			
		[ArrayElementType("IsoObject")]
		private var objectList: Array;
		
		private var numCols: int = 10;
		private var numRows: int = 10;
		
		public function IsoWorld()
		{
		}
		
		static public function create(): IsoWorld
		{
			return new IsoWorld();
		}
		
		/**
		 * 
		 * @param size The tile size to user when making the world
		 * @return A fully populated IsoWorld instance
		 * 
		 */		
		public function makeWorld( size: Number, mapGrid: Array, tileTypes: Dictionary ): void
		{
			//cellSize = size;
			numCols = mapGrid.length;
			numRows = mapGrid[0].length;
			
			//createGrid( size );
			
			for( var i:int = 0; i < mapGrid.length; i++ )
			{
				for( var j:int = 0; j < mapGrid[i].length; j++ )
				{
					var cellType: String = mapGrid[i][j] as String;
					var cell: Object = tileTypes[ cellType ];
					
					var tile: IsoObject = IsoObject.create( cell.type );
					
					tile.draw(size, parseInt(cell.color), parseInt(cell.height));
					tile.walkable = cell.walkable == "true" ? true:false;
					
					tile.position = new Point3D( j * 20, 0, i * 20 );
					
					//grid.setNodeObject( j, i, tile );
					
					addChild( tile );	
				
					//trace( "tile type:" + cell.type + " x:" + i + " y:" + j  + " walkable:" + tile.walkable +  " " + grid.getNode(j,i).walkable );
				}
			}
		}
		
		
		public function setPosition( x: Number, y: Number ): void
		{
			this.x = x;
			this.y = y;
		}
		
	}
}


 

IsoWord類根據Map信息通過makeWorld創建地圖信息。

Map  地圖信息 ( map.txt 文件) //行爲註釋, # 行爲定義, 其他的地圖信息 0表示Tile, 1 表示Box。 如果添加新的圖形,可定義2, 3, 4等等.

//this is a comment
# 0 type:Tile walkable:true height:0 color:0xcccccc
# 1 type:Box walkable:false height:20 color:0xff6666


0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0

0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


 

MapLoder類

package com.hope.isometric
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	public class MapLoader extends EventDispatcher
	{
		private var _tileTypes: Dictionary;
		
		private var _mapGrid: Array;
		private var _loader: URLLoader;
		
		public function MapLoader()
		{
			init();				
		}
		
		static public function create(): MapLoader
		{
			return new MapLoader();	
		}
		
		private function init(): void
		{
			_tileTypes = new Dictionary();
		}

		/**
		 * Loads a text file from the specified url
		 * @param url The location of the text file to load
		 * 
		 */	
		public function loadMap( url: String ): void
		{
			_loader = new URLLoader();
			_loader.addEventListener( Event.COMPLETE, onLoad );
			
			_loader.load( new URLRequest( url ));
		}
		
		/**
		 * Parse text file int tile definitions and map;
		 * @param event
		 * 
		 */	
		private function onLoad( event: Event ): void
		{
			_mapGrid = new Array();
			var data: String = _loader.data;
			trace( "mapData:" + data );
			
			//first get each line of the file
			var lines: Array = data.split( "\r\n" );
			for( var i: int = 0; i < lines.length; i++ )
			{
				var line: String = lines[i];
				
				//if line is tile definition
				if( isDefinition( line ) )
				{
					parseDefinition( line );	
				}
				else if( !lineIsEmpty(line) && !isComment( line ) )
				{
					var cells: Array = line.split(" ");
					_mapGrid.push( cells );
				}	
			}
			
			dispatchEvent( new Event( Event.COMPLETE ) );
		}
		
		/**
		 * 
		 * @param line
		 * 
		 */		
		private function parseDefinition( line: String ): void
		{
			var tokens: Array = line.split(" ");
			
			//shift #
			tokens.shift();
			
			var symbol: String = tokens.shift() as String;
			
			var definition: Dictionary = new Dictionary();
			for( var i:int = 0; i < tokens.length; i++ )
			{
				var key:String = tokens[i].split(":")[0];
				var val:String = tokens[i].split(":")[1];
				
				definition[ key ] = val;
			}
			
			//register the type and definition
			setTileType( symbol, definition );	
		}
		
		/**
		 * Links a symbol with a definition object 
		 * @param symbol The charactor to user the definition
		 * @param definition A generic object with definition properties;
		 * 
		 */		
		public function setTileType( symbol: String, definition: Object ): void
		{
			_tileTypes[ symbol ] = definition;
		}
		
		/**
		 * Return true if line only contains space, false if any other characters; 
		 * @param line
		 * @return 
		 * 
		 */		
		private function lineIsEmpty( line: String ): Boolean
		{
			for( var i: int = 0; i < line.length; i++ )
			{
				if( line.charAt(i) != " " ) return false;
			}
			
			return true;
		}
		
		/**
		 * Retrun true if line is a comment( start with "//" )
		 * @param line The string to test
		 * @return 
		 * 
		 */		
		private function isComment( line: String ): Boolean
		{
			return line.indexOf( "//" ) == 0 ? true : false;
		}
		
		/**
		 * Return true if line is a definition ( start width "#" )
		 * @param line The string to test
		 * @return 
		 * 
		 */		
		private function isDefinition( line: String ): Boolean
		{
			return line.indexOf( "#" ) == 0 ? true : false;
		}	
		
		//////////////
		///setter / getter
		/////////////
		public function get tileTypes(): Dictionary
		{
			return _tileTypes;
		}
		
		public function get mapGrid(): Array
		{
			return _mapGrid;	
		}
	}
}


MapLoader類用於下載map.txt文件,並記取文件信息

IsoWorldTest測試類

package com.hope.isometric
{
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.net.URLRequest;

	
	public class IsoWorldTest extends Sprite
	{
		private var world: IsoWorld;
		private var mapLoader: MapLoader;
		private var astar: AStar;
		
		public function IsoWorldTest()
		{
			if( stage )
				init();
			else
				addEventListener( Event.ADDED_TO_STAGE, init );
		}
		
		private function init( event: Event = null ): void
		{
			removeEventListener( Event.ADDED_TO_STAGE, init );
			
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
		
			loadMap();		
		}
		
		private function loadMap(): void
		{
			mapLoader = new MapLoader();
			mapLoader.addEventListener( Event.COMPLETE, onMapComplete );
			mapLoader.loadMap( "map.txt" );	
		}
		
		private function onMapComplete( event: Event ): void
		{
			trace( "load complete" );
			world = IsoWorld.create();
			
			world.makeWorld( 20, mapLoader.mapGrid, mapLoader.tileTypes );
			
			addChild( world );
			world.setPosition( 500, 200 );			
		}
	}
}


首先加載地圖信息文件,完成後能過IsoWorld類的makeWorld函數創建地圖。

 

最後運行結果

 

發佈了17 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章