smooth unit-movement. Doesn't look right yet, but it's getting there.

This commit is contained in:
Bob
2009-10-24 18:20:58 +13:00
parent 06e6d50735
commit d66475edcb
3 changed files with 107 additions and 62 deletions

View File

@@ -17,7 +17,7 @@ namespace OpenRa.Game
public readonly UnitInfo unitInfo; public readonly UnitInfo unitInfo;
public int2 Location; public int2 Location;
public Player Owner; public Player Owner;
public int Health; public int Health;
public Actor( string name, int2 location, Player owner ) public Actor( string name, int2 location, Player owner )
@@ -25,21 +25,21 @@ namespace OpenRa.Game
unitInfo = Rules.UnitInfo[ name ]; unitInfo = Rules.UnitInfo[ name ];
Location = location; Location = location;
CenterLocation = new float2( 12, 12 ) + Game.CellSize * (float2)Location; CenterLocation = new float2( 12, 12 ) + Game.CellSize * (float2)Location;
Owner = owner; Owner = owner;
Health = unitInfo.Strength; /* todo: handle cases where this is not true! */ Health = unitInfo.Strength; /* todo: handle cases where this is not true! */
if( unitInfo.Traits != null ) if( unitInfo.Traits != null )
{ {
foreach( var traitName in unitInfo.Traits ) foreach( var traitName in unitInfo.Traits )
{ {
var type = typeof( Traits.Mobile ).Assembly.GetType( typeof( Traits.Mobile ).Namespace + "." + traitName, true, false ); var type = typeof( Traits.Mobile ).Assembly.GetType( typeof( Traits.Mobile ).Namespace + "." + traitName, true, false );
var ctor = type.GetConstructor( new[] { typeof( Actor ) } ); var ctor = type.GetConstructor( new[] { typeof( Actor ) } );
traits.Add( type, ctor.Invoke( new object[] { this } ) ); traits.Add( type, ctor.Invoke( new object[] { this } ) );
} }
} }
else else
throw new InvalidOperationException( "No Actor traits for " + unitInfo.Name throw new InvalidOperationException( "No Actor traits for " + unitInfo.Name
+ "; add Traits= to units.ini for appropriate unit" ); + "; add Traits= to units.ini for appropriate unit" );
} }
public Actor( TreeReference tree, TreeCache treeRenderer, int2 mapOffset ) public Actor( TreeReference tree, TreeCache treeRenderer, int2 mapOffset )
@@ -49,8 +49,8 @@ namespace OpenRa.Game
} }
public void Tick() public void Tick()
{ {
foreach (var tick in traits.WithInterface<Traits.ITick>()) foreach (var tick in traits.WithInterface<Traits.ITick>())
tick.Tick(this); tick.Tick(this);
} }
@@ -63,8 +63,8 @@ namespace OpenRa.Game
} }
public Order Order( int2 xy ) public Order Order( int2 xy )
{ {
if (Owner != Game.LocalPlayer) if (Owner != Game.LocalPlayer)
return null; return null;
return traits.WithInterface<Traits.IOrder>() return traits.WithInterface<Traits.IOrder>()
@@ -80,32 +80,32 @@ namespace OpenRa.Game
var loc = CenterLocation - 0.5f * size; var loc = CenterLocation - 0.5f * size;
return new RectangleF(loc.X, loc.Y, size.X, size.Y); return new RectangleF(loc.X, loc.Y, size.X, size.Y);
} }
} }
public bool IsDead { get { return Health <= 0; } } public bool IsDead { get { return Health <= 0; } }
public void InflictDamage(Actor attacker, Bullet inflictor, int damage) public void InflictDamage(Actor attacker, Bullet inflictor, int damage)
{ {
/* todo: auto-retaliate, etc */ /* todo: auto-retaliate, etc */
/* todo: death sequence for infantry based on inflictor */ /* todo: death sequence for infantry based on inflictor */
/* todo: start smoking if < conditionYellow and took damage, and not already smoking */ /* todo: start smoking if < conditionYellow and took damage, and not already smoking */
if (Health <= 0) return; /* overkill! don't count extra hits as more kills! */ if (Health <= 0) return; /* overkill! don't count extra hits as more kills! */
Health -= damage; Health -= damage;
if (Health <= 0) if (Health <= 0)
{ {
Health = 0; Health = 0;
if (attacker.Owner != null) if (attacker.Owner != null)
attacker.Owner.Kills++; attacker.Owner.Kills++;
Game.world.AddFrameEndTask(w => w.Remove(this)); Game.world.AddFrameEndTask(w => w.Remove(this));
if (Owner == Game.LocalPlayer) if (Owner == Game.LocalPlayer)
Game.PlaySound("unitlst1.aud", false); Game.PlaySound("unitlst1.aud", false);
/* todo: explosion */ /* todo: explosion */
} }
} }
} }
} }

View File

@@ -87,7 +87,8 @@ namespace OpenRa.Game.Traits
List<int2> path; List<int2> path;
int moveFraction, moveFractionTotal; int moveFraction, moveFractionTotal;
float2 from, to; float2 from, to;
int fromFacing, toFacing;
Action<Actor, Mobile> OnComplete; Action<Actor, Mobile> OnComplete;
@@ -129,28 +130,41 @@ namespace OpenRa.Game.Traits
path.RemoveAt( path.Count - 1 ); path.RemoveAt( path.Count - 1 );
moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 35 : 25; moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 35 : 25;
from = CenterOfCell( mobile.fromCell ); from = CenterOfCell( mobile.fromCell );
to = BetweenCells( mobile.fromCell, mobile.toCell ); to = BetweenCells( mobile.fromCell, mobile.toCell );
CalculateMoveFraction();
fromFacing = mobile.facing;
toFacing = mobile.facing;
OnComplete = OnCompleteFirstHalf; OnComplete = OnCompleteFirstHalf;
} }
mobile.currentAction.Tick( self, mobile ); mobile.currentAction.Tick( self, mobile );
} }
void TickMove( Actor self, Mobile mobile ) void TickMove( Actor self, Mobile mobile )
{ {
moveFraction += ( self.unitInfo as UnitInfo.MobileInfo ).Speed; moveFraction += ( self.unitInfo as UnitInfo.MobileInfo ).Speed;
UpdateCenterLocation( self, (float)moveFraction / moveFractionTotal, from, to ); UpdateCenterLocation( self, mobile, (float)moveFraction / moveFractionTotal );
if( moveFraction >= moveFractionTotal ) if( moveFraction >= moveFractionTotal )
{ {
moveFraction -= moveFractionTotal; moveFraction -= moveFractionTotal;
OnComplete( self, mobile ); OnComplete( self, mobile );
mobile.fromCell = mobile.toCell; //mobile.fromCell = mobile.toCell;
} }
return; return;
} }
static void UpdateCenterLocation( Actor self, float frac, float2 from, float2 to ) void UpdateCenterLocation( Actor self, Mobile mobile, float frac )
{ {
self.CenterLocation = float2.Lerp( from, to, frac ); self.CenterLocation = float2.Lerp( from, to, frac );
if( moveFraction >= moveFractionTotal )
mobile.facing = toFacing;
else
mobile.facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
}
void CalculateMoveFraction()
{
var d = to - from;
moveFractionTotal = (int)Math.Sqrt( d.X * d.X + d.Y * d.Y ) * (25 / 6);
} }
static float2 CenterOfCell( int2 loc ) static float2 CenterOfCell( int2 loc )
@@ -164,17 +178,38 @@ namespace OpenRa.Game.Traits
} }
void OnCompleteFirstHalf( Actor self, Mobile mobile ) void OnCompleteFirstHalf( Actor self, Mobile mobile )
{ {
from = BetweenCells( mobile.fromCell, mobile.toCell ); if( path.Count > 0 )
to = CenterOfCell( mobile.toCell ); {
OnComplete = OnCompleteSecondHalf; var nextCell = path[ path.Count - 1 ];
if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) )
{
path.RemoveAt( path.Count - 1 );
from = BetweenCells( mobile.fromCell, mobile.toCell );
to = BetweenCells( mobile.toCell, nextCell );
CalculateMoveFraction();
mobile.fromCell = mobile.toCell;
mobile.toCell = nextCell;
fromFacing = mobile.facing;
toFacing = Util.GetNearestFacing( fromFacing, Util.GetFacing( mobile.toCell-mobile.fromCell, fromFacing ) );
OnComplete = OnCompleteFirstHalf;
return;
}
}
from = BetweenCells( mobile.fromCell, mobile.toCell );
to = CenterOfCell( mobile.toCell );
CalculateMoveFraction();
fromFacing = toFacing = mobile.facing;
OnComplete = OnCompleteSecondHalf;
mobile.fromCell = mobile.toCell;
} }
void OnCompleteSecondHalf( Actor self, Mobile mobile ) void OnCompleteSecondHalf( Actor self, Mobile mobile )
{ {
moveFractionTotal = 0; moveFractionTotal = 0;
self.CenterLocation = CenterOfCell( mobile.toCell ); self.CenterLocation = CenterOfCell( mobile.toCell );
OnComplete = null; OnComplete = null;
mobile.fromCell = mobile.toCell;
} }
} }
} }

View File

@@ -43,5 +43,15 @@ namespace OpenRa.Game.Traits
return highest * 8; return highest * 8;
} }
public static int GetNearestFacing( int facing, int desiredFacing )
{
var turn = desiredFacing - facing;
if( turn > 128 )
turn -= 256;
if( turn < -128 )
turn += 256;
return facing + turn;
}
} }
} }