git-svn-id: svn://svn.ijw.co.nz/svn/OpenRa@1299 993157c7-ee19-0410-b2c4-bb4e9862e678
This commit is contained in:
@@ -5,7 +5,7 @@ using System.Diagnostics;
|
|||||||
|
|
||||||
namespace OpenRa.DataStructures
|
namespace OpenRa.DataStructures
|
||||||
{
|
{
|
||||||
class PriorityQueue<T>
|
public class PriorityQueue<T>
|
||||||
where T : IComparable<T>
|
where T : IComparable<T>
|
||||||
{
|
{
|
||||||
List<T[]> items = new List<T[]>();
|
List<T[]> items = new List<T[]>();
|
||||||
@@ -36,10 +36,16 @@ namespace OpenRa.DataStructures
|
|||||||
{
|
{
|
||||||
index = 0;
|
index = 0;
|
||||||
++level;
|
++level;
|
||||||
|
if( items.Count <= level )
|
||||||
items.Add( new T[ 1 << level ] );
|
items.Add( new T[ 1 << level ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Empty
|
||||||
|
{
|
||||||
|
get { return ( level == 0 ); }
|
||||||
|
}
|
||||||
|
|
||||||
T At( int level, int index )
|
T At( int level, int index )
|
||||||
{
|
{
|
||||||
return items[ level ][ index ];
|
return items[ level ][ index ];
|
||||||
@@ -123,7 +129,7 @@ namespace OpenRa.DataStructures
|
|||||||
// System.Diagnostics.Debug.Assert( At( i, j ).CompareTo( Above( i, j ) ) < 0, "At( i, j ) > Above( i, j )" );
|
// System.Diagnostics.Debug.Assert( At( i, j ).CompareTo( Above( i, j ) ) < 0, "At( i, j ) > Above( i, j )" );
|
||||||
//}
|
//}
|
||||||
|
|
||||||
private int RowLength( int i )
|
int RowLength( int i )
|
||||||
{
|
{
|
||||||
if( i == level )
|
if( i == level )
|
||||||
return index;
|
return index;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace OpenRa.Game
|
|||||||
Location = Point.Empty;
|
Location = Point.Empty;
|
||||||
Visible = true;
|
Visible = true;
|
||||||
|
|
||||||
renderer = new Renderer(this, GetResolution(settings), false);
|
renderer = new Renderer(this, GetResolution(settings), true);
|
||||||
|
|
||||||
map = new Map(new IniFile(File.OpenRead("../../../" + settings.GetValue("map", "scm12ea.ini"))));
|
map = new Map(new IniFile(File.OpenRead("../../../" + settings.GetValue("map", "scm12ea.ini"))));
|
||||||
|
|
||||||
@@ -71,6 +71,7 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
sidebar = new Sidebar(Race.Soviet, renderer, viewport);
|
sidebar = new Sidebar(Race.Soviet, renderer, viewport);
|
||||||
|
|
||||||
|
PathFinder.Instance = new PathFinder( map, terrain.tileSet );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrecacheStructure(string name)
|
void PrecacheStructure(string name)
|
||||||
|
|||||||
@@ -95,10 +95,17 @@ namespace OpenRa.Game
|
|||||||
currentOrder = null;
|
currentOrder = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int2 dir = destination - fromCell;
|
List<int2> res = PathFinder.Instance.FindUnitPath( world, this, destination );
|
||||||
toCell = fromCell + dir.Sign();
|
if( res.Count != 0 )
|
||||||
|
{
|
||||||
|
toCell = res[ res.Count - 1 ];
|
||||||
|
|
||||||
|
int2 dir = toCell - fromCell;
|
||||||
moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 250 : 200;
|
moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 250 : 200;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
destination = toCell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,5 +155,10 @@ namespace OpenRa.Game
|
|||||||
else
|
else
|
||||||
return new MoveOrder( this, xy );
|
return new MoveOrder( this, xy );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int2 Location
|
||||||
|
{
|
||||||
|
get { return toCell; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,10 @@
|
|||||||
<Compile Include="World.cs" />
|
<Compile Include="World.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\OpenRa.DataStructures\OpenRa.DataStructures.csproj">
|
||||||
|
<Project>{2F9E7A23-56C0-4286-9C8E-1060A9B2F073}</Project>
|
||||||
|
<Name>OpenRa.DataStructures</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\OpenRa.FileFormats\OpenRa.FileFormats.csproj">
|
<ProjectReference Include="..\OpenRa.FileFormats\OpenRa.FileFormats.csproj">
|
||||||
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
|
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
|
||||||
<Name>OpenRa.FileFormats</Name>
|
<Name>OpenRa.FileFormats</Name>
|
||||||
|
|||||||
168
OpenRa.Game/PathFinder.cs
Normal file
168
OpenRa.Game/PathFinder.cs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using OpenRa.FileFormats;
|
||||||
|
using OpenRa.DataStructures;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace OpenRa.Game
|
||||||
|
{
|
||||||
|
class PathFinder
|
||||||
|
{
|
||||||
|
public static PathFinder Instance;
|
||||||
|
|
||||||
|
bool[ , ] passable = new bool[ 128, 128 ];
|
||||||
|
Map map;
|
||||||
|
|
||||||
|
public PathFinder( Map map, TileSet tileSet )
|
||||||
|
{
|
||||||
|
this.map = map;
|
||||||
|
|
||||||
|
for( int x = 0 ; x < 128 ; x++ )
|
||||||
|
{
|
||||||
|
for( int y = 0 ; y < 128 ; y++ )
|
||||||
|
{
|
||||||
|
if( x < map.XOffset || y < map.YOffset || x >= map.XOffset + map.Width || y >= map.YOffset + map.Height )
|
||||||
|
passable[ x, y ] = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// HACK: water( tiles 1 and 2) are impassable
|
||||||
|
passable[ x, y ] = ( map.MapTiles[ x, y ].tile != 1 && map.MapTiles[ x, y ].tile != 2 );
|
||||||
|
// TODO: implement all the different terrain classes, including bonuses for roads etc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool first = true;
|
||||||
|
|
||||||
|
public List<int2> FindUnitPath( World world, Mcv unit, int2 destination )
|
||||||
|
{
|
||||||
|
int2 offset = new int2( map.XOffset, map.YOffset );
|
||||||
|
|
||||||
|
destination += offset;
|
||||||
|
int2 startLocation = unit.Location + offset;
|
||||||
|
|
||||||
|
bool[ , ] seen = new bool[ 128, 128 ];
|
||||||
|
int2[ , ] path = new int2[ 128, 128 ];
|
||||||
|
double[ , ] minCost = new double[ 128, 128 ];
|
||||||
|
|
||||||
|
for( int x = 0 ; x < 128 ; x++ )
|
||||||
|
{
|
||||||
|
for( int y = 0 ; y < 128 ; y++ )
|
||||||
|
{
|
||||||
|
path[ x, y ] = new int2( x, y );
|
||||||
|
minCost[ x, y ] = double.PositiveInfinity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PriorityQueue<PathDistance> queue = new PriorityQueue<PathDistance>();
|
||||||
|
|
||||||
|
queue.Add( new PathDistance( Estimate( startLocation, destination ), startLocation ) );
|
||||||
|
minCost[ startLocation.X, startLocation.Y ] = Estimate( startLocation, destination );
|
||||||
|
|
||||||
|
int hax = 0;
|
||||||
|
int seenCount = 0;
|
||||||
|
int impassableCount = 0;
|
||||||
|
|
||||||
|
while( !queue.Empty )
|
||||||
|
{
|
||||||
|
++hax;
|
||||||
|
PathDistance p = queue.Pop();
|
||||||
|
int2 here = p.Location;
|
||||||
|
seen[ here.X, here.Y ] = true;
|
||||||
|
|
||||||
|
if( hax < 128 )
|
||||||
|
world.AddFrameEndTask( delegate { world.Add( new Mcv( here - offset, 2 ) ); } );
|
||||||
|
|
||||||
|
if( p.Location == destination )
|
||||||
|
{
|
||||||
|
Log.Write( "{0}, {1}, {2}", hax, seenCount, impassableCount );
|
||||||
|
first = false;
|
||||||
|
return MakePath( path, destination, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach( int2 d in directions )
|
||||||
|
{
|
||||||
|
int2 newHere = here + d;
|
||||||
|
|
||||||
|
if( seen[ newHere.X, newHere.Y ] )
|
||||||
|
{
|
||||||
|
++seenCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( !passable[ newHere.X, newHere.Y ] )
|
||||||
|
{
|
||||||
|
++impassableCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double newCost = minCost[ here.X, here.Y ] + ( ( d.X * d.Y != 0 ) ? 1.414213563 : 1.0 );
|
||||||
|
|
||||||
|
if( newCost >= minCost[ newHere.X, newHere.Y ] )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
path[ newHere.X, newHere.Y ] = here;
|
||||||
|
minCost[ newHere.X, newHere.Y ] = newCost;
|
||||||
|
|
||||||
|
queue.Add( new PathDistance( newCost + Estimate( newHere, destination ), newHere ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no path exists
|
||||||
|
return new List<int2>();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int2> MakePath( int2[ , ] path, int2 destination, int2 offset )
|
||||||
|
{
|
||||||
|
List<int2> ret = new List<int2>();
|
||||||
|
int2 pathNode = destination;
|
||||||
|
|
||||||
|
while( path[ pathNode.X, pathNode.Y ] != pathNode )
|
||||||
|
{
|
||||||
|
ret.Add( pathNode - offset );
|
||||||
|
pathNode = path[ pathNode.X, pathNode.Y ];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Write( "Path Length: {0}", ret.Count );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly int2[] directions =
|
||||||
|
new int2[] {
|
||||||
|
new int2( -1, -1 ),
|
||||||
|
new int2( -1, 0 ),
|
||||||
|
new int2( -1, 1 ),
|
||||||
|
new int2( 0, -1 ),
|
||||||
|
new int2( 0, 1 ),
|
||||||
|
new int2( 1, -1 ),
|
||||||
|
new int2( 1, 0 ),
|
||||||
|
new int2( 1, 1 ),
|
||||||
|
};
|
||||||
|
|
||||||
|
double Estimate( int2 here, int2 destination )
|
||||||
|
{
|
||||||
|
int2 d = ( here - destination ).Abs();
|
||||||
|
int diag = Math.Min( d.X, d.Y );
|
||||||
|
int straight = Math.Abs( d.X - d.Y );
|
||||||
|
return 1.5 * diag + straight;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PathDistance : IComparable<PathDistance>
|
||||||
|
{
|
||||||
|
public double EstTotal;
|
||||||
|
public int2 Location;
|
||||||
|
|
||||||
|
public PathDistance( double estTotal, int2 location )
|
||||||
|
{
|
||||||
|
EstTotal = estTotal;
|
||||||
|
Location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo( PathDistance other )
|
||||||
|
{
|
||||||
|
return Math.Sign( EstTotal - other.EstTotal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,14 +10,15 @@ namespace OpenRa.Game
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main( string[] args )
|
static void Main( string[] args )
|
||||||
{
|
{
|
||||||
|
if( System.Diagnostics.Debugger.IsAttached )
|
||||||
|
{
|
||||||
|
Run( args );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Run( args );
|
||||||
Application.SetCompatibleTextRenderingDefault( false );
|
|
||||||
|
|
||||||
Settings settings = new Settings(args);
|
|
||||||
|
|
||||||
new MainWindow( settings ).Run();
|
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{
|
{
|
||||||
@@ -26,5 +27,15 @@ namespace OpenRa.Game
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Run( string[] args )
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault( false );
|
||||||
|
|
||||||
|
Settings settings = new Settings( args );
|
||||||
|
|
||||||
|
new MainWindow( settings ).Run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ namespace OpenRa.Game
|
|||||||
FvfVertexBuffer<Vertex> vertexBuffer;
|
FvfVertexBuffer<Vertex> vertexBuffer;
|
||||||
IndexBuffer indexBuffer;
|
IndexBuffer indexBuffer;
|
||||||
Sheet terrainSheet;
|
Sheet terrainSheet;
|
||||||
TileSet tileSet;
|
public TileSet tileSet;
|
||||||
Viewport viewport;
|
Viewport viewport;
|
||||||
|
|
||||||
Renderer renderer;
|
Renderer renderer;
|
||||||
@@ -32,30 +32,30 @@ namespace OpenRa.Game
|
|||||||
Dictionary<TileReference, Sprite> tileMapping =
|
Dictionary<TileReference, Sprite> tileMapping =
|
||||||
new Dictionary<TileReference, Sprite>();
|
new Dictionary<TileReference, Sprite>();
|
||||||
|
|
||||||
Size tileSize = new Size(24, 24);
|
Size tileSize = new Size( 24, 24 );
|
||||||
|
|
||||||
List<Vertex> vertices = new List<Vertex>();
|
List<Vertex> vertices = new List<Vertex>();
|
||||||
List<ushort> indices = new List<ushort>();
|
List<ushort> indices = new List<ushort>();
|
||||||
|
|
||||||
for (int j = 0; j < map.Height; j++)
|
for( int j = 0 ; j < map.Height ; j++ )
|
||||||
for (int i = 0; i < map.Width; i++)
|
for( int i = 0 ; i < map.Width ; i++ )
|
||||||
{
|
{
|
||||||
TileReference tileRef = map.MapTiles[i + map.XOffset, j + map.YOffset];
|
TileReference tileRef = map.MapTiles[ i + map.XOffset, j + map.YOffset ];
|
||||||
Sprite tile;
|
Sprite tile;
|
||||||
|
|
||||||
if (!tileMapping.TryGetValue(tileRef, out tile))
|
if( !tileMapping.TryGetValue( tileRef, out tile ) )
|
||||||
tileMapping.Add(tileRef, tile = SheetBuilder.Add(tileSet.GetBytes(tileRef), tileSize));
|
tileMapping.Add( tileRef, tile = SheetBuilder.Add( tileSet.GetBytes( tileRef ), tileSize ) );
|
||||||
|
|
||||||
terrainSheet = tile.sheet;
|
terrainSheet = tile.sheet;
|
||||||
|
|
||||||
Util.CreateQuad(vertices, indices, 24 * new float2(i,j), tile, 0);
|
Util.CreateQuad( vertices, indices, 24 * new float2( i, j ), tile, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexBuffer = new FvfVertexBuffer<Vertex>(renderer.Device, vertices.Count, Vertex.Format);
|
vertexBuffer = new FvfVertexBuffer<Vertex>( renderer.Device, vertices.Count, Vertex.Format );
|
||||||
vertexBuffer.SetData(vertices.ToArray());
|
vertexBuffer.SetData( vertices.ToArray() );
|
||||||
|
|
||||||
indexBuffer = new IndexBuffer(renderer.Device, indices.Count);
|
indexBuffer = new IndexBuffer( renderer.Device, indices.Count );
|
||||||
indexBuffer.SetData(indices.ToArray());
|
indexBuffer.SetData( indices.ToArray() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw()
|
void Draw()
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace OpenRa.Game
|
|||||||
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
|
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
|
||||||
|
|
||||||
public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); }
|
public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); }
|
||||||
|
public int2 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); }
|
||||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
|
|||||||
Reference in New Issue
Block a user