2011年8月29日 星期一

as3 FLIXEL FINDPATH DEFAULT自訂路徑

如果利用flixel底下的findPath,自訂自已想要的行走路線?
我的作法如下
1.利用tilemap,定義出每條路線的起點跟終點,還有所經過的所有點
2.將每條路徑的點,利用FlxPath轉化成node
3.接著把enemy套上followPath,並把我們自訂的path丟進去,enemy就會跟著自訂的路線走啦


demo:
http://a-z.tw/blogger/assample/btdsample/BTDsample.html
主要functioin如下
class HTD_map:




package
{
 import org.flixel.*;
 import org.flixel.system.FlxTile;
 public class HTD_map extends FlxTilemap
 {
  private var categoryNumber:uint;
  public var paths:Array;
  public function HTD_map(categoryNumber:uint)
  {
   super();
   this.categoryNumber=categoryNumber;
  }
  
  public function findAllPathForBTD():Array
  {
   paths=new Array(categoryNumber);
   var startPoints:Array=new Array;
   var endPoints:Array=new Array;
   for(var yIndex:uint=0;yIndex<heightInTiles;yIndex++)
   {
    for(var xIndex:uint=0;xIndex<widthInTiles;xIndex++)
    {
     var tile:uint=getTile(xIndex,yIndex);
     if(tile<=categoryNumber&&tile!=0)//start  ., get center=>+0.5
      startPoints[tile-1]=new FlxPoint((xIndex+0.5)*_tileWidth,(yIndex+0.5)*_tileHeight);
     else if(tile>categoryNumber*2)//start
      endPoints[tile-(categoryNumber*2)-1]=new FlxPoint((xIndex+0.5)*_tileWidth,(yIndex+0.5)*_tileHeight);
    }
   }
   var paths:Array=new Array;
   for(var index:uint=0;index<startPoints.length;index++)
    paths.push(findPath(startPoints[index],endPoints[index]));
   return paths;
  }
  
  public override function findPath(Start:FlxPoint,End:FlxPoint,Simplify:Boolean=true,RaySimplify:Boolean=false):FlxPath
  {
   //figure out what tile we are starting and ending on.設立起點跟終點在map上的絕對位置 一維展開
   var startIndex:uint = int((Start.y-y)/_tileHeight) * widthInTiles + int((Start.x-x)/_tileWidth);
   var endIndex:uint = int((End.y-y)/_tileHeight) * widthInTiles + int((End.x-x)/_tileWidth);
   //取得相對路徑的通行記號
   var currectCategory:uint=getTileByIndex(startIndex)+categoryNumber;
   //figure out how far each of the tiles is from the starting tile
   var distances:Array = computePathDistanceOfHTD(startIndex,endIndex,currectCategory);
   if(distances == null)//這裡會把所有的可能畫出來 所以畫出來的路徑其實不止一條
    return null;
   
   //then count backward to find the shortest path.//計算返回的次數找出捷徑
   var points:Array = new Array();
   walkPath(distances,endIndex,points);//這裡找出捷徑上的每個點依序的位置
   
   //reset the start and end points to be exact
   var node:FlxPoint;
   node = points[points.length-1] as FlxPoint;
   node.x = Start.x;
   node.y = Start.y;
   node = points[0] as FlxPoint;
   node.x = End.x;
   node.y = End.y;
   
   //some simple path cleanup options
   if(Simplify)
    simplifyPath(points);
   if(RaySimplify)
    raySimplifyPath(points);
   
   //finally load the remaining points into a new path object and return it
   var path:FlxPath = new FlxPath();
   var i:int = points.length - 1;
   while(i >= 0)
   {
    node = points[i--] as FlxPoint;
    if(node != null)
     path.addPoint(node,true);
   }
   return path;//path 中的node真的是node,所以會減化點,就只有轉折處會記錄下來成node
  }
  
  protected function computePathDistanceOfHTD(StartIndex:uint, EndIndex:uint,currectCategory:uint):Array
  {
   //Create a distance-based representation of the tilemap.
   //All walls are flagged as -2, all open areas as -1.
   var mapSize:uint = widthInTiles*heightInTiles;
   var distances:Array = new Array(mapSize);
   var i:int = 0;
   while(i < mapSize)
   {
    if(_data[i]==currectCategory||_data[i]==(currectCategory+categoryNumber))
     distances[i] = -1;//有路設為-1
    else
     distances[i] = -2;//沒路設為-2
    i++;
   }
   distances[StartIndex] = 0;//起點設為0
   var distance:uint = 1;
   var neighbors:Array = [StartIndex];
   var current:Array;
   var currentIndex:uint;
   var left:Boolean;
   var right:Boolean;
   var up:Boolean;
   var down:Boolean;
   var currentLength:uint;
   var foundEnd:Boolean = false;
   while(neighbors.length > 0)
   {
    current = neighbors;
    neighbors = new Array();
    
    i = 0;
    currentLength = current.length;
    while(i < currentLength)
    {
     currentIndex = current[i++];
     if(currentIndex == EndIndex)
     {
      foundEnd = true;
      neighbors.length = 0;
      break;
     }
     
     //basic map bounds
     left = currentIndex%widthInTiles > 0;
     right = currentIndex%widthInTiles < widthInTiles-1;
     up = currentIndex/widthInTiles > 0;
     down = currentIndex/widthInTiles < heightInTiles-1;
     
     var index:uint;
     if(up)
     {
      index = currentIndex - widthInTiles;
      if(distances[index] == -1)
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(right)
     {
      index = currentIndex + 1;//如果往右 index就+1
      if(distances[index] == -1)//如果右邊那格是-1代表能走
      {
       distances[index] = distance;//就將那一格設為1
       neighbors.push(index);
      }
     }
     if(down)
     {
      index = currentIndex + widthInTiles;
      if(distances[index] == -1)
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(left)
     {
      index = currentIndex - 1;
      if(distances[index] == -1)
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(up && right)
     {
      index = currentIndex - widthInTiles + 1;
      if((distances[index] == -1))
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(right && down)//右下
     {
      index = currentIndex + widthInTiles + 1;
      if((distances[index] == -1))
      {//如果右下那格可以走,並且要滿足 下面跟右邊都同時能走
       //在這裡 因為上面right跟down都已加入路徑,所以行走的方式會是先右在下
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(left && down)
     {
      index = currentIndex + widthInTiles - 1;
      if((distances[index] == -1))
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
     if(up && left)
     {
      index = currentIndex - widthInTiles - 1;
      if((distances[index] == -1))
      {
       distances[index] = distance;
       neighbors.push(index);
      }
     }
    }
    distance++;
   }
   if(!foundEnd)
    distances = null;
   return distances;
  }
 }
}
source code

沒有留言:

張貼留言