PDA

Volledige versie bekijken : [AS 2.0] A* pathfinding , geoptimaliseerd voor flash


Dauntless
%Europe/Berlin %633 %2005, 16:12
Haai!

Sommigen zullen dit topic nog wel kennen van het vorige forum. Wel, nu met GreenVille had ik weer een A* nodig, maar een leuke snelle dus heb ik hem terug vanaf 0 herschreven :D .Voor degene die het niet kennen: A* is een pathfinding algoritme: het zoekt de korste weg van A naar B en liefst zo snel en kort mogelijk. Omdat A* flexibel is kan je ook verschillende terrein costen per tegel zetten zodat hij bv eerder via een weg rond een moeras gaat, dan erdoor.

De Astar op zich bestaat uit 3 classes: Tile, Astar en BinaryHeap.
Ik heb hem gebrouwd zodat hij echt dynamisch is en zodat anderen (jullie) er ook gebruik van kunnen maken. Ik heb alles ook zo goed mogelijk gedocumenteerd en de documentatie staat dus ook online.

Classes

Tile class:
import be.dauntless.Astar.*;

class be.dauntless.Astar.Tile
{

private var inOpen:Boolean = false;
private var closed:Boolean = false;

private var parent:Tile;

private static var ids:Number = 0;

private var gUp:Boolean = false;


private var h:Number;
private var g:Number;

private var cost:Number = Astar.standardCost;

public var x:Number;
public var y:Number;
public var id:Number;
public var walkable:Boolean = true;

/*
* Function: Tile
* Constructor. Set the x, y and cost of the tile;
*
* Parameters:
*
* x - x position of the tile;
* y - y position of the tile;
* cost - cost of the tile;
*
* Returns:
*
* Nothing
*/
public function Tile(xp:Number, yp:Number, cost:Number){
x = xp;
y = yp;
id = ids++;
this.cost = cost;
}

/*
* Function: setWalkable
* Set the ability to walk on this the tile
*
* Parameters:
*
* walkable - Boolean value whether or not the tile is walkable
*
* Returns:
*
* Nothing
*/
public function setWalkable(b:Boolean):Void
{
walkable = b;
}


/*
* Function: setOpen
* Set this tile to be in the open-array. This is used by the findPath method of the Astar class.
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*
* See also:
*
* <setClosed>
*
* <setWalkable>
*/
public function setOpen():Void
{
inOpen = true;
closed = false;
}

/*
* Function: setClosed
* Set this tile to be in the closed-array. This is used by the findPath method of the Astar class.
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*
* See also:
*
* <setOpen>
*
* <setWalkable>
*/

public function setClosed():Void
{
inOpen = false;
closed = true;
}

/*
* Function: isClosed
* returns whether or not the tile is in the closed list.
*
* Parameters:
*
* None
*
* Returns:
*
* closed - Boolean representing whether or not its closed
*/

public function isClosed():Boolean
{
return closed;
}

/*
* Function: getOpen
* returns whether or not the tile is in the open list.
*
* Parameters:
*
* None
*
* Returns:
*
* open - Boolean representing whether or not its open
*/

public function getOpen():Boolean
{
return inOpen;
}

/*
* Function: setParent
* sets the parent of the node
*
* Parameters:
*
* Tile - Parent of the node
*
* Returns:
*
* Nothing
*/

public function setParent(tile:Tile):Void
{
parent = tile;
}

/*
* Function: getParent
* Returns the parent of the node
*
* Parameters:
*
* None
*
* Returns:
*
* The parent of the node
*/

public function getParent():Tile
{
return parent;
}

/*
* Function: setH
* sets the H for the node. H is calculated with the manhatten method.
*
* Parameters:
*
* bx - number representing the x position of the tile
* by - number representing the y position of the tile
* ex - number representing the x position of the endPoint
* ey - number representing the y position of the endPoint
*
* Returns:
*
* Nothing
*/

public function setH(bx:Number, by:Number, ex:Number, ey:Number):Void
{
h = Math.abs(ex - bx) * cost + Math.abs(ey - by) * cost;
}

/*
* Function: setG
* Sets the G (cost) for the tile
*
* Parameters:
*
* g - the cost of the parent tile
*
* Returns:
*
* Nothing
*/

public function setG(_g:Number):Void
{
g = _g + getCost();
}

/*
* Function: getF
* Returns the F of the tile (F = G + H);
*
* Parameters:
*
* None
*
* Returns:
*
* F - The F of the tile
*/
public function getF():Number
{
return this.getG() + h;
}

/*
* Function: getH
* Returns the H of the tile
*
* Parameters:
*
* None
*
* Returns:
*
* H - The H of the tile
*/
public function getH():Number
{
return h;
}

/*
* Function: setCost
* Set the cost for the tile
*
* Parameters:
*
* cost - cost of the tile
*
* Returns:
*
* Nothing
*/

public function setCost(_cost:Number):Void
{
cost = _cost;
}

/*
* Function: getG
* get the G (cost) of the tile
*
* Parameters:
*
* None
*
* Returns:
*
* g - the total cost of the tile
*/


public function getG():Number
{
return g;
}

/*
* Function: getCost
* Returns the cost for the tile
*
* Parameters:
*
* None
*
* Returns:
*
* cost - the cost of the tile
*/

public function getCost():Number
{
var addCost:Number = (gUp)?1.414:1;
return cost * addCost;
}

/*
* Function: toggleWalkable
* Toggles the ability to walk on the tile
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function toggleWalkable():Void
{
this.walkable = !this.walkable;
}


/*
* Function: reset
* This method resets the tile for further use
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function reset():Void
{
this.inOpen = false;
this.closed = false;
this.closed = false;
this.parent = null;
this.h = null;
this.g = null;
this.gUp = false;
}

/*
* Function: costUp
* This method tells the node that its being accessed diagonally
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function costUp():Void
{
this.gUp = true;
}

/*
* Function: costDown
* This method tells the node that its NOT being accessed diagonally
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function costDown():Void
{
this.gUp = false;
}

/*
* Function: notice
* This method is called by A*. It tells the tile that it's in the found path.
* This can be used when you extend the tile class.
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function notice():Void
{
//does nothing.
}
}




Astar class:
import be.dauntless.Astar.Tile;
import be.dauntless.Astar.BinaryHeap;

class be.dauntless.Astar.Astar
{

private var startPoint:Array;

private var endPoint:Array;

private var map:Array;

public static var standardCost:Number = 1;

private var mapH:Number;

private var mapW:Number;

private var clipping:Boolean = false;

private var heap:BinaryHeap;

/*
* Function: Astar (constructor)
* Constructor, sets 'clipping'
*
* Parameters:
*
* clipping - Boolean indicating whether or not clipping is aloud.
*
* Returns:
*
* Nothing
*/
public function Astar(c:Boolean)
{
clipping = c;
}

/*
* Function: setMap
* Set the map for the engine
*
* Parameters:
*
* _map - A 2d array of references to tiles, presenting the current map
*
* Returns:
*
* Nothing
*
* See Also:
*
* <setStartPoint>
*
* <setEndPoint>
*/
public function setMap(_map:Array):Void
{
this.map = new Array();
this.map = _map;
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}

/*
* Function: newMap
* Build a new Map
*
* Parameters:
*
* x - width of the map
* y - height of the map
*
* Returns:
*
* Nothing
*
* See Also:
*
* <setMap>
*/
public function newMap(w:Number, h:Number):Void
{
w = Math.floor(w);
h = Math.floor(h);
this.map = new Array();
for (var y = 0; y<h; y++)
{
map[y] = new Array();
for (var x = 0; x<w; x++)
{
var tile:Tile = new Tile(x, y, Astar.standardCost);
map[y][x] = tile;
}
}
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}

/*
* Function: setStartPoint
* Set the stating point (player position) for the engine
*
* Parameters:
*
* x - the x position of the player
* y - the y position of the player
*
* Returns:
*
* Nothing
*
* See Also:
*
* <setEndPoint>
*
* <setMap>
*/
public function setStartPoint(x:Number, y:Number):Void
{
this.startPoint = new Array();
this.startPoint[0] = x;
this.startPoint[1] = y;
}

/*
* Function: setEndPoint
* Set the map for the engine
*
* Parameters:
*
* x - the x position of the player
* y - the y position of the players
*
* Returns:
*
* Nothing
*
* See Also:
*
* <setStartPoint>
*
* <setMap>
*/
public function setEndPoint(x:Number, y:Number):Void
{
this.endPoint = new Array();
this.endPoint[0] = x;
this.endPoint[1] = y;
}

/*
* Function: findPath
* find a path from the startPoint to the endPoint in the given map
*
* Parameters:
*
* None
*
* Returns:
*
* array/Boolean - array containing references of tiles presenting the path from startpoint to endpoint OR false if no path was found.
*
*
*
* See Also:
*
* <setStartPoint>
*
* <setEndPoint>
*
* <setMap>
*/
public function findPath():Object
{
//if you reuse the same tiles, the tiles will be closed. So we need to open all the tiles:
openMap();

if(!ready()) return false;

//the binary heap
heap = new BinaryHeap();

//there is no path found yet
var pathFound:Boolean = false;

//start off with the first tile (startPoint).
//set it to open, calculate its G (0, 'cause it IS the startpoint), and H.
//and add that tile to the open array
var beginTile:Tile = map[startPoint[1]][startPoint[0]];

beginTile.setOpen();
beginTile.setG(0);
beginTile.setH(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
beginTile.setParent(beginTile);
heap.addToHeap(beginTile);

//as long as there is a tile that can be visited and no path is found...
//(if open is empty, there is no solution)
while(heap.getLength() > 0 && !pathFound)
{
// the current-array always represents the current tile
var current:Tile = getLowestFTile();

//check if the path is found (current tile = end tile)
if(current.x == endPoint[0] && current.y == endPoint[1])
{
trace("Path was found");
pathFound = true;
break;
}

// remove the current object from the open-array
current.setClosed();

//find all the surrounding nodes
var neighbours:Array = findSurroundingTiles(current);
for(var i in neighbours)
{

//if this neighbour is not in the open-array
if(!neighbours[i].getOpen())
{
//add this neighbour to the open-array
//and calculate all the needed settings.
neighbours[i].setOpen();
neighbours[i].setParent(current);
neighbours[i].setH(neighbours[i].x, neighbours[i].y, endPoint[0], endPoint[1]);
neighbours[i].setG(current.getG());
heap.addToHeap(neighbours[i]);

} else {
//calculate new F. If the new F is smaller, that means the way to this node trough
//the currentnode is shorter. So update that node to make current node its parent
//and calculate new G.
var tempF:Number = neighbours[i].getH() + current.getG() + neighbours[i].getCost();
if(tempF < neighbours[i].getF())
{
var id = neighbours[i].id;
neighbours[i].setParent(current);
neighbours[i].setG(current.getG());
heap.updateList(heap.getPosition(id));
}
}
}
}

//if the open array is empty, no path was found
if(heap.getLength() == 0 && !pathFound){
trace("There is no path!");
return false;

}

//the path is calculated, so now we have to start at the end and work our way back:
var path:Array = new Array();
var px:Number = endPoint[0]; //pathX;
var py:Number = endPoint[1]; //pathY;
map[px][py].notice();
path.push(map[py][px]);
var parent:Tile = map[py][px].getParent();
px = parent.x; //pathX;
py = parent.y;

//as long as one of the two cordinates still isn't the same as the start point, continue
while (px != startPoint[0] || py != startPoint[1])
{
path.push(map[py][px]);

//notice the tile
map[py][px].notice();

//request next parent
parent = map[py][px].getParent();

//map[py][px] returns the tile; getParent() returns its parent and x the x property of the tiles parent
px = parent.x;
py = parent.y

}


//and put the startPoint in there too
path.push(map[startPoint[1]][startPoint[0]]);

//notice start tile
map[startPoint[1]][startPoint[0]].notice();

//we started at the endpoint, so now we have to reverse the array
path.reverse();

//and now we're all done so return the path!!!
return path;
}

/*
* Function: getLowestFTile
* find the tile in the open-array with the lowest F (best node to look at next).
*
* Parameters:
*
* None
*
* Returns:
*
* Tile - Reference to the tile with the lowest F
*
*/
private function getLowestFTile():Tile
{
return heap.getLowest();
}

/*
* Function: findSurroundingTiles
* find the surrounding tiles of the given tile. If clipping is set to true,
* 8 tiles will be scanned. If not: 4 tiles.
*
*
* Parameters:
*
* x - the x value of the tile
*
* Returns:
*
* array - array containing references to all the valid neighbour tiles
*/
private function findSurroundingTiles(current:Tile):Array
{
var st:Array = new Array(); //st = surroundingTiles
var x:Number = current.x;
var y:Number = current.y;

//check left, right, down and up. Check: walkable & not closed
if(map[y][x-1].walkable && !map[y][x-1].isClosed() )
{
st.push(map[y][x-1]);
map[y][x-1].costDown();
}
if(map[y][x+1].walkable && !map[y][x+1].isClosed() )
{
st.push(map[y][x+1]);
map[y][x+1].costDown();
}
if(map[y+1][x].walkable && !map[y+1][x].isClosed() )
{
st.push(map[y+1][x]);
map[y+1][x].costDown();
}
if(map[y-1][x].walkable && !map[y-1][x].isClosed() )
{
st.push(map[y-1][x]);
map[y-1][x].costDown();
}

if(clipping){
//check left-up, left-down, right-up and right-down. Check: walkable & not closed
if(map[y-1][x-1].walkable && !map[y-1][x-1].isClosed() )
{
st.push(map[y-1][x-1]);
map[y-1][x-1].costUp();
}
if(map[y-1][x+1].walkable && !map[y-1][x+1].isClosed() )
{
st.push(map[y-1][x+1]);
map[y-1][x+1].costUp();
}
if(map[y+1][x+1].walkable && !map[y+1][x+1].isClosed() )
{
st.push(map[y+1][x+1]);
map[y+1][x+1].costUp();
}
if(map[y+1][x-1].walkable && !map[y+1][x-1].isClosed() )
{
st.push(map[y+1][x-1]);
map[y+1][x-1].costUp();

}
}
return st;
}

/*
* Function: ready
* Check whether or not all the settings are correct
*
* Parameters:
*
* None
*
* Returns:
*
* Boolean - True: Game is ready, false: There was an error
*
*/
private function ready():Boolean
{
if(map == undefined){
trace("No map specified");
return false;
}
if(startPoint[0] != Math.floor(startPoint[0]) || startPoint[1] != Math.floor(startPoint[1]))
{
trace("Startpoint isn't valid");
return false;
}

if(endPoint[0] != Math.floor(endPoint[0]) || endPoint[1] != Math.floor(endPoint[1]))
{
trace("Endpoint isn't valid");
return false;
}

if(startPoint[0] < 0 || startPoint[0] >= mapW)
{
trace("=>"+mapW);
trace("Startpoint isn't valid");
return false;
} else if(startPoint[1] < 0 || startPoint[1] >= mapH){
trace("Startpoint isn't valid");
return false;
}

if(endPoint[0] < 0 || endPoint[0] >= mapW)
{
trace("EndPoint isn't valid");
return false;
} else if(endPoint[1] < 0 || endPoint[1] >= mapH){
trace("EndPoint isn't valid");
return false;
}

if(!map[endPoint[1]][endPoint[0]].walkable){
trace("Endpoint isn't walkable.");
return false;
}
if(!map[startPoint[1]][startPoint[0]].walkable){
trace("Startpoint isn't walkable.");
return false;
}
return true;
}

/*
* Function: setWalkable
* Toggle the tile to be walkable or not
*
* Parameters:
*
* x - x position of the tile
* y - y position of the tile
* walkable - boolean representing the ability to walk on the tile or not
*
* Returns:
*
* Nothing
*
* See also:
*
* <toggleWalkable>
*/
public function setWalkable(x:Number, y:Number, b:Boolean):Void
{
map[y][x].setWalkable(b);
}

/*
* Function: toggleWalkable
* Toggle the tile to be walkable or not
*
* Parameters:
*
* x - x position of the tile
* y - y position of the tile
*
* Returns:
*
* Nothing
*
* See also:
*
* <setWalkable>
*/
public function toggleWalkable(x:Number, y:Number):Void
{
map[y][x].toggleWalkable();
}

/*
* Function: setClipping
* Toggle clipping. Clipping is the ability to move diagonally.
*
* Parameters:
*
* clipping - Boolean representing the ability to use clipping
*
* Returns:
*
* Nothing
*/
public function setClipping(c):Void
{
clipping = c;
}

/*
* Function: openMap
* Opens the map (resets all the tiles)
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
private function openMap(){
for(var y = 0; y<mapH; y++){
for(var x = 0; x<mapW; x++){
map[y][x].reset();
}
}
}
}


BinaryHeap class
import be.dauntless.Astar.Tile;

class be.dauntless.Astar.BinaryHeap
{
private var heap:Array;

/*
* Function: BinaryHeap
* Constructor; makes a new heap array
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function BinaryHeap()
{
heap = new Array(null);
}

/*
* Function: addToHeap
* Adds a tile to the binary heap
*
* Parameters:
*
* Tile - The tile to be added
*
* Returns:
*
* Nothing
*/
public function addToHeap(newTile:Tile):Void
{
heap.push(newTile);
var cp:Number = heap.length-1; //cp = current position
var np:Number = Math.floor(cp/2);

//as long as the item isnt in the first position
while(cp != 1){
if(heap[cp].getF() <= heap[Math.floor(cp/2)].getF()){
//if the current F is lower than or equal to its parent, switch them!
var t:Number = heap[Math.floor(cp/2)];
heap[Math.floor(cp/2)] = heap[cp];
heap[cp] = t;
cp = Math.floor(cp/2);
} else {
//destination reached!
break;
}
}
}

/*
* Function: getLowest
* This method returns the lowest F from the heap. That F is deleted from the heap
*
* Parameters:
*
* None
*
* Returns:
*
* Tile - Tile with the lowest F
*/
public function getLowest():Tile
{
var cp:Number = 1; //current position
var np:Number; //next position
var lowest:Tile = heap[1];
if(heap.length == 2){
heap.pop();
} else {
heap[1] = heap.pop();
}

while(true){
np = cp;
if(cp*2+1 <= (heap.length -1) ){
if(heap[np].getF() >= heap[np*2].getF() ) cp = 2*np;
if(heap[cp].getF() >= heap[np*2+1].getF() ) cp = 2*np+1;
} else if(2*np <= (heap.length -1)){
if(heap[np].getF() >= heap[2*np].getF() ) cp = 2*np;
}

//check if np has changed, 'cause then we have to switch them
if(np != cp){
//switch heap[cp] & heap[np]
var t:Tile = heap[np];
heap[np] = heap[cp];
heap[cp] = t;
} else {
//position found, return!
return lowest;
}
}

}

/*
* Function: getLength
* This method returns the length of the heap
*
* Parameters:
*
* None
*
* Returns:
*
* Nothing
*/
public function getLength():Number
{
return (heap.length -1);
}

/*
* Function: getPosition
* This method returns the position of the given ID in the heap
*
* Parameters:
*
* id - id of the node's position to find
*
* Returns:
*
* Number - position of id in heap
*/
public function getPosition(id):Number
{
for(var i in heap){
if(heap[i].id == id){
return i;
}
}
}

/*
* Function: updateList
* This method changes the given tile's f in the heap and resorts it.
*
* Parameters:
*
* Tile - the tile to be changed
*
* Returns:
*
* Nothing
*/
public function updateList(cp_):Void
{
var cp:Number = cp_;
var np:Number = Math.floor(cp/2);

//as long as the item isnt in the first position
while(cp != 1){
if(heap[cp].getF() <= heap[Math.floor(cp/2)].getF()){
//if the current F is lower than or equal to its parent, switch them!
var t:Number = heap[Math.floor(cp/2)];
heap[Math.floor(cp/2)] = heap[cp];
heap[cp] = t;
cp = Math.floor(cp/2);
} else {
//destination reached!
break;
}
}
}
}

Gebruik

Aangezien dit best wel wat AS is, is het misschien handiger om deze zip te downloaden:
ZIP (http://www.dauntless.be/Projects/Astar/Astar.zip)
In deze zip zit ook de documentatie.

Omdat ik het dus dynamisch wou maken is het puur code en is er niets grafisch aan. Daarom is het het handigst als je de Tile class extend. Op die manier kan je je eigen grafische elementen toevoegen. Een lijst van alle properties en methods staat in de documentatie, dus zorg ervoor dat je die niet overschrijft.

Een voorbeeld om de Tile class te extenden:

class GameTile extends be.dauntless.Astar.Tile
{

private var root:MovieClip;
private var mc:MovieClip;
private static var depth:Number = 0;


public function GameTile(x:Number, y:Number, cost:Number, root:MovieClip)
{
super(x, y, cost);
this.root = root;
mc = root.attachMovie("mc_test", "mc"+x+"_"+y, depth++);
mc._x = x * mc._width;
mc._y = y * mc._height;
mc.costt.text = cost;
}

public function notice():Void
{
mc.nextFrame();
}
}

Als je wil dat er iets met de tile gebeurt moet je de 'notice method' overschrijven. Deze wordt immers aangeroepen bij het bouwen van het pad en in de Tile Class is ze toch gewoon leeg (hier DIENT ze dus voor!). Als je de Tile class extend moet je wel altijd in de constructor super() oproepen met de x, y en cost van de tegel.

Voor zij die het niet weten: Deze class is opgebouwd met packages. Het handigste is om ergens op je computer een dir aan te maken waar je alle classes in wil gaan zetten. Daar zet je dan de 'be' map. In flash kan je bij de instellingen de classpaths aanpassen (en daar voeg je de class dir dan aan toe).

In principe kan je het gebruik helemaal uit de helpfiles nemen, maar 'k zal hier nog maar snel wat AS zetten:

import be.dauntless.Astar.*;
var a:Astar = new Astar(false);
a.newMap(10,10);
a.setStartPoint(0, 0);
a.setEndPoint(5, 8);
var path = a.findPath();
if(!path){
//er werd geen path gevonden
} else {
//hier het path
}

Het path wordt terug gegeven in de vorm van tegels. Om de x en y te krijgen doe je dus: path[i].x of path[i].y


Ik heb m'n best gedaan om hem zo snel mogelijk te krijgen (bv door die binaryHeap), maar als jullie nog dingen weten, zeg het maar. Ohja, daardoor heb ik nu ook geen closed list meer, maar is het gewoon opgeslagen in elke node. Door dit is het dus eigenlijk geen A* meer... Hmm, dan maar m'n eigen naam: D* ! :D

Voor zij die tot hier gelezen hebben: DANKU! :p Voor de anderen: grrrr :mad: (lezen ze dan toch niet :p).

Euhm,
Ik hoop op zoveel mogelijk reacties!

Greets,
Me!

Vinc
%Europe/Berlin %641 %2005, 16:23
Ziet er indrukwekkend uit.. maarre.. wat kan je ermee? :P

Dauntless
%Europe/Berlin %653 %2005, 16:40
Ziet er indrukwekkend uit.. maarre.. wat kan je ermee? :P
Ah crap :D 'k heb m'n post aangepast! :) (vanboven)

Tommyfied
%Europe/Berlin %655 %2005, 16:43
Ziet er strak uit Dauntless, ik kan me het nog wel herinneren van vroeger. Je hebt wel flink zitten optimaliseren. :)

Ik kan alleen de ZIP file niet downloaden (not found on server) ... zou wel even willen kloten met je script.

Qua code ziet alles er goed uit hoor ... zal nog een keer kijken of ik nog wat dingetjes kun bedenken die het sneller maken ... volgens mij is dit iig wel sneller arrayName[arrayLength] = arrayValue ipv arrayName.push(value) om maar vast te beginnen.

Ook zou ik even overal netjes return types defineren (ook Void) dat staat wat netter.

Dauntless
%Europe/Berlin %662 %2005, 16:53
Ziet er strak uit Dauntless, ik kan me het nog wel herinneren van vroeger. Je hebt wel flink zitten optimaliseren. :)
Thx :)

Ik kan alleen de ZIP file niet downloaden (not found on server) ... zou wel even willen kloten met je script. Link aangepast.


Ook zou ik even overal netjes return types defineren (ook Void) dat staat wat netter.
Ik ben het op 1 plaats vergeten! :p

Dauntless
%Europe/Berlin %676 %2005, 17:13
Omdat ik langs msn een verzoek kreeg tot grafische voorstelling van m'n engine, heb ik een paar voorbeeld SWFjes gemaakt.
http://www.dauntless.be/Projects/Astar/

Roenes
%Europe/Berlin %676 %2005, 17:14
Ziet er goed uit. De heap zit ook lekker in elkaar :)

Maar toch ben ik ergens niet tevreden over (je zal ook niet anders verwacht hebben ;)):
Je newMap methode in je Astar class. Die doet dingen die je setMap ook doet:


//setMap
public function setMap(_map:Array):Void
{
this.map = new Array();
this.map = _map;
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}

//newMap
public function newMap(w:Number, h:Number):Void
{
w = Math.floor(w);
h = Math.floor(h);
this.map = new Array();
for (var y = 0; y<h; y++)
{
map[y] = new Array();
for (var x = 0; x<w; x++)
{
var tile:Tile = new Tile(x, y, Astar.standardCost);
map[y][x] = tile;
}
}
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}
Je doet nu eigenlijk de setMap ook in de newMap (ik weet het, setMap is eigenlijk anders bedoelt maar toch). Je kunt setMap dus ook gebruiken in de functie newMap:

public function newMap(w:Number, h:Number):Void
{
w = Math.floor(w);
h = Math.floor(h);
var tempMap = new Array();
for (var y = 0; y<h; y++)
{
tempMap [y] = new Array();
for (var x = 0; x<w; x++)
{
var tile:Tile = new Tile(x, y, Astar.standardCost);
tempMap [y][x] = tile;
}
}
setMap(tempMap);
}
Je hebt nu geen dubbele regels meer. Ook weet je nu cker dat alle vars worden geupdate omdat je setMap aanroept :)

Voor de rest op dit moment niets over te zeggen. Misschien dat ik die heap nog helemaal ga uitpluizen. Wellicht dat ik daar nog iets kan vinden.

Nog wel 1 ding wat me nu te binnen schiet: je kunt de boel nog verder optimaliseren door de for lusjes te veranderen naar de snelle while variant. Dat heb ik destijds bij mijne ook gedaan en dat scheelde toch best een aantal ms! Wellicht de moeite waard.
De while variant (Als ik em me goed herinner)

var i = 10;
while(--i-(-1))
{
//Doe je ding
}
Maar knap staaltje AS2 :)

Eigenlijk wordt ik nu gedwongen om ook wat te plaatsen. ;)

Dauntless
%Europe/Berlin %684 %2005, 17:26
Wat dacht je van dit?
public function setMap(_map:Array):Void
{
this.map = new Array();
this.map = _map;
mapSettings();
}
public function mapSettings():Void
{
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}

public function newMap(w:Number, h:Number):Void
{
w = Math.floor(w);
h = Math.floor(h);
this.map = new Array();
for (var y = 0; y<h; y++)
{
map[y] = new Array();
for (var x = 0; x<w; x++)
{
var tile:Tile = new Tile(x, y, Astar.standardCost);
map[y][x] = tile;
}
}
mapSettings();
}
?


Ziet er goed uit. De heap zit ook lekker in elkaar :) ... Maar knap staaltje AS2 :)
Thx! ! !

Maar toch ben ik ergens niet tevreden over (je zal ook niet anders verwacht hebben ;)): idd, en 't is ook beter zo ;).
Nog wel 1 ding wat me nu te binnen schiet: je kunt de boel nog verder optimaliseren door de for lusjes te veranderen naar de snelle while variant. Dat heb ik destijds bij mijne ook gedaan en dat scheelde toch best een aantal ms! Wellicht de moeite waard.
Ja, ik had geprobeerd om de for loops om te zetten tot while loops, maar om de een of andere duistere rede crashte hij dan... Maar 'k zal het nog eens proberen :).

Eigenlijk wordt ik nu gedwongen om ook wat te plaatsen. ;)
Eerst Tommyfied, nu ik... waar bijf je joh? :D

Fl4sh3r
%Europe/Berlin %692 %2005, 17:37
Ziet er erg goed uit. Ik heb me ook nog ns verdiept in A* ten tijde van die contest (die nooit echt iets geworden is).

Omdat ik langs msn een verzoek kreeg tot grafische voorstelling van m'n engine, heb ik een paar voorbeeld SWFjes gemaakt.

Map met veriabele cost (refresh een paar keer (http://www.dauntless.be/Projects/Astar/var_cost.swf)
Map 1 met clipping (http://www.dauntless.be/Projects/Astar/map1_c.swf)
Map 1 zonder clipping (http://www.dauntless.be/Projects/Astar/map1_nc.swf)
Map 2 met clipping (http://www.dauntless.be/Projects/Astar/map2_c.swf)
Map 2 zonder clipping (http://www.dauntless.be/Projects/Astar/map2_c.swf)

Ik zie in die links toch wat dingen waar ik wat uitleg bij nodig heb...
- Eerst een simpele: die link Map 2 zonder clipping mis een n in de link (map2_nc.swf).
- Ik zie dit als 'optimale' route:
http://download.bleq.nl/image13.png
Is de door mij in blauw aangegeven route niet sneller? (Lagere cost)

Als voor dat laatste een goeie verklaring is vind ik m erg netjes zoals ie nu is, anders... :cool:

Dauntless
%Europe/Berlin %694 %2005, 17:40
Als voor dat laatste een goeie verklaring is vind ik m erg netjes zoals ie nu is, anders... :cool:
Euhm,ja, daar staat een muur :D maar je ziet hem niet... dom van me ... 'k zal het zo meteen aanpassen :p :p.

//EDIT
Ok, aangepast :). (Leeg je cache wel)

Fl4sh3r
%Europe/Berlin %708 %2005, 18:00
Ah, ja... die muur :)

(Cache legen hoeft niet met FireFox :D)

Dauntless
%Europe/Berlin %709 %2005, 18:02
Ah, ja... die muur :)

(Cache legen hoeft niet met FireFox :D)
Vreeeemd, bij mij wel :s:D

Roenes
%Europe/Berlin %713 %2005, 18:07
(Cache legen hoeft niet met FireFox :D)Niet helemaal waar. Dit is gewoon instelbaar ;)

Wat dacht je van dit?
public function setMap(_map:Array):Void
{
this.map = new Array();
this.map = _map;
mapSettings();
}
public function mapSettings():Void
{
this.mapW = this.map[0].length;
this.mapH = this.map.length;
}

public function newMap(w:Number, h:Number):Void
{
w = Math.floor(w);
h = Math.floor(h);
this.map = new Array();
for (var y = 0; y<h; y++)
{
map[y] = new Array();
for (var x = 0; x<w; x++)
{
var tile:Tile = new Tile(x, y, Astar.standardCost);
map[y][x] = tile;
}
}
mapSettings();
}
?
is idd ook een optie. Toch zou ik persoonlijk voor mijn variant kiezen. Maar dit kan ook zeker :)

Tha Narie
%Europe/Berlin %729 %2005, 18:30
Ik wil nog een versie waar alleen no-wall-clipping in zit.
Een hoekje van een muur kan je niet schuin afsnijden, maar een lege ruimte wel.

Roenes
%Europe/Berlin %766 %2005, 19:23
Ik wil nog een versie waar alleen no-wall-clipping in zit.
Een hoekje van een muur kan je niet schuin afsnijden, maar een lege ruimte wel.Hierdoor komt het red alert idee weer boven ;)

Tha Narie
%Europe/Berlin %831 %2005, 20:56
Blizzard-games zijn veel beter, die werkten bij units niet met hokjes, die kon je gewoon op de pixel neerzetten, en die liepen gewoon in een rechte schuine lijn :D

Tommyfied
%Europe/Berlin %864 %2005, 21:44
Ooit Red Alert (2) gespeeld Narie, die units lopen ook wel degelijk echt schuin hoor :P

Tha Narie
%Europe/Berlin %896 %2005, 22:31
Dat kan wel, maar volgens mij was het stilstaan daar nog steeds per vakje. En ook poppetjes waren het altijd netjes 5 per vakje.
Bij Starcraft (1998) waren alle units (lopen + stilstaan) al pixel-based zeg maar.

Tommyfied
%Europe/Berlin %462 %2005, 12:06
Daar heb je helemaal gelijk in ... zelf vond ik dat juist wel handig / vet. Kon je goed georganiseerde legers maken en muren van mirage tanks e.d. ;)

(maargoed dit wordt een beetje off-topic)

kH_
%Europe/Berlin %794 %2005, 20:04
VET relaxt Dauntless. Ik heb hier nog mee ge-experimenteerd op school tijdens een Robotica project, maar dan in Java....maarja....het algoritme zelf kan natuurlijk in zowat elke taal geimplementeerd worden.
Het algoritme is ook super-handig, vooral ook voor navigatie-systemen (zoals TT ;)), al zijn daarbij de kosten-functies wel dusdanig geoptimaliseerd dat niet alle mogelijkheden afgelopen worden (bij bepaalde kosten-functies worden ALLE mogelijkheden doorlopen, das nie handig natuurlijk :))

Mooi gedaan :cool:

Dauntless
%Europe/Berlin %928 %2005, 23:16
VET relaxt Dauntless. ...Mooi gedaan :cool:
Bedankt! :) :)

En deze A* is ook geoptimaliseerd voor die F'en te sorteren. Door die binary heap wordt een F direct op de juiste plaats gezet en kan ik gewoon het eerste element van de heap opvragen en die wordt dan de volgende node...:)

Dauntless
%Europe/Berlin %967 %2005, 00:13
BUG UPDATE

In de H methode moet *Astar.standardCost ipv * cost. Hierdoor was de H van een tegel met een cost van bv 4 véél te hoog (4x te hoog dus ;) ).

'k Zal morgen of zo terug de volgende versies online zetten :)

Dauntless
%Europe/Berlin %826 %2005, 20:50
Update van voorbeelden:
http://www.dauntless.be/Projects/Astar .

Hij is dus ook uitgebreid naar wat Narie vroeg: semi clipping...

SaphuA
%Europe/Berlin %420 %2005, 11:05
Erg netjes Dauntless :)
Hij lijkt me erg snel en geordend, mooi werk.
Heb je 't alogrythme zelf van niets af geschreven of heb je een ander gebruikt en deze verbeterd?

Dauntless
%Europe/Berlin %520 %2005, 13:29
A* is een algoritme op zich... Dit is een zeer interessant artikel (http://www.policyalmanac.org/games/aStarTutorial.htm). Maar ik heb die open en closed list er dus uitgehaalt en zodus is het geen A* meer... Maar hij doet wat hij moet doen en hij is relatief snel, dus ik klaag niet :D.

Ik zal vanavond ook eens mijn 'aangepaste' algoritme hier zetten...

matzo
%Europe/Berlin %905 %2005, 22:44
Is dit nu wat er in een GPS zit, maar dan een versimpelde versie met minder tiles.

Dauntless
%Europe/Berlin %920 %2005, 23:05
Ik denk dat er in een GPS systeem een heel ander pathfinding algoritme zit... Ik heb het mezelf ook al eens liggen afvragen, maar bv: hij moet ook rekening houden met enkel-richting en zo... Dat gaat niet echt met dit algoritme...

Roenes
%Europe/Berlin %947 %2005, 23:44
Ik kan me niet voorstellen dat GPS werkt met zo'n relatief simpel algoritme :)

Tha Narie
%Europe/Berlin %964 %2005, 00:09
Jij bedoelt navigatie neem ik aan? GPS zelf is alleen het kijken dmv een satteliet waar je BENT :P

flashfreak
%Europe/Berlin %965 %2005, 00:10
tis nu eenmaal Global Positioning System he
Daunty, zou wel een mooie uitdaging zijn, probber een navigatiealgotje te schrijven.

Dauntless
%Europe/Berlin %967 %2005, 00:13
tis nu eenmaal Global Positioning System he
Daunty, zou wel een mooie uitdaging zijn, probber een navigatiealgotje te schrijven.
Wauw, jij bent zot :D Moet ik dan beginnen met eerst de straten atlas beginnen en alles na te tekenen? :D :D

flashfreak
%Europe/Berlin %968 %2005, 00:14
nee zot, gwn, je maakt een tilebased mapje, whater da het is, laat de gebruiker kiezen van waar naar waar en berekend de kortste weg...
makkelijk beginnen he

Roenes
%Europe/Berlin %969 %2005, 00:16
nee zot, gwn, je maakt een tilebased mapje, whater da het is, laat de gebruiker kiezen van waar naar waar en berekend de kortste weg...
makkelijk beginnen heDit heeft hij al gemaakt met A* ;)

flashfreak
%Europe/Berlin %970 %2005, 00:17
ja kan niet kiezen van waar naar waar he...
en ook werken met bepaalde verplichtingen zoals doodlopend etc

Dauntless
%Europe/Berlin %970 %2005, 00:17
Als dat het enige punt is, dan ben ik klaar :p.

Dat is wat hij nu toch doet... ? Je maakt een tilebased mapje (dmv muren / costs) en je kan zelf kiezen waar je vertrekt en stopt...

[m]
%Europe/Berlin %105 %2005, 03:31
Met waypoints in een array stoppen, dan ben je er al een stuk verder.

Trouwens, zo'n wijs-mij-de-weg programma zal daar echt geen superingewikkeld algorithme voor gebruiken. Die heeft kaarten waarop alle mogelijke wegen va punt naar punt al zijn beschreven met snelheidslimiet en lengte. Beetje sleutelen aan de code zodat hij altijd eerst begint met het zoeken naar een geschikte snelweg (vermindert een hoop rekentijd) en je bent klaar. :) alleen is het dan niet tile-based, maar een dikke tree.

Ik heb eens een demo gezien van microsoft dat realtime filedata in een routeplanner had ingebouwd en op een pda gezet had. Dat was erg tof. :)

Flashingback
%Europe/Berlin %467 %2005, 12:12
http://www.werkenmenenpoort.be/ ik weet aleen niet honderd procent zeker of het ook met zo een algoritme is maar ik vermoed van wel

[m]
%Europe/Berlin %600 %2005, 15:24
http://www.werkenmenenpoort.be/ ik weet aleen niet honderd procent zeker of het ook met zo een algoritme is maar ik vermoed van wel

Dat is tof gedaan!

Voor de mensen die willen weten hoe het is gedaan:

kaart + cost: http://www.werkenmenenpoort.be/routeplan.xml
lijst van ondernemers: http://www.werkenmenenpoort.be/ondernemers_xml.php

Tommyfied
%Europe/Berlin %453 %2005, 11:53
Dat is erg leuk gedaan! :) Dit lijkt me iets waarbij je flink kan scoren bij bedrijven. :) (Als je zoiets maken kan ipv een statische contact page)

[m]
%Europe/Berlin %573 %2005, 14:45
Dat is erg leuk gedaan! :) Dit lijkt me iets waarbij je flink kan scoren bij bedrijven. :) (Als je zoiets maken kan ipv een statische contact page)

Ik zeg: maak het en zorg dat je er een cijfer voor krijgt. ;)


(PS niet doen, want dan moet je bij elke project net zo'n uberding produceren :( )

Tommyfied
%Europe/Berlin %629 %2005, 16:05
Hahaha ja laat ik maar niet meteen de lat zo abnormaal hoog leggen in jaar 1 he :P

[m]
%Europe/Berlin %878 %2005, 22:05
ik spreek uit ervaring; doe net alsof je nergens van weet maar wel van alles wilt leren, mag je ook nog eens andere rollen spelen in de groepsopdrachten. ;)

Gollum
%Europe/Berlin %452 %2006, 10:51
Ik heb nu ff geen tijd om alles door te lezen. Maar ik heb een vraagje: waar zijn die cijfertjes voor? Vooral bij het random-voorbeeld. Overigens, cool!

Dauntless
%Europe/Berlin %695 %2006, 16:41
Die random cijfertjes geven de cost van de tile weer. Stel bv dat je van het linkerpunt van een moeras naar het rechterpunt wilt. Als je het moeras een hogere cost geven, dan zal hij eerder voor het pad (de weg met een veel lagere cost) kiezen, omdat dat in totaal hem minder 'moeite' kost.

Chrono
%Europe/Berlin %505 %2006, 12:07
Kan iemand mij vertellen hoe ik dit actionscript het best kan leren begrijpen?
Ik script wel wat voor simpele game'pjes in Flash 5, maar ik snap veel van de code hierboven niet. Alvast bedankt.
Chrono P)

Dauntless
%Europe/Berlin %547 %2006, 13:08
Je kan deze classes pas gebruiken vanaf flash MX 04 (niet?) . Ik denk dat het nog niet mogelijk is om custom classes in Flash 5 te gebruiken...

Flash 5 is overigens een erg oude versie! Je zou eens moeten upgraden :).

Als je het AS wil begrijpen: daar ben je nogal weinig mee, aangezien je er zelf niets mee zou kunnen doen. Ik heb dit geschreven in AS 2.0 en die is dus pas beschikbaar vanaf flash MX 04.

De algemene gedachtengang achter A* vind je hier: http://www.policyalmanac.org/games/aStarTutorial.htm
Maar ik heb hem wel aangepast om hem zo snel mogelijk te krijgen, dus het is geen complete A* meer :).

FredericCox
%Europe/Berlin %577 %2006, 13:51
Indrukwekkend Dauntless, waar heb je je basis gehaald over Classes en OOP? Wil daar na mijn examens ook eens mee beginnen

Fatty Owl
%Europe/Berlin %607 %2006, 14:35
verschrikkelijk betekend toch verschrikkelijk leuk hé [}:|]

Dauntless
%Europe/Berlin %694 %2006, 16:39
Vind je het geen leuk project, FO ? :D Ging je er btw zelf ook geen maken ? :)

En Essential ActionScript 2.0 is mijn bijbel ;).

Fatty Owl
%Europe/Berlin %715 %2006, 17:09
whaha ik kon me zelfs niet herrinneren dat ik gestemd had, maar blijkbaar toch wel :p.
Mijn (unfinished) pathfinder fla ligt onder het stof.

Dauntless
%Europe/Berlin %716 %2006, 17:12
Geef je zo snel al op ? :O :p. Je mag gerust de mijne gebruiken hoor... Alhoewel, jij stemde voor 'verschrikkelijk' .... [}:|]

Chrono
%Europe/Berlin %510 %2006, 12:15
jammer...

goety
%Europe/Berlin %380 %2006, 09:07
klein foutje waardoor hij pak te traag performed, zoekt nu in feite alle tegengestelde tiles eerst af !!

setH functie in findPath
beginTile.setH(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
4 parameters

whereas in tile.as

public function setH(ex:Number, ey:Number):Void{
h = Math.abs(ex - x) * Astar.standardCost + Math.abs(ey - y) * Astar.standardCost;
}
2 parameters

setH in findPath moet geloof ik enkel de endPoints meegeven.
am I correct ?

Dauntless
%Europe/Berlin %539 %2006, 12:56
Wauw, je hebt idd m'n classes grondig zitten doorpluizen :D.

En je hebt gelijk! Hij moet het eindpunt meegeven... En ik kan me inderdaad goed inbeelden dat hij daardoor nog veel te traag is !!

Ik ga het vanmiddag allemaal zitten uittesten (inclusief onderverdelen in meerdere frames).

Nog eens bedankt! :)

goety
%Europe/Berlin %603 %2006, 14:28
no problem, looking forward to it !

Dauntless
%Europe/Berlin %617 %2006, 14:49
"Waardoor hij pak te traag performed"
-> ik heb het nu aangepast, maar eerlijk gezegd is er geen snelheidswinst... Bij jou wel? :S

goety
%Europe/Berlin %641 %2006, 15:24
absoluut, als ik terug thuis ben zal ik mijn resultaten posten

Dauntless
%Europe/Berlin %657 %2006, 15:46
Logisch gezien zou ook een snelheidswinst moeten geven... Ik begrijp alleen niet wrm m'n traces hetzelfde blijven...

Deze test code:

import be.dauntless.Astar.*;
map = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1],
[1,0,0,0,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,1],
[1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0, 0,1,1,1,1,0,1],
[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,1,0,1],
[1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,0, 0,0,1,0,1,0,1],
[1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,0,0,1,0,1,1,0,0,1,1,1,0,0,1,1,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,0,0,1,1,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, 1,0,1,0,1,0,1],
[1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0, 0,0,0,0,1,0,1],
[1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0, 0,1,1,1,1,0,1],
[1,0,0,0,0,0,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,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1]
];
var myMap:Array = new Array();
for(var y:Number = 0; y<map.length; y++)
{
myMap[y] = new Array();
for(var x:Number = 0; x<map[0].length; x++)
{
myMap[y][x] = new Tile(x, y, 1);
myMap[y][x].setWalkable((map[y][x] == 1?false:true));
}
}
var myAstar:Astar = new Astar();
myAstar.setMap(myMap);
myAstar.setStartPoint(1, 1);
var startX:Number = 1;
var startY:Number = 1;
var endX:Number = map[0].length -2;
var endY:Number = map.length -2;

myAstar.setEndPoint(endX, endY);
var t:Number = getTimer();
var path:Object = myAstar.findPath();
trace("path found in "+(getTimer() - t));

goety
%Europe/Berlin %935 %2006, 22:27
mmmm, snap het niet. Mijn testen opnieuw aan het runnen, (oude versie) en krijg geen sluitende resultaten meer.

de reden dat ik het gevonden had was nochtans zo:

had een search depth toegevoegd die na een aantal iteraties een resultaat teruggaf,
zodat een creature al kon starten, na op het eindpunt aangekomen te zijn, zoekt die
verder enz.

maar die creatures begonnen toen constant met in de foute richting te starten. wat logisch
is als je aan setH de beginlocatie inplek van de eindlocatie meegeeft.

de logica is er dus. maar een echt numeriek verschil in snelheid kan ik niet meer echt vinden

raar want was er van overtuigd met eerdere testen.

btw. Dauntless heb je de code van Andre Michelle al eens kunnen bekijken ? al een
id hoe je code execution over verschillende frames kan opdelen ?

vandaag geen tijd gehad (alleen wonen schroeft vrije tijd terug!!!)

dit blijft een zalig projectje.

building voor den rts da ik aan bezig ben. (more to come)
http://www.befragile.com/factory.jpg

Dauntless
%Europe/Berlin %942 %2006, 22:37
Coole 3d pic! :D

Ik heb eens gekeken naar die classes van andre michelle... Maar wauw, die code onduidelijk!

if ( ~map[ $y0 ][ $x0 + 1 ] & 1 ) launch( new Agent( $x0 + 1, $y0, 1, [ { x: $x0 + 1 , y: $y0 } ] ) );
if ( ~map[ $y0 ][ $x0 - 1 ] & 1 ) launch( new Agent( $x0 - 1, $y0, 2, [ { x: $x0 - 1 , y: $y0 } ] ) );
if ( ~map[ $y0 + 1 ][ $x0 ] & 1 ) launch( new Agent( $x0, $y0 + 1, 4, [ { x: $x0 , y: $y0 + 1 } ] ) );
if ( ~map[ $y0 - 1 ][ $x0 ] & 1 ) launch( new Agent( $x0, $y0 - 1, 8, [ { x: $x0 , y: $y0 - 1 } ] ) ); P) ...

Maar 'k heb eigenlijk wel een ID hoe ik 'm kan omzetten :). Alleen is het wel veel werk natuurlijk... De core engine moet helemaal geherstructureerd worden... Hopelijk kan ik er deze week nog wat aan werken :).

goety
%Europe/Berlin %950 %2006, 22:48
misschien best een nieuwe versie dan ofzo.

en de oude opnieuw posten met de kleine bugs, schoonheidsfoutjes eruit.

pic is inderdaad in max gemaakt, maar in flash gaat het natuurlijk gewoon
de bitmap zijn, eventueel uit verschillende hoeken gerenderd.

Als je wil kan ik je wel even een sneak peak geven op de "werkende" versie van het spel(techtest). Met jouw A*. Deze versie is van voor ik van scratch terug ben begonnen met FlashDevelop. (add me eventueel even op msn voor de link)

Dauntless
%Europe/Berlin %961 %2006, 23:04
Ohja: Als er nog anderen zijn die toevallig nog optimalisatie technieken weten voor A*... Post ze hé! :)

Dauntless
%Europe/Berlin %981 %2006, 23:32
Oh My GOD!

M'n A* is zo net 3 tot 4x zo snel geworden !!!

Mijn volledige dank gaat uit naar goety van hierboven. Hij zat helemaal juist.... je moest alleen nog ergens anders de setH aanpassen (hij wordt maar 2x opgeroepen in Astar classe, dus .... :p)

THANK YOU THANK YOU THANK YOU

(Btw: Voor zover ik zie is mijn A* nu zo'n 10 ms sneller dan dat bestandje van Andre Michelle dat je me had doorgestuurd). (zijne doet er 50-70 over, mijne 40 ... Maar dat blijft natuurlijk moeilijk testen).

Emveedee
%Europe/Berlin %987 %2006, 23:42
heh, best cool :)

Dauntless
%Europe/Berlin %991 %2006, 23:47
Hij is nu eigenlijk exact even snel (is moeilijk te testen hé) als Zehn's A*, welke over het algemen beschouwd wordt als de snelste A* in Flash... Maar in zijn A* zit dus eigenlijk bijna niets van functionaliteit... Zeker als je hem vergelijkt met die van mij...

Maar aangezien mensen altijd kijken naar tijden, niet naar functionaliteit (of toch de meesen), ga ik proberen om em nog 5 ms sneller te krijgen :p.

Emveedee
%Europe/Berlin %016 %2006, 00:23
Ik vraag me af:
Is ie niet sneller zonder comment erin?
Zijn toch al een heel stuk minder regels wat ie dan moet lezen?

Dauntless
%Europe/Berlin %021 %2006, 00:31
Geen id eigenlijk.... :#

Wat WEL HEEL VEEL zou helpen, is dat ik alle variabele '1 char variabelen' maak. Dus in plaats van de variabele 'heap', 'h' nemen. En zo echt voor ELKE variabele (waarschijnlijk dus ook variabeleen met 2 letters). Maar... dan kan niemand nog aan het script aan uit.

goety
%Europe/Berlin %354 %2006, 08:31
commentaar verwijderen... denk niet dat dat iets doet.
je file is compiled voor ze runt hé...

1 char vars moet is getest worden. maar ben ik ook niet
zo zeker van. Als je iets maakt en dan decompiled zijn de
var namen ook niet hetzelfde meer.. dus denk dat de compiler
da ook zelf doet. (testen maar)

optimalizaties zoals je me gisteren toonde Dauntless zijn wel koel
natuurlijk [i-(-1)] sneller dan i+1

blijven gaan!

matzo
%Europe/Berlin %359 %2006, 08:38
Super Dauntless, mooi werk!!!!!
En die conversietabel waarover ik iets zei op msn, zou dat helpen??

LunchBox
%Europe/Berlin %355 %2006, 09:31
chique dinges, die van antwerpen kunnen er wah van :)

Dauntless
%Europe/Berlin %438 %2006, 11:32
Thx :).

Overigens is het topic in de ShowCase recenter... Dus ik ga deze op slot gooien met een linkje naar daar :).

Er kan hier verder gegaan worden:
http://www.flashfocus.nl/forum/showthread.php?p=105387