Moved Activity and friends into separate files.

This commit is contained in:
Bob
2009-11-02 20:22:12 +13:00
parent 279f13bc5b
commit ddc91ddafa
9 changed files with 400 additions and 372 deletions

View File

@@ -299,7 +299,7 @@ namespace OpenRa.Game
unit = new Actor(name, (1 / 24f * producer.CenterLocation).ToInt2(), player);
var mobile = unit.traits.Get<Mobile>();
mobile.facing = 128;
mobile.QueueActivity(new Mobile.MoveTo(unit.Location + new int2(0, 3)));
mobile.QueueActivity(new Traits.Activities.Move(unit.Location + new int2(0, 3)));
}
world.Add( unit );

View File

@@ -77,6 +77,7 @@
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="OrderManager.cs" />
<Compile Include="Traits\AcceptsOre.cs" />
<Compile Include="Traits\Activities\Activity.cs" />
<Compile Include="Traits\Activities\DeployMcv.cs" />
<Compile Include="Actor.cs" />
<Compile Include="Bullet.cs" />
@@ -128,6 +129,8 @@
<Compile Include="TerrainCosts.cs" />
<Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Graphics\TreeCache.cs" />
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\AttackTurreted.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\Harvester.cs" />

View File

@@ -197,11 +197,6 @@ namespace OpenRa.Game
return null;
}
static bool IsAutoCompleting(string group)
{
return group != "Building";
}
SidebarItem mouseOverItem;
void MouseHandler(MouseInput mi)

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits.Activities
{
interface Activity
{
Activity NextActivity { get; set; }
void Tick( Actor self, Mobile mobile );
void Cancel( Actor self, Mobile mobile );
}
}

View File

@@ -5,9 +5,9 @@ using System.Text;
namespace OpenRa.Game.Traits.Activities
{
class DeployMcv : Mobile.CurrentActivity
class DeployMcv : Activity
{
public Mobile.CurrentActivity NextActivity { get; set; }
public Activity NextActivity { get; set; }
public void Tick( Actor self, Mobile mobile )
{

View File

@@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits.Activities
{
class Move : Activity
{
public Activity NextActivity { get; set; }
int2? destination;
public List<int2> path;
Func<Actor, Mobile, List<int2>> getPath;
MovePart move;
public Move( int2 destination )
{
this.getPath = ( self, mobile ) => Game.PathFinder.FindUnitPath(
self.Location, destination,
mobile.GetMovementType() );
this.destination = destination;
}
public Move( Actor target, int range )
{
this.getPath = ( self, mobile ) => Game.PathFinder.FindUnitPathToRange(
self.Location, target.Location,
mobile.GetMovementType(), range );
this.destination = null;
}
static bool CanEnterCell( int2 c, Actor self )
{
var u = Game.UnitInfluence.GetUnitAt( c );
var b = Game.BuildingInfluence.GetBuildingAt( c );
return ( u == null || u == self ) && b == null;
}
public void Tick( Actor self, Mobile mobile )
{
if( move != null )
{
move.TickMove( self, mobile, this );
return;
}
if( destination == self.Location )
{
mobile.InternalSetActivity( NextActivity );
return;
}
if( path == null ) path = getPath( self, mobile ).TakeWhile( a => a != self.Location ).ToList();
if( path.Count == 0 )
{
destination = mobile.toCell;
return;
}
destination = path[ 0 ];
var nextCell = PopPath( self, mobile );
if( nextCell == null )
return;
int2 dir = nextCell.Value - mobile.fromCell;
var firstFacing = Util.GetFacing( dir, mobile.facing );
if( firstFacing != mobile.facing )
{
var t = new Turn( firstFacing ) { NextActivity = this };
mobile.InternalSetActivity( t );
path.Add( nextCell.Value );
t.Tick( self, mobile );
}
else
{
mobile.toCell = nextCell.Value;
move = new MoveFirstHalf(
CenterOfCell( mobile.fromCell ),
BetweenCells( mobile.fromCell, mobile.toCell ),
mobile.facing,
mobile.facing,
0 );
Game.UnitInfluence.Update( mobile );
move.TickMove( self, mobile, this );
}
}
int2? PopPath( Actor self, Mobile mobile )
{
if( path.Count == 0 ) return null;
var nextCell = path[ path.Count - 1 ];
if( !CanEnterCell( nextCell, self ) )
{
if( ( mobile.toCell - destination.Value ).LengthSquared <= 8 )
{
path.Clear();
return null;
}
Game.UnitInfluence.Remove( mobile );
var newPath = Game.PathFinder.FindPathToPath( self.Location, path, mobile.GetMovementType() )
.TakeWhile( a => a != self.Location )
.ToList();
Game.UnitInfluence.Add( mobile );
if( newPath.Count == 0 )
return null;
while( path[ path.Count - 1 ] != newPath[ 0 ] )
path.RemoveAt( path.Count - 1 );
for( int i = 1 ; i < newPath.Count ; i++ )
path.Add( newPath[ i ] );
if( path.Count == 0 )
return null;
nextCell = path[ path.Count - 1 ];
}
path.RemoveAt( path.Count - 1 );
return nextCell;
}
static float2 CenterOfCell( int2 loc )
{
return new float2( 12, 12 ) + Game.CellSize * (float2)loc;
}
static float2 BetweenCells( int2 from, int2 to )
{
return 0.5f * ( CenterOfCell( from ) + CenterOfCell( to ) );
}
abstract class MovePart
{
public readonly float2 from, to;
public readonly int fromFacing, toFacing;
public int moveFraction;
public readonly int moveFractionTotal;
public MovePart( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
{
this.from = from;
this.to = to;
this.fromFacing = fromFacing;
this.toFacing = toFacing;
this.moveFraction = startingFraction;
this.moveFractionTotal = (int)( to - from ).Length * ( 25 / 6 );
}
public void TickMove( Actor self, Mobile mobile, Move parent )
{
var oldFraction = moveFraction;
var oldTotal = moveFractionTotal;
moveFraction += ( self.unitInfo as UnitInfo.MobileInfo ).Speed;
UpdateCenterLocation( self, mobile );
if( moveFraction >= moveFractionTotal )
{
parent.move = OnComplete( self, mobile, parent );
if( parent.move == null )
UpdateCenterLocation( self, mobile );
}
}
void UpdateCenterLocation( Actor self, Mobile mobile )
{
var frac = (float)moveFraction / moveFractionTotal;
self.CenterLocation = float2.Lerp( from, to, frac );
if( moveFraction >= moveFractionTotal )
mobile.facing = toFacing & 0xFF;
else
mobile.facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
}
protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent );
}
class MoveFirstHalf : MovePart
{
public MoveFirstHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
{
}
protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent )
{
var nextCell = parent.PopPath( self, mobile );
if( nextCell != null )
{
if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) )
{
var ret = new MoveFirstHalf(
BetweenCells( mobile.fromCell, mobile.toCell ),
BetweenCells( mobile.toCell, nextCell.Value ),
mobile.facing,
Util.GetNearestFacing( mobile.facing, Util.GetFacing( nextCell.Value - mobile.toCell, mobile.facing ) ),
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
mobile.toCell = nextCell.Value;
Game.UnitInfluence.Update( mobile );
return ret;
}
else
parent.path.Add( nextCell.Value );
}
var ret2 = new MoveSecondHalf(
BetweenCells( mobile.fromCell, mobile.toCell ),
CenterOfCell( mobile.toCell ),
mobile.facing,
mobile.facing,
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
Game.UnitInfluence.Update( mobile );
return ret2;
}
}
class MoveSecondHalf : MovePart
{
public MoveSecondHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
{
}
protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent )
{
self.CenterLocation = CenterOfCell( mobile.toCell );
mobile.fromCell = mobile.toCell;
return null;
}
}
public void Cancel( Actor self, Mobile mobile )
{
path = new List<int2>();
NextActivity = null;
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits.Activities
{
class Turn : Activity
{
public Activity NextActivity { get; set; }
public int desiredFacing;
public Turn( int desiredFacing )
{
this.desiredFacing = desiredFacing;
}
public void Tick( Actor self, Mobile mobile )
{
if( desiredFacing == mobile.facing )
{
mobile.InternalSetActivity( NextActivity );
if( NextActivity != null )
NextActivity.Tick( self, mobile );
return;
}
Util.TickFacing( ref mobile.facing, desiredFacing, self.unitInfo.ROT );
}
public void Cancel( Actor self, Mobile mobile )
{
desiredFacing = mobile.facing;
NextActivity = null;
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using OpenRa.Game.GameRules;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits.Activities;
namespace OpenRa.Game.Traits
{
@@ -16,7 +17,7 @@ namespace OpenRa.Game.Traits
public int facing;
public int Voice = Game.CosmeticRandom.Next(2);
CurrentActivity currentActivity;
Activity currentActivity;
public Mobile(Actor self)
{
@@ -25,7 +26,7 @@ namespace OpenRa.Game.Traits
Game.UnitInfluence.Update( this );
}
public void QueueActivity( CurrentActivity nextActivity )
public void QueueActivity( Activity nextActivity )
{
if( currentActivity == null )
{
@@ -40,6 +41,11 @@ namespace OpenRa.Game.Traits
act.NextActivity = nextActivity;
}
public void InternalSetActivity( Activity activity )
{
currentActivity = activity;
}
public void Tick(Actor self)
{
if( currentActivity != null )
@@ -80,280 +86,9 @@ namespace OpenRa.Game.Traits
return vi.Tracked ? UnitMovementType.Track : UnitMovementType.Wheel;
}
public interface CurrentActivity
{
CurrentActivity NextActivity { get; set; }
void Tick( Actor self, Mobile mobile );
void Cancel( Actor self, Mobile mobile );
}
public class Turn : CurrentActivity
{
public CurrentActivity NextActivity { get; set; }
public int desiredFacing;
public Turn( int desiredFacing )
{
this.desiredFacing = desiredFacing;
}
public void Tick( Actor self, Mobile mobile )
{
if( desiredFacing == mobile.facing )
{
mobile.currentActivity = NextActivity;
if( NextActivity != null )
NextActivity.Tick( self, mobile );
return;
}
Util.TickFacing( ref mobile.facing, desiredFacing, self.unitInfo.ROT );
}
public void Cancel( Actor self, Mobile mobile )
{
desiredFacing = mobile.facing;
NextActivity = null;
}
}
public class MoveTo : CurrentActivity
{
public CurrentActivity NextActivity { get; set; }
int2? destination;
public List<int2> path;
Func<Actor, Mobile, List<int2>> getPath;
MovePart move;
public MoveTo( int2 destination )
{
this.getPath = (self, mobile) => Game.PathFinder.FindUnitPath(
self.Location, destination,
mobile.GetMovementType());
this.destination = destination;
}
public MoveTo(Actor target, int range)
{
this.getPath = (self, mobile) => Game.PathFinder.FindUnitPathToRange(
self.Location, target.Location,
mobile.GetMovementType(), range);
this.destination = null;
}
static bool CanEnterCell(int2 c, Actor self)
{
var u = Game.UnitInfluence.GetUnitAt(c);
var b = Game.BuildingInfluence.GetBuildingAt(c);
return (u == null || u == self) && b == null;
}
public void Tick( Actor self, Mobile mobile )
{
if( move != null )
{
move.TickMove( self, mobile, this );
return;
}
if( destination == self.Location )
{
mobile.currentActivity = NextActivity;
return;
}
if (path == null) path = getPath(self, mobile).TakeWhile(a => a != self.Location).ToList();
if (path.Count == 0)
{
destination = mobile.toCell;
return;
}
destination = path[0];
var nextCell = PopPath( self, mobile );
if( nextCell == null )
return;
int2 dir = nextCell.Value - mobile.fromCell;
var firstFacing = Util.GetFacing( dir, mobile.facing );
if( firstFacing != mobile.facing )
{
mobile.currentActivity = new Turn( firstFacing ) { NextActivity = this };
path.Add( nextCell.Value );
}
else
{
mobile.toCell = nextCell.Value;
move = new MoveFirstHalf(
CenterOfCell( mobile.fromCell ),
BetweenCells( mobile.fromCell, mobile.toCell ),
mobile.facing,
mobile.facing,
0 );
Game.UnitInfluence.Update( mobile );
}
mobile.currentActivity.Tick( self, mobile );
}
int2? PopPath( Actor self, Mobile mobile )
{
if( path.Count == 0 ) return null;
var nextCell = path[ path.Count - 1 ];
if( !CanEnterCell( nextCell, self ) )
{
if( ( mobile.toCell - destination.Value ).LengthSquared <= 8 )
{
path.Clear();
return null;
}
Game.UnitInfluence.Remove( mobile );
var newPath = Game.PathFinder.FindPathToPath( self.Location, path, mobile.GetMovementType() )
.TakeWhile( a => a != self.Location )
.ToList();
Game.UnitInfluence.Add( mobile );
if( newPath.Count == 0 )
return null;
while( path[ path.Count - 1 ] != newPath[ 0 ] )
path.RemoveAt( path.Count - 1 );
for( int i = 1 ; i < newPath.Count ; i++ )
path.Add( newPath[ i ] );
if( path.Count == 0 )
return null;
nextCell = path[ path.Count - 1 ];
}
path.RemoveAt( path.Count - 1 );
return nextCell;
}
static float2 CenterOfCell( int2 loc )
{
return new float2( 12, 12 ) + Game.CellSize * (float2)loc;
}
static float2 BetweenCells( int2 from, int2 to )
{
return 0.5f * ( CenterOfCell( from ) + CenterOfCell( to ) );
}
abstract class MovePart
{
public readonly float2 from, to;
public readonly int fromFacing, toFacing;
public int moveFraction;
public readonly int moveFractionTotal;
public MovePart( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
{
this.from = from;
this.to = to;
this.fromFacing = fromFacing;
this.toFacing = toFacing;
this.moveFraction = startingFraction;
this.moveFractionTotal = (int)( to - from ).Length * ( 25 / 6 );
}
public void TickMove( Actor self, Mobile mobile, MoveTo parent )
{
var oldFraction = moveFraction;
var oldTotal = moveFractionTotal;
moveFraction += ( self.unitInfo as UnitInfo.MobileInfo ).Speed;
UpdateCenterLocation( self, mobile );
if( moveFraction >= moveFractionTotal )
{
parent.move = OnComplete( self, mobile, parent );
if( parent.move == null )
UpdateCenterLocation( self, mobile );
}
}
void UpdateCenterLocation( Actor self, Mobile mobile )
{
var frac = (float)moveFraction / moveFractionTotal;
self.CenterLocation = float2.Lerp( from, to, frac );
if( moveFraction >= moveFractionTotal )
mobile.facing = toFacing & 0xFF;
else
mobile.facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
}
protected abstract MovePart OnComplete( Actor self, Mobile mobile, MoveTo parent );
}
class MoveFirstHalf : MovePart
{
public MoveFirstHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
{
}
protected override MovePart OnComplete( Actor self, Mobile mobile, MoveTo parent )
{
var nextCell = parent.PopPath( self, mobile );
if( nextCell != null )
{
if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) )
{
var ret = new MoveFirstHalf(
BetweenCells( mobile.fromCell, mobile.toCell ),
BetweenCells( mobile.toCell, nextCell.Value ),
mobile.facing,
Util.GetNearestFacing( mobile.facing, Util.GetFacing( nextCell.Value - mobile.toCell, mobile.facing ) ),
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
mobile.toCell = nextCell.Value;
Game.UnitInfluence.Update( mobile );
return ret;
}
else
parent.path.Add( nextCell.Value );
}
var ret2 = new MoveSecondHalf(
BetweenCells( mobile.fromCell, mobile.toCell ),
CenterOfCell( mobile.toCell ),
mobile.facing,
mobile.facing,
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
Game.UnitInfluence.Update( mobile );
return ret2;
}
}
class MoveSecondHalf : MovePart
{
public MoveSecondHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
{
}
protected override MovePart OnComplete( Actor self, Mobile mobile, MoveTo parent )
{
self.CenterLocation = CenterOfCell( mobile.toCell );
mobile.fromCell = mobile.toCell;
return null;
}
}
public void Cancel( Actor self, Mobile mobile )
{
path = new List<int2>();
NextActivity = null;
}
}
public IEnumerable<int2> GetCurrentPath()
{
var move = currentActivity as MoveTo;
var move = currentActivity as Traits.Activities.Move;
if (move == null || move.path == null) return new int2[] { };
return Enumerable.Reverse(move.path);
}

View File

@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.Traits;
using OpenRa.Game.GameRules;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
@@ -17,7 +16,7 @@ namespace OpenRa.Game
{
var mobile = order.Subject.traits.Get<Mobile>();
mobile.Cancel( order.Subject );
mobile.QueueActivity( new Mobile.MoveTo( order.TargetLocation ) );
mobile.QueueActivity( new Traits.Activities.Move( order.TargetLocation ) );
var attackBase = order.Subject.traits.WithInterface<AttackBase>().FirstOrDefault();
if( attackBase != null )
@@ -37,7 +36,7 @@ namespace OpenRa.Game
var range = Rules.WeaponInfo[ weapon ].Range;
mobile.QueueActivity(
new Mobile.MoveTo( order.TargetActor,
new Traits.Activities.Move( order.TargetActor,
Math.Max( 0, (int)range - RangeTolerance ) ) );
}
@@ -50,7 +49,7 @@ namespace OpenRa.Game
break; /* throw the order on the floor */
var mobile = order.Subject.traits.Get<Mobile>();
mobile.QueueActivity( new Mobile.Turn( 96 ) );
mobile.QueueActivity( new Traits.Activities.Turn( 96 ) );
mobile.QueueActivity( new Traits.Activities.DeployMcv() );
break;
}
@@ -58,8 +57,8 @@ namespace OpenRa.Game
{
var mobile = order.Subject.traits.Get<Mobile>();
mobile.Cancel(order.Subject);
mobile.QueueActivity(new Mobile.MoveTo(order.TargetActor.Location + new int2(1, 2)));
mobile.QueueActivity(new Mobile.Turn(64));
mobile.QueueActivity( new Traits.Activities.Move( order.TargetActor.Location + new int2( 1, 2 ) ) );
mobile.QueueActivity( new Traits.Activities.Turn( 64 ) );
/* todo: actual deliver activity! [animation + add cash] */
break;