Gamestudio Links
Zorro Links
Newest Posts
Help with plotting multiple ZigZag
by degenerate_762. 04/30/24 23:23
M1 Oversampling
by 11honza11. 04/30/24 08:16
Trading Journey
by howardR. 04/28/24 09:55
Zorro Trader GPT
by TipmyPip. 04/27/24 13:50
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
2 registered members (vicknick, 7th_zorro), 888 guests, and 3 spiders.
Key: Admin, Global Mod, Mod
Newest Members
firatv, wandaluciaia, Mega_Rod, EternallyCurious, howardR
19050 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Pathfinding mit Koordinatengitter #347963
11/21/10 14:02
11/21/10 14:02
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
Hallo zusammen,

ich plane ein Aufbaustrategiespiel. Momentan stehe ich vor der Aufgabe, ein vernünftiges, stabiles und performantes Pathfinding zu realisieren.
Die Entities können sich nur auf den Linien eines gedachten Gitters bewegen. Dieses kann man sich wie ein kariertes Blatt papier vorstellen. Die einzelnen Punkte sind dann die Schnittstellen der linien. Sie werden in einem Array (coord[x][y]) gespeichert. Links unten ist dann der Punkt 0/0 und oben rechts z.B. 200/200.

Jetzt kann jeder dieser Knotenpunkte zwei zustände einnehmen: frei oder belegt. Wenn sich eine Entity von einem Punkt zum anderen bewegen soll, muss natürlich berücksichtigt werden, dass einige dazwischen evt belegt sind. Die Aufgabe ist es nun, dass der kürzeste freie Weg gefunden wird. Dabei ist es auch sinnvoll, dass die Entity nicht unbeding immer zuerste die eine Achse entlang läuft und dann die andere. Sie soll viel mehr die Punkte ablaufen, die praktisch am nächsten an der Luftlinie liegen, soweit dies möglich ist.

Hier mal zur Veranschaulichung:


Wie realisiere ich soetwas?

Dank und Gruß
derGarv


GameStudio Version: A7 Pro v7.86
Re: Pathfinding mit Koordinatengitter [Re: garv3] #347965
11/21/10 14:11
11/21/10 14:11
Joined: Dec 2008
Posts: 271
Saturnus Offline
Member
Saturnus  Offline
Member

Joined: Dec 2008
Posts: 271
Schau dir den Dijkstra- bzw. A*-Algorithmus an. Damit wird das gemacht.

Re: Pathfinding mit Koordinatengitter [Re: Saturnus] #347968
11/21/10 14:33
11/21/10 14:33
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
Werd ich mir ansehen. Danke!!!


GameStudio Version: A7 Pro v7.86
Re: Pathfinding mit Koordinatengitter [Re: garv3] #347975
11/21/10 15:39
11/21/10 15:39
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
AStar sieht ja schonmal interessant aus. Aber wie kann ich den Algorithmus in lite-c umsetzen? Ist dann doch etwas zu hoch für mich grin


GameStudio Version: A7 Pro v7.86
Re: Pathfinding mit Koordinatengitter [Re: garv3] #347998
11/21/10 17:14
11/21/10 17:14
Joined: Dec 2008
Posts: 271
Saturnus Offline
Member
Saturnus  Offline
Member

Joined: Dec 2008
Posts: 271
Ich empfehle dir, dich zu allererst mit dem Dijkstra-Algorithmus näher zu beschäftigen. Versuche zu verstehen, wie dieser Algorithmus abläuft. Gegebenenfalls auf einem Blatt Papier (oder etwas moderner: in einer Textdatei wink ). Wenn du Dijkstra verstanden hast, sollte die Implementation kein großes Problem mehr darstellen. Dann wird dir auch der (kleine) Unterschied zu A* auffallen.

Ein paar Punkte an denen du dich orientieren könntest:

- Der Algorithmus findet auf einem Graphen statt. Der Graph besteht aus Knoten, die durch Kanten miteinander verbunden sind. Einen solchen Graphen hast du ja bereits in deinem ersten Beitrag dargestellt.

- Die Knoten können in zwei Gruppen unterschieden werden: 1) Knoten, die von dem Algorithmus noch überprüft werden müssen und 2) Knoten, deren Überprüfung abgeschlossen ist. Diese beiden Gruppen bezeichnet man üblicherweise als Open und Closed List.

- Die Suche beginnt beim Startknoten und endet, sobald der Zielknoten erreicht ist. Die Reihenfolge, in der die dazwischenliegenden Knoten geprüft werden, hängt von ihren sogenannten Wegkosten ab.

Kommst du mit diesen Informationen weiter?
Im Prinzip geht es nur darum, den Algorithmus zu verstehen und anschließend in lauffähigen Code zu übersetzen. Die Pseudocodes, die man dazu im Netz finden kann, können dir dabei auch behilflich sein.

Wenn du konkrete Fragen dazu oder Probleme bei der Implementation hast, kannst du dich ja hier melden.

Re: Pathfinding mit Koordinatengitter [Re: Saturnus] #348015
11/21/10 19:07
11/21/10 19:07
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
Ich habe den Algorithmus soweit verstanden, denke ich jedenfalls.
Allerdings sehe ich zwei Probleme:

1. Es gibt nicht EINEN Knoten mit minimaler Distanz zu einem vorigen Knoten. Die Distanz zwischen allen benachbarten Knoten ist identisch (quadratisch angeordnet)
2. Die Umsetzung in lite-c (habe keine Erfahrung mit Structs usw.)


GameStudio Version: A7 Pro v7.86
Re: Pathfinding mit Koordinatengitter [Re: garv3] #348030
11/22/10 00:14
11/22/10 00:14
Joined: Dec 2008
Posts: 271
Saturnus Offline
Member
Saturnus  Offline
Member

Joined: Dec 2008
Posts: 271
1. Es ist egal, welcher der Knoten zuerst ausgewählt wird. Wenn der ausgewählte Knoten in die falsche Richtung führt, macht sich das in seinen höheren Wegkosten bemerkbar.

2. Hier ist eine sehr simple Umsetzung in lite-C. Verwendet keine Structs. Vielleicht kannst du ja damit etwas anfangen.

Code:
/*
 * Simple Implementierung des Dijkstra-Algorithmus in lite-C. Verwendet ein
 * regelmäßiges Gitter als Graphen. Ohne Optimierungen.
 *
 * Diesen Code in eine .c-Datei kopieren und in SED ausführen.
 *
 * Getestet in A8.03.2
 */

#include <acknex.h>
#include <default.c>

// Eigenschaften des Graphen
#define NUMBER_OF_COLS 10
#define NUMBER_OF_ROWS 10
#define NUMBER_OF_NODES 100

// Die Kosten, um von einem Knoten zum Nachbarknoten zu gelangen.
// Der Wert an sich ist hier ohne große Bedeutung.
#define EDGE_COST 10.0

// Kennzeichnet ungültige bzw. nicht vorhandene Knoten.
#define NULLNODE -1

// row-major order Berechnung
#define NODE_INDEX(col, row) ((row) * NUMBER_OF_COLS + (col))

// Nummer des Vorgängerknotens für jeden Knoten
int nodeParent[NUMBER_OF_NODES];

// Pfadkosten vom Startknoten bis zu jedem Knoten
var nodePathCost[NUMBER_OF_NODES];

// speichert, ob sich der jeweilige Knoten in der Open List befindet
BOOL inOpenList[NUMBER_OF_NODES];

// speichert die Passierbarkeit eines Knotens: 0 = passierbar, 1 = unpassierbar
BOOL nodeBlocked[NUMBER_OF_NODES]  = { 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, 0, 0, 0, 0,
				       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
				       0, 0, 1, 0, 0, 1, 1, 0, 1, 1,
				       0, 0, 1, 1, 1, 1, 0, 0, 1, 0,
				       0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
				       0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
				       0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
				       0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

// speichert den Pfad vom Zielknoten bis zum Startknoten
int path[NUMBER_OF_NODES];

// Prototypen
BOOL isOpenListEmpty();
int getBestNodeFromOpenList();
void reconstructPath(int node);
void expandNode(int parent);

// Die Hauptfunktion des Suchalgorithmus. Liefert TRUE zurück, wenn ein Pfad
// zwischen Start- und Zielknoren gefunden wird, ansonsten FALSE.
// Der gefundene Pfad wird in umgekehrter Reihenfolge im globalen Array path[]
// gespeichert.
BOOL dijkstra(int start_node, int dest_node)
{
	int node;
	
	if ((nodeBlocked[start_node] == TRUE) ||
		(nodeBlocked[dest_node] == TRUE))
	{
		return FALSE;
	}
	
	// Knoten initialisieren
	for (node = 0; node < NUMBER_OF_NODES; node++)
	{
		nodeParent[node] = NULLNODE;
		nodePathCost[node] = VAR_MAX;
		inOpenList[node] = TRUE;
	}
	
	nodePathCost[start_node] = 0;
	
	do
	{
		node = getBestNodeFromOpenList();
		inOpenList[node] = FALSE;
		
		if (node == dest_node) // Pfad gefunden!
		{
			reconstructPath(node);
			return TRUE;
		}
		
		expandNode(node);
	}
	while (isOpenListEmpty() == FALSE);
	
	return FALSE;
}

// Liefert TRUE zurück, wenn die Open List keine Knoten mehr enthält,
// ansonsten FALSE.
BOOL isOpenListEmpty()
{
	int node = 0;
	
	for (node = 0; node < NUMBER_OF_NODES; node++)
	{
		if (inOpenList[node] == TRUE)
		{
			return FALSE;
		}
	}
	
	return TRUE;
}

// Liefert den Knoten mit den kleinsten Wegkosten aus den Open List zurück.
int getBestNodeFromOpenList()
{
	var smallest_path_cost = VAR_MAX;
	int best_node = NULLNODE;
	int node;
	
	for (node = 0; node < NUMBER_OF_NODES; node++)
	{
		if ((inOpenList[node] == TRUE) &&
			(nodePathCost[node] < smallest_path_cost))
		{
			best_node = node;
			smallest_path_cost = nodePathCost[node];
		}
	}
	
	return best_node;
}

// Rekonstruiert den Pfad vom Zielknoten (node) bis zum Startknoten.
// Das Ergebnis wird im globalen Array path[] gespeichert.
void reconstructPath(int node)
{
	int path_length = 0;
		
	for (; node >= 0; path_length++)
	{
		path[path_length] = node;
		node = nodeParent[node];
	}
	
	if (path_length < (NUMBER_OF_NODES - 1))
	{
		// Markiere das Ende des Pfads
		path[path_length] = NULLNODE;
	}
}

// Aktualisiert die Wegkosten der Nachbarknoten von parent.
void expandNode(int parent)
{
	int parent_col = parent % NUMBER_OF_COLS;
	int parent_row = parent / NUMBER_OF_COLS;
	int node_col, node_row;
	
	for (node_row = parent_row - 1; node_row <= parent_row + 1; node_row++)
	{
		for (node_col = parent_col - 1; node_col <= parent_col + 1; node_col++)
		{
			int node = NODE_INDEX(node_col, node_row);
		
			if ((node_col < 0) || (node_col >= NUMBER_OF_COLS) ||
				(node_row < 0) || (node_row >= NUMBER_OF_ROWS) ||
				(node == parent))
			{
				// kein gültiger Nachbarknoten
				continue;
			}
			
			if ((inOpenList[node] == TRUE) && (nodeBlocked[node] == FALSE))
			{
				var path_cost = nodePathCost[parent] + EDGE_COST;
				
				if ((node_col != parent_col) && (node_row != parent_row))
				{
					// diagonale Pfade bekommen höhere Wegkosten
					path_cost += EDGE_COST * 0.5;
				}
				
				if (path_cost < nodePathCost[node])
				{
					nodePathCost[node] = path_cost;
					nodeParent[node] = parent;
				}
			}
		}
	}
}

// Liefert zurück, ob sich der angegebene Knoten im Pfad befindet.
BOOL isNodeInPath(int node)
{
	int n;
	
	for (n = 0; n < NUMBER_OF_NODES; n++)
	{
		if (path[n] == node)
			return TRUE;
		else if (path[n] == NULLNODE) // Ende des Pfads
			break;
	}
	
	return FALSE;
}

PANEL *pfindDescPnl =
{
	digits(10, 10, "rot: blockierte Knoten\ngruen: Pfad", *, 0, 0);
	flags = SHOW;
}

void main()
{
	level_load(NULL);
	
	vec_set(&camera->x, vector(50, -80, 180));
	vec_set(&camera->pan, vector(90, -80, 0));
	
	path[0] = NULLNODE; // noch kein Pfad gefunden
	
	// Finde den Pfad von Knoten 12 zu Knoten 98
	dijkstra(12, 98);
	
	while (1)
	{
		int row, col;
		
		// Zeichne den Graphen
		for (row = 0; row < NUMBER_OF_ROWS; row++)
		{
			for (col = 0; col < NUMBER_OF_COLS; col++)
			{	
				COLOR node_color;
				int node = NODE_INDEX(col, row);
				
				if (isNodeInPath(node) == TRUE)
					vec_set(&node_color, vector(0, 255, 0));
				else if (nodeBlocked[node] == FALSE)
					vec_set(&node_color, vector(128, 128, 128));
				else
					vec_set(&node_color, vector(0, 0, 255));
				
				draw_point3d(vector(col * 10, -row * 10, 0), &node_color, 100, 5);
			}
		}
		wait(1);
	}
}



Re: Pathfinding mit Koordinatengitter [Re: Saturnus] #348089
11/22/10 16:13
11/22/10 16:13
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
Hi!

Ich hab den Dijkstra jetzt selbst komplett in Lite-C umgesetzt. Habe dazu ein dreidimensionales Array benutzt.
Funktioniert soweit gut!

Danke nochmal für die Hilfe!!!

MfG
derGarv


GameStudio Version: A7 Pro v7.86
Re: Pathfinding mit Koordinatengitter [Re: garv3] #348099
11/22/10 16:53
11/22/10 16:53
Joined: Jan 2005
Posts: 605
Deutschland, NRW
G
garv3 Offline OP
User
garv3  Offline OP
User
G

Joined: Jan 2005
Posts: 605
Deutschland, NRW
So, jetzt habe ich noch ein Problem:
Ich kann den Pfad nun rückwärts abgehen (vom Ziel zum Start) aber wie kann ich die Wegpunkte nun in der korrekten Reihenfolge (vom Start zum Ziel) in ein Array schreiben und dieses dann zurückgeben?

P.S.
Hier mal ein Screenshot:

(grün=frei, rot=blockiert, weiß=start, blau=ziel, schwarz=pfad)


GameStudio Version: A7 Pro v7.86

Moderated by  HeelX, Spirit 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1