Pathfind with camera
/**
* Copyright NewKrok ( http://wonderfl.net/user/NewKrok )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/oJM8
*/
package {
import flash.display.Shape;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import caurina.transitions.Tweener;
public class PathFinder extends Sprite {
private const degree60:Number = Math.PI / 6;
private const SQRT3:Number = Math.sqrt(3);
static private const numCols:Number = 50;
static private const numRows:Number = 50;
private var cellSize:int = 10;
private var _grid:Grid;
private var _player:Sprite;
private var _floor:Sprite;
private var _path:Array;
private var _index:Number;
private var cells:Array;
public function PathFinder() {
makeGrid();
makePlayer();
addEventListener(MouseEvent.CLICK, onGridClick);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function makePlayer():void {
_player = new Sprite();
_player.graphics.lineStyle(1,0,1)
_player.graphics.beginFill(0x00FF00);
_player.graphics.drawCircle(0, 0, 7);
_player.graphics.endFill();
_player.graphics.moveTo( 0, 0 )
_player.graphics.lineTo( 7, 0 )
var i:int = Math.floor(Math.random() * numCols);
var j:int = Math.floor(Math.random() * numRows);
_player.x = dx * i + dx * j / 2 + cellSize;
_player.y = dy * j + radius;
addChild(_player);
}
private function makeGrid():void {
_floor = new Sprite();
//_floor.addChild ( new GrassBack )
addChild(_floor);
_grid = new Grid(numCols, numRows);
var n:int = numCols * numRows * 2 / 9;
for (var i:int = 0; i < n; i++) {
_grid.setWalkable(Math.floor(Math.random() * numCols),
Math.floor(Math.random() * numRows),
false);
}
drawGrid();
}
private function drawGrid():void {
cells = new Array();
var white:Shape = makeHex(radius, 0xffffff);
var black:Shape = makeHex(radius, 0x000000);
for (var i:int = 0; i < _grid.numCols; i++) {
cells[i] = new Array();
for (var j:int = 0; j < _grid.numRows; j++) {
var node:Node = _grid.getNode(i, j);
var hex:Shape = new Shape();
if (!node.walkable) {
hex.graphics.copyFrom(black.graphics);
}else{
hex.graphics.copyFrom(white.graphics);
}
_floor.addChild(hex);
cells[i][j] = hex;
hex.x = dx * i + dx * j / 2 + cellSize;
hex.y = dy * j + radius;
}
}
}
private function onGridClick(event:MouseEvent):void {
var mouse:Point = localToGlobal(new Point(mouseX - x, mouseY - y));
for (var i:int = 0; i < _grid.numCols; i++) {
for (var j:int = 0; j < _grid.numRows; j++) {
var hex:Shape = cells[i][j];
if (hex.hitTestPoint(mouse.x, mouse.y, true)) _grid.setEndNode(i, j);
if (hex.hitTestPoint(_player.x, _player.y, true)) _grid.setStartNode(i, j);
}
}
findPath();
}
private function findPath():void {
var astar:AStar = new AStar();
if (astar.findPath(_grid)) {
_path = astar.path;
_index = 1;
_player.rotation = Math.atan2 ( _path[_index].y - _path[_index - 1].y, _path[_index].x - _path[_index - 1].x ) / ( Math.PI / 180 )
if ( _player.rotation == 90 )
_player.rotation = 60
if ( _player.rotation == -90 )
_player.rotation = -120
ttt ()
}
}
private function ttt ():void {
var i:int = _path[_index].x;
var j:int = _path[_index].y;
Tweener.addTween ( _player, { x: cells[i][j].x, y: cells[i][j].y, time: .3, transition: "linear", onComplete: function ():void {
_index++;
if ( _index < _path.length ) {
_player.rotation = Math.atan2 ( _path[_index].y - _path[_index - 1].y, _path[_index].x - _path[_index - 1].x ) / ( Math.PI / 180 )
if ( _player.rotation == 90 )
_player.rotation = 60
if ( _player.rotation == -90 )
_player.rotation = -120
ttt()
}
} } )
}
import caurina.transitions.Tweener
public var camP:Point = new Point ( 0, 0 )
private function onEnterFrame(event:Event):void {
this.x += ( ( -_player.x + _player.width / 2 + stage.stageWidth / 2 ) - camP.x ) / 20
this.y += ( ( -_player.y + _player.height / 2 + stage.stageHeight / 2 ) - camP.y ) / 20
camP.x = this.x
camP.y = this.y
}
private function xyToAxis(x:int, y:int):Object{
var axis:Object = new Object();
if (x * y >= 0) {
axis.a = 0;
axis.b = x;
axis.c = y;
}else {
if (Math.abs(x) > Math.abs(y)) {
axis.a = x + y;
axis.b = 0;
axis.c = -y;
} else {
axis.a = 0;
axis.b = x + y;
axis.c = 2 * x + y;
}
}
return axis;
}
private function axisToXY(a:int, b:int, c:int):Object {
var xy:Object = new Object();
xy.x = a + c;
xy.c = -a + c;
return xy;
}
private function makeHex(radius:Number,color:uint = 0xffffff):Shape {
var hex:Shape = new Shape();
hex.graphics.lineStyle(0);
hex.graphics.beginFill(color);
hex.graphics.moveTo(radius * Math.cos(degree60), radius * Math.sin(degree60));
for (var i:int = 1; i <= 6; i++) {
var x:Number = radius * Math.cos((2 * i + 1) * degree60);
var y:Number = radius * Math.sin((2 * i + 1) * degree60);
hex.graphics.lineTo(x, y);
}
hex.graphics.endFill();
return hex;
}
private function get dx():Number{
return 2 * cellSize;
}
private function get dy():Number {
return SQRT3 * cellSize;
}
private function get radius():Number {
return dy * 2 / 3;
}
}
}
class AStar
{
private var _grid:Grid;
private var _open:Array;
private var _closed:Array;
private var _startNode:Node;
private var _endNode:Node;
private var _path:Array;
private var _heuristic:Function = diagonal;
private var _straightCost:Number = 1.0;
public function AStar()
{
}
public function findPath(grid:Grid):Boolean
{
_grid = grid;
_open = new Array();
_closed = new Array();
_startNode = _grid.startNode;
_endNode = _grid.endNode;
_startNode.g = 0;
_startNode.h = _heuristic(_startNode);
_startNode.f = _startNode.g + _startNode.h;
return search();
}
private function search():Boolean
{
var node:Node = _startNode;
while (node != _endNode)
{
var startX:int = Math.max(0, node.x - 1);
var endX:int = Math.min(_grid.numCols - 1, node.x + 1);
var startY:int = Math.max(0, node.y - 1);
var endY:int = Math.min(_grid.numRows - 1, node.y + 1);
for (var i:int = startX; i <= endX; i++)
{
for (var j:int = startY; j <= endY; j++)
{
var test:Node = _grid.getNode(i, j);
if ((i - node.x) * (j - node.y) > 0)
continue;
if (test == node || !test.walkable)
continue;
var cost:Number = _straightCost;
var g:Number = node.g + cost;
var h:Number = _heuristic(test);
var f:Number = g + h;
if (isOpen(test) || isClosed(test))
{
if (test.f > f)
{
test.f = f;
test.g = g;
test.h = h;
test.parent = node;
}
}
else
{
test.f = f;
test.g = g;
test.h = h;
test.parent = node;
_open.push(test);
}
}
}
_closed.push(node);
if (_open.length == 0)
{
trace("no path found");
return false;
}
_open.sortOn("f", Array.NUMERIC);
node = _open.shift() as Node;
}
buildPath();
return true;
}
private function buildPath():void
{
_path = new Array();
var node:Node = _endNode;
_path.push(node);
while (node != _startNode)
{
node = node.parent;
_path.unshift(node);
}
}
public function get path():Array
{
return _path;
}
private function isOpen(node:Node):Boolean
{
for (var i:int = 0; i < _open.length; i++)
{
if (_open[i] == node)
{
return true;
}
}
return false;
}
private function isClosed(node:Node):Boolean
{
for (var i:int = 0; i < _closed.length; i++)
{
if (_closed[i] == node)
{
return true;
}
}
return false;
}
private function diagonal(node:Node):Number
{
var dx:Number = node.x - _endNode.x;
var dy:Number = node.y - _endNode.y;
var distance:Number = Math.abs(dx + dy);
var A_axis:Number = (Math.abs(dx - dy) - distance) / 2;
if (A_axis > 0)
{
distance += A_axis;
}
return distance * _straightCost;
}
public function get visited():Array
{
return _closed.concat(_open);
}
}
class Grid
{
private var _startNode:Node;
private var _endNode:Node;
private var _nodes:Array;
private var _numCols:int;
private var _numRows:int;
public function Grid(numCols:int, numRows:int)
{
_numCols = numCols;
_numRows = numRows;
_nodes = new Array();
for (var i:int = 0; i < _numCols; i++)
{
_nodes[i] = new Array();
for (var j:int = 0; j < _numRows; j++)
{
_nodes[i][j] = new Node(i, j);
}
}
}
public function getNode(x:int, y:int):Node
{
return _nodes[x][y] as Node;
}
public function setStartNode(x:int, y:int):void
{
_startNode = _nodes[x][y] as Node;
}
public function setEndNode(x:int, y:int):void
{
_endNode = _nodes[x][y] as Node;
}
public function setWalkable(x:int, y:int, value:Boolean):void
{
_nodes[x][y].walkable = value;
}
public function get numRows():int
{
return _numRows;
}
public function get numCols():int
{
return _numCols;
}
public function get endNode():Node
{
return _endNode;
}
public function get startNode():Node
{
return _startNode;
}
}
class Node
{
public var x:int;
public var y:int;
public var f:Number;
public var g:Number;
public var h:Number;
public var walkable:Boolean = true;
public var parent:Node;
public function Node(x:int, y:int)
{
this.x = x;
this.y = y;
}
}