package org.flixel { import flash.display.Graphics; import org.flixel.plugin.DebugPathDisplay; /** * This is a simple path data container. Basically a list of points that * a FlxObject can follow. Also has code for drawing debug visuals. * FlxTilemap.findPath() returns a path object, but you can * also just make your own, using the add() functions below * or by creating your own array of points. * * @author Adam Atomic */ public class FlxPath { /** * The list of FlxPoints that make up the path data. */ public var nodes:Array; /** * Specify a debug display color for the path. Default is white. */ public var debugColor:uint; /** * Specify a debug display scroll factor for the path. Default is (1,1). * NOTE: does not affect world movement! Object scroll factors take care of that. */ public var debugScrollFactor:FlxPoint; /** * Setting this to true will prevent the object from appearing * when the visual debug mode in the debugger overlay is toggled on. */ public var ignoreDrawDebug:Boolean; /** * Internal helper for keeping new variable instantiations under control. */ protected var _point:FlxPoint; /** * Instantiate a new path object. * * @param Nodes Optional, can specify all the points for the path up front if you want. */ public function FlxPath(Nodes:Array=null) { if(Nodes == null) nodes = new Array(); else nodes = Nodes; _point = new FlxPoint(); debugScrollFactor = new FlxPoint(1.0,1.0); debugColor = 0xffffff; var debugPathDisplay:DebugPathDisplay = manager; if(debugPathDisplay != null) debugPathDisplay.add(this); } /** * Clean up memory. */ public function destroy():void { var debugPathDisplay:DebugPathDisplay = manager; if(debugPathDisplay != null) debugPathDisplay.remove(this); debugScrollFactor = null; _point = null; nodes = null; } /** * Add a new node to the end of the path at the specified location. * * @param X X position of the new path point in world coordinates. * @param Y Y position of the new path point in world coordinates. */ public function add(X:Number,Y:Number):void { nodes.push(new FlxPoint(X,Y)); } /** * Add a new node to the path at the specified location and index within the path. * * @param X X position of the new path point in world coordinates. * @param Y Y position of the new path point in world coordinates. * @param Index Where within the list of path nodes to insert this new point. */ public function addAt(X:Number, Y:Number, Index:uint):void { if(Index > nodes.length) Index = nodes.length; nodes.splice(Index,0,new FlxPoint(X,Y)); } /** * Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates. * This also gives you the option of not creating a new node but actually adding that specific * FlxPoint object to the path. This allows you to do neat things, like dynamic paths. * * @param Node The point in world coordinates you want to add to the path. * @param AsReference Whether to add the point as a reference, or to create a new point with the specified values. */ public function addPoint(Node:FlxPoint,AsReference:Boolean=false):void { if(AsReference) nodes.push(Node); else nodes.push(new FlxPoint(Node.x,Node.y)); } /** * Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates. * This also gives you the option of not creating a new node but actually adding that specific * FlxPoint object to the path. This allows you to do neat things, like dynamic paths. * * @param Node The point in world coordinates you want to add to the path. * @param Index Where within the list of path nodes to insert this new point. * @param AsReference Whether to add the point as a reference, or to create a new point with the specified values. */ public function addPointAt(Node:FlxPoint,Index:uint,AsReference:Boolean=false):void { if(Index > nodes.length) Index = nodes.length; if(AsReference) nodes.splice(Index,0,Node); else nodes.splice(Index,0,new FlxPoint(Node.x,Node.y)); } /** * Remove a node from the path. * NOTE: only works with points added by reference or with references from nodes itself! * * @param Node The point object you want to remove from the path. * * @return The node that was excised. Returns null if the node was not found. */ public function remove(Node:FlxPoint):FlxPoint { var index:int = nodes.indexOf(Node); if(index >= 0) return nodes.splice(index,1); else return null; } /** * Remove a node from the path using the specified position in the list of path nodes. * * @param Index Where within the list of path nodes you want to remove a node. * * @return The node that was excised. Returns null if there were no nodes in the path. */ public function removeAt(Index:uint):FlxPoint { if(nodes.length <= 0) return null; if(Index >= nodes.length) Index = nodes.length-1; return nodes.splice(Index,1); } /** * Get the first node in the list. * * @return The first node in the path. */ public function head():FlxPoint { if(nodes.length > 0) return nodes[0]; return null; } /** * Get the last node in the list. * * @return The last node in the path. */ public function tail():FlxPoint { if(nodes.length > 0) return nodes[nodes.length-1]; return null; } /** * While this doesn't override FlxBasic.drawDebug(), the behavior is very similar. * Based on this path data, it draws a simple lines-and-boxes representation of the path * if the visual debug mode was toggled in the debugger overlay. You can use debugColor * and debugScrollFactor to control the path's appearance. * * @param Camera The camera object the path will draw to. */ public function drawDebug(Camera:FlxCamera=null):void { if(nodes.length <= 0) return; if(Camera == null) Camera = FlxG.camera; //Set up our global flash graphics object to draw out the path var gfx:Graphics = FlxG.flashGfx; gfx.clear(); //Then fill up the object with node and path graphics var node:FlxPoint; var nextNode:FlxPoint; var i:uint = 0; var l:uint = nodes.length; while(i < l) { //get a reference to the current node node = nodes[i] as FlxPoint; //find the screen position of the node on this camera _point.x = node.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY() _point.y = node.y - int(Camera.scroll.y*debugScrollFactor.y); _point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001)); _point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001)); //decide what color this node should be var nodeSize:uint = 2; if((i == 0) || (i == l-1)) nodeSize *= 2; var nodeColor:uint = debugColor; if(l > 1) { if(i == 0) nodeColor = FlxG.GREEN; else if(i == l-1) nodeColor = FlxG.RED; } //draw a box for the node gfx.beginFill(nodeColor,0.5); gfx.lineStyle(); gfx.drawRect(_point.x-nodeSize*0.5,_point.y-nodeSize*0.5,nodeSize,nodeSize); gfx.endFill(); //then find the next node in the path var linealpha:Number = 0.3; if(i < l-1) nextNode = nodes[i+1]; else { nextNode = nodes[0]; linealpha = 0.15; } //then draw a line to the next node gfx.moveTo(_point.x,_point.y); gfx.lineStyle(1,debugColor,linealpha); _point.x = nextNode.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY() _point.y = nextNode.y - int(Camera.scroll.y*debugScrollFactor.y); _point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001)); _point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001)); gfx.lineTo(_point.x,_point.y); i++; } //then stamp the path down onto the game buffer Camera.buffer.draw(FlxG.flashGfxSprite); } static public function get manager():DebugPathDisplay { return FlxG.getPlugin(DebugPathDisplay) as DebugPathDisplay; } } }