using UnityEngine;
using System. Collections. Generic;
using System;
using System. Linq;
public static class PathFinding2D
{
public static List< Vector2Int> find4 ( Vector2Int from , Vector2Int to, Dictionary< Vector2Int, int > map, List< int > passableValues)
{
Func< Vector2Int, Vector2Int, float > getDistance = delegate ( Vector2Int a, Vector2Int b)
{
float xDistance = Mathf. Abs ( a. x - b. x) ;
float yDistance = Mathf. Abs ( a. y - b. y) ;
return xDistance * xDistance + yDistance * yDistance;
} ;
Func< Vector2Int, List< Vector2Int> > getNeighbors = delegate ( Vector2Int pos)
{
var neighbors = new List < Vector2Int > ( ) ;
neighbors. Add ( new Vector2Int ( pos. x, pos. y + 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x, pos. y - 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x + 1 , pos. y) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 1 , pos. y) ) ;
return neighbors;
} ;
return astar ( from , to, map, passableValues, getDistance, getNeighbors) ;
}
public static List< Vector2Int> find6X ( Vector2Int from , Vector2Int to, Dictionary< Vector2Int, int > map, List< int > passableValues)
{
Func< Vector2Int, Vector2Int, float > getDistance = delegate ( Vector2Int a, Vector2Int b)
{
float xDistance = Mathf. Abs ( a. x - b. x) ;
float yDistance = Mathf. Abs ( a. y - b. y) * Mathf. Sqrt ( 3 ) ;
return xDistance * xDistance + yDistance * yDistance;
} ;
Func< Vector2Int, List< Vector2Int> > getNeighbors = delegate ( Vector2Int pos)
{
var neighbors = new List < Vector2Int > ( ) ;
neighbors. Add ( new Vector2Int ( pos. x + 1 , pos. y + 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 1 , pos. y + 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x + 1 , pos. y - 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 1 , pos. y - 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 2 , pos. y) ) ;
neighbors. Add ( new Vector2Int ( pos. x + 2 , pos. y) ) ;
return neighbors;
} ;
return astar ( from , to, map, passableValues, getDistance, getNeighbors) ;
}
public static List< Vector2Int> find6Y ( Vector2Int from , Vector2Int to, Dictionary< Vector2Int, int > map, List< int > passableValues)
{
Func< Vector2Int, Vector2Int, float > getDistance = delegate ( Vector2Int a, Vector2Int b)
{
float xDistance = Mathf. Abs ( a. x - b. x) * Mathf. Sqrt ( 3 ) ;
float yDistance = Mathf. Abs ( a. y - b. y) ;
return xDistance * xDistance + yDistance * yDistance;
} ;
Func< Vector2Int, List< Vector2Int> > getNeighbors = delegate ( Vector2Int pos)
{
var neighbors = new List < Vector2Int > ( ) ;
neighbors. Add ( new Vector2Int ( pos. x + 1 , pos. y + 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 1 , pos. y + 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x + 1 , pos. y - 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x - 1 , pos. y - 1 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x, pos. y - 2 ) ) ;
neighbors. Add ( new Vector2Int ( pos. x, pos. y + 2 ) ) ;
return neighbors;
} ;
return astar ( from , to, map, passableValues, getDistance, getNeighbors) ;
}
static List< Vector2Int> astar ( Vector2Int from , Vector2Int to, Dictionary< Vector2Int, int > map, List< int > passableValues,
Func< Vector2Int, Vector2Int, float > getDistance, Func< Vector2Int, List< Vector2Int> > getNeighbors)
{
var result = new List < Vector2Int > ( ) ;
if ( from == to)
{
result. Add ( from ) ;
return result;
}
Node finalNode;
List< Node> open = new List < Node > ( ) ;
if ( findDest ( new Node ( null , from , getDistance ( from , to) , 0 ) , open, map, to, out finalNode, passableValues, getDistance, getNeighbors) )
{
while ( finalNode != null )
{
result. Add ( finalNode. pos) ;
finalNode = finalNode. preNode;
}
}
result. Reverse ( ) ;
return result;
}
static bool findDest ( Node currentNode, List< Node> openList,
Dictionary< Vector2Int, int > map, Vector2Int to, out Node finalNode, List< int > passableValues,
Func< Vector2Int, Vector2Int, float > getDistance, Func< Vector2Int, List< Vector2Int> > getNeighbors)
{
if ( currentNode == null ) {
finalNode = null ;
return false ;
}
else if ( currentNode. pos == to)
{
finalNode = currentNode;
return true ;
}
currentNode. open = false ;
openList. Add ( currentNode) ;
foreach ( var item in getNeighbors ( currentNode. pos) )
{
if ( map. ContainsKey ( item) && passableValues. Contains ( map[ item] ) )
{
findTemp ( openList, currentNode, item, to, getDistance) ;
}
}
var next = openList. FindAll ( obj = > obj. open) . Min ( ) ;
return findDest ( next, openList, map, to, out finalNode, passableValues, getDistance, getNeighbors) ;
}
static void findTemp ( List< Node> openList, Node currentNode, Vector2Int from , Vector2Int to, Func< Vector2Int, Vector2Int, float > getDistance)
{
Node temp = openList. Find ( obj = > obj. pos == ( from ) ) ;
if ( temp == null )
{
temp = new Node ( currentNode, from , getDistance ( from , to) , currentNode. gScore + 1 ) ;
openList. Add ( temp) ;
}
else if ( temp. open && temp. gScore > currentNode. gScore + 1 )
{
temp. gScore = currentNode. gScore + 1 ;
temp. fScore = temp. hScore + temp. gScore;
temp. preNode = currentNode;
}
}
class Node : IComparable
{
public Node preNode;
public Vector2Int pos;
public float fScore;
public float hScore;
public float gScore;
public bool open = true ;
public Node ( Node prePos, Vector2Int pos, float hScore, float gScore)
{
this . preNode = prePos;
this . pos = pos;
this . hScore = hScore;
this . gScore = gScore;
this . fScore = hScore + gScore;
}
public int CompareTo ( object obj)
{
Node temp = obj as Node;
if ( temp == null ) return 1 ;
if ( Mathf. Abs ( this . fScore - temp. fScore) < 0.01f ) {
return this . fScore > temp. fScore ? 1 : - 1 ;
}
if ( Mathf. Abs ( this . hScore - temp. hScore) < 0.01f )
{
return this . hScore > temp. hScore ? 1 : - 1 ;
}
return 0 ;
}
}
}
using UnityEngine;
using System. Collections;
using System. Collections. Generic;
using System. Linq;
public class Example : MonoBehaviour
{
enum TileType
{
none,
wall,
}
public int width = 15 ;
public int height = 12 ;
public int obstacleFillPercent = 30 ;
public float scale = 32f ;
Sprite tilePrefab;
string message = "" ;
List< int > passableValues;
GameObject allMapTiles;
GameObject player;
GameObject goal;
void Start ( )
{
Camera. main. orthographicSize = scale * 10 ;
Camera. main. gameObject. transform. position = new Vector3 ( width * scale / 2 , height * scale / 2 , - 10 ) ;
tilePrefab = Sprite. Create ( new Texture2D ( ( int ) scale, ( int ) scale) , new Rect ( 0 , 0 , scale, scale) , new Vector2 ( 0.5f , 0.5f ) , 1f ) ;
goal = new GameObject ( "goal" ) ;
goal. AddComponent < SpriteRenderer > ( ) ;
goal. GetComponent < SpriteRenderer > ( ) . sprite = tilePrefab;
goal. GetComponent < SpriteRenderer > ( ) . color = Color. yellow;
goal. GetComponent < SpriteRenderer > ( ) . sortingOrder = 1 ;
player = new GameObject ( "player" ) ;
player. AddComponent < SpriteRenderer > ( ) ;
player. GetComponent < SpriteRenderer > ( ) . sprite = tilePrefab;
player. GetComponent < SpriteRenderer > ( ) . color = Color. red;
player. GetComponent < SpriteRenderer > ( ) . sortingOrder = 2 ;
passableValues = new List < int > ( ) ;
passableValues. Add ( ( int ) TileType. none) ;
}
void OnGUI ( )
{
if ( GUI. Button ( new Rect ( 10 , 10 , 150 , 30 ) , "pathfinding 4" ) )
{
message = "finding..." ;
simPathFinding4 ( ) ;
}
if ( GUI. Button ( new Rect ( 10 , 50 , 150 , 30 ) , "pathfinding 6X" ) )
{
message = "finding..." ;
simPathFinding6 ( ) ;
}
if ( GUI. Button ( new Rect ( 10 , 90 , 150 , 30 ) , "pathfinding 6Y" ) )
{
message = "finding..." ;
simPathFinding6 ( false ) ;
}
GUI. Label ( new Rect ( 180 , 20 , 300 , 30 ) , message) ;
}
public void simPathFinding4 ( )
{
StopAllCoroutines ( ) ;
var map = mapToDict4 ( generateMapArray ( width, height) ) ;
float xScale = scale;
float yScale = scale;
renderMap ( map, xScale, yScale) ;
var playerPos = new Vector2Int ( 0 , 0 ) ;
map[ playerPos] = ( int ) TileType. none;
setTransformPosition ( player. transform, playerPos, xScale, yScale) ;
var goalPos = new Vector2Int ( width - 1 , height - 1 ) ;
map[ goalPos] = ( int ) TileType. none;
setTransformPosition ( goal. transform, goalPos, xScale, yScale) ;
var path = PathFinding2D. find4 ( playerPos, goalPos, map, passableValues) ;
if ( path. Count == 0 )
{
message = "oops! cant find goal" ;
}
else
{
StartCoroutine ( movePlayer ( path, xScale, yScale, .2f ) ) ;
}
}
public void simPathFinding6 ( bool staggerByRow = true )
{
StopAllCoroutines ( ) ;
var map = mapToDict6 ( generateMapArray ( width, height) , staggerByRow) ;
var hexScale = scale + 4f ;
float xScale = staggerByRow ? hexScale / 2 : hexScale;
float yScale = staggerByRow ? hexScale : hexScale/ 2 ;
renderMap ( map, xScale, yScale) ;
var mapPoses = map. Keys. ToList ( ) ;
mapPoses. Sort ( ( a, b) = > a. x + a. y - b. x - b. y) ;
var playerPos = mapPoses. First ( ) ;
map[ playerPos] = ( int ) TileType. none;
setTransformPosition ( player. transform, playerPos, xScale, yScale) ;
var goalPos = mapPoses. Last ( ) ;
map[ goalPos] = ( int ) TileType. none;
setTransformPosition ( goal. transform, goalPos, xScale, yScale) ;
List< Vector2Int> path;
if ( staggerByRow) {
path = PathFinding2D. find6X ( playerPos, goalPos, map, passableValues) ;
} else {
path = PathFinding2D. find6Y ( playerPos, goalPos, map, passableValues) ;
}
if ( path. Count == 0 )
{
message = "oops! cant find goal" ;
}
else
{
StartCoroutine ( movePlayer ( path, xScale, yScale, .2f ) ) ;
}
}
void setTransformPosition ( Transform trans, Vector2Int pos, float xScale, float yScale)
{
trans. position = new Vector3 ( pos. x * xScale, pos. y * yScale, 0 ) ;
}
void renderMap ( Dictionary< Vector2Int, int > map, float xScale, float yScale)
{
Destroy ( allMapTiles) ;
allMapTiles = new GameObject ( "allMapTiles" ) ;
foreach ( var item in map)
{
GameObject temp = new GameObject ( ) ;
temp. transform. position = new Vector3 ( item. Key. x * xScale, item. Key. y * yScale, 0 ) ;
SpriteRenderer spr = temp. AddComponent < SpriteRenderer > ( ) ;
spr. sprite = tilePrefab;
switch ( item. Value)
{
case ( int ) TileType. none:
spr. color = Color. white;
break ;
case ( int ) TileType. wall:
spr. color = Color. black;
break ;
}
temp. transform. parent = allMapTiles. transform;
}
}
IEnumerator movePlayer ( List< Vector2Int> path, float xScale, float yScale, float interval = 0.1f )
{
foreach ( var item in path) {
setTransformPosition ( player. transform, item, xScale, yScale) ;
yield return new WaitForSeconds ( interval) ;
}
message = "reach goal !" ;
}
int [ , ] generateMapArray ( int pwidth, int pheight)
{
var mapArray = new int [ pwidth, pheight] ;
for ( int x = 0 ; x < pwidth; x++ )
{
for ( int y = 0 ; y < pheight; y++ )
{
mapArray[ x, y] = Random. Range ( 0 , 100 ) < obstacleFillPercent ? ( int ) TileType. wall : ( int ) TileType. none;
}
}
return mapArray;
}
Dictionary< Vector2Int, int > mapToDict4 ( int [ , ] mapArray)
{
Dictionary< Vector2Int, int > mapDict = new Dictionary < Vector2Int , int > ( ) ;
for ( int x = 0 ; x < mapArray. GetLength ( 0 ) ; x++ )
{
for ( int y = 0 ; y < mapArray. GetLength ( 1 ) ; y++ )
{
mapDict. Add ( new Vector2Int ( x, y) , mapArray[ x, y] ) ;
}
}
return mapDict;
}
Dictionary< Vector2Int, int > mapToDict6 ( int [ , ] mapArray, bool stretchRow)
{
Dictionary< Vector2Int, int > mapDict = new Dictionary < Vector2Int , int > ( ) ;
for ( int x = 0 ; x < mapArray. GetLength ( 0 ) ; x++ )
{
for ( int y = 0 ; y < mapArray. GetLength ( 1 ) ; y++ )
{
if ( stretchRow)
{
if ( y % 2 == 0 )
{
mapDict. Add ( new Vector2Int ( 2 * x, y) , mapArray[ x, y] ) ;
}
else
{
mapDict. Add ( new Vector2Int ( 2 * x + 1 , y) , mapArray[ x, y] ) ;
}
}
else
{
if ( x % 2 == 0 )
{
mapDict. Add ( new Vector2Int ( x, 2 * y) , mapArray[ x, y] ) ;
}
else
{
mapDict. Add ( new Vector2Int ( x, 2 * y + 1 ) , mapArray[ x, y] ) ;
}
}
}
}
return mapDict;
}
}