smooth unit-movement. Doesn't look right yet, but it's getting there.
This commit is contained in:
@@ -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 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user