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
|
||||
{
|
||||
class PriorityQueue<T>
|
||||
public class PriorityQueue<T>
|
||||
where T : IComparable<T>
|
||||
{
|
||||
List<T[]> items = new List<T[]>();
|
||||
@@ -36,10 +36,16 @@ namespace OpenRa.DataStructures
|
||||
{
|
||||
index = 0;
|
||||
++level;
|
||||
items.Add( new T[ 1 << level ] );
|
||||
if( items.Count <= level )
|
||||
items.Add( new T[ 1 << level ] );
|
||||
}
|
||||
}
|
||||
|
||||
public bool Empty
|
||||
{
|
||||
get { return ( level == 0 ); }
|
||||
}
|
||||
|
||||
T At( int level, int 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 )" );
|
||||
//}
|
||||
|
||||
private int RowLength( int i )
|
||||
int RowLength( int i )
|
||||
{
|
||||
if( i == level )
|
||||
return index;
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenRa.Game
|
||||
Location = Point.Empty;
|
||||
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"))));
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace OpenRa.Game
|
||||
|
||||
sidebar = new Sidebar(Race.Soviet, renderer, viewport);
|
||||
|
||||
PathFinder.Instance = new PathFinder( map, terrain.tileSet );
|
||||
}
|
||||
|
||||
void PrecacheStructure(string name)
|
||||
|
||||
@@ -95,9 +95,16 @@ namespace OpenRa.Game
|
||||
currentOrder = null;
|
||||
else
|
||||
{
|
||||
int2 dir = destination - fromCell;
|
||||
toCell = fromCell + dir.Sign();
|
||||
moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 250 : 200;
|
||||
List<int2> res = PathFinder.Instance.FindUnitPath( world, this, destination );
|
||||
if( res.Count != 0 )
|
||||
{
|
||||
toCell = res[ res.Count - 1 ];
|
||||
|
||||
int2 dir = toCell - fromCell;
|
||||
moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 250 : 200;
|
||||
}
|
||||
else
|
||||
destination = toCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,5 +155,10 @@ namespace OpenRa.Game
|
||||
else
|
||||
return new MoveOrder( this, xy );
|
||||
}
|
||||
|
||||
public int2 Location
|
||||
{
|
||||
get { return toCell; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@
|
||||
<Compile Include="World.cs" />
|
||||
</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">
|
||||
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
|
||||
<Name>OpenRa.FileFormats</Name>
|
||||
@@ -96,4 +100,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
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]
|
||||
static void Main( string[] args )
|
||||
{
|
||||
if( System.Diagnostics.Debugger.IsAttached )
|
||||
{
|
||||
Run( args );
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault( false );
|
||||
|
||||
Settings settings = new Settings(args);
|
||||
|
||||
new MainWindow( settings ).Run();
|
||||
Run( args );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
@@ -26,5 +27,15 @@ namespace OpenRa.Game
|
||||
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;
|
||||
IndexBuffer indexBuffer;
|
||||
Sheet terrainSheet;
|
||||
TileSet tileSet;
|
||||
public TileSet tileSet;
|
||||
Viewport viewport;
|
||||
|
||||
Renderer renderer;
|
||||
@@ -32,30 +32,30 @@ namespace OpenRa.Game
|
||||
Dictionary<TileReference, Sprite> tileMapping =
|
||||
new Dictionary<TileReference, Sprite>();
|
||||
|
||||
Size tileSize = new Size(24, 24);
|
||||
Size tileSize = new Size( 24, 24 );
|
||||
|
||||
List<Vertex> vertices = new List<Vertex>();
|
||||
List<ushort> indices = new List<ushort>();
|
||||
|
||||
for (int j = 0; j < map.Height; j++)
|
||||
for (int i = 0; i < map.Width; i++)
|
||||
for( int j = 0 ; j < map.Height ; j++ )
|
||||
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;
|
||||
|
||||
if (!tileMapping.TryGetValue(tileRef, out tile))
|
||||
tileMapping.Add(tileRef, tile = SheetBuilder.Add(tileSet.GetBytes(tileRef), tileSize));
|
||||
if( !tileMapping.TryGetValue( tileRef, out tile ) )
|
||||
tileMapping.Add( tileRef, tile = SheetBuilder.Add( tileSet.GetBytes( tileRef ), tileSize ) );
|
||||
|
||||
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.SetData(vertices.ToArray());
|
||||
vertexBuffer = new FvfVertexBuffer<Vertex>( renderer.Device, vertices.Count, Vertex.Format );
|
||||
vertexBuffer.SetData( vertices.ToArray() );
|
||||
|
||||
indexBuffer = new IndexBuffer(renderer.Device, indices.Count);
|
||||
indexBuffer.SetData(indices.ToArray());
|
||||
indexBuffer = new IndexBuffer( renderer.Device, indices.Count );
|
||||
indexBuffer.SetData( indices.ToArray() );
|
||||
}
|
||||
|
||||
void Draw()
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace OpenRa.Game
|
||||
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 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); }
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
|
||||
Reference in New Issue
Block a user