Some thoughts towards improving our bogus idle handling. Untested.

This commit is contained in:
Paul Chote
2010-11-29 13:15:44 +13:00
parent 7850acc6fb
commit c7f1d08748
7 changed files with 97 additions and 149 deletions

View File

@@ -68,7 +68,7 @@ namespace OpenRA
public void Tick() public void Tick()
{ {
if (currentActivity == null) if (currentActivity == null || currentActivity is Idle)
foreach (var ni in TraitsImplementing<INotifyIdle>()) foreach (var ni in TraitsImplementing<INotifyIdle>())
ni.TickIdle(this); ni.TickIdle(this);

View File

@@ -1,47 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{
public class IdleAnimation : Idle
{
string sequence;
int delay;
public IdleAnimation(string sequence, int delay)
{
this.sequence = sequence;
this.delay = delay;
}
bool active = true;
public override IActivity Tick(Actor self)
{
if (!active) return NextActivity;
if (delay > 0 && --delay == 0)
self.Trait<RenderInfantry>().anim.PlayThen(sequence, () => active = false);
return this;
}
protected override bool OnCancel( Actor self )
{
active = false;
return true;
}
}
}

View File

@@ -18,43 +18,6 @@ namespace OpenRA.Mods.RA
class AutoHeal : INotifyIdle class AutoHeal : INotifyIdle
{ {
public void TickIdle( Actor self )
{
self.QueueActivity( new IdleHealActivity() );
}
class IdleHealActivity : Idle
{
Actor currentTarget;
IActivity inner;
public override IActivity Tick( Actor self )
{
if( inner == null )
{
if( NextActivity != null )
return NextActivity;
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
if (NeedsNewTarget(self))
{
currentTarget = ChooseTarget(self, range);
if( currentTarget != null )
inner = self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( currentTarget ), false );
}
}
if( inner != null )
{
if( NeedsNewTarget(self) )
inner.Cancel( self );
inner = Util.RunActivity( self, inner );
}
return this;
}
bool NeedsNewTarget(Actor self) bool NeedsNewTarget(Actor self)
{ {
var attack = self.Trait<AttackBase>(); var attack = self.Trait<AttackBase>();
@@ -84,6 +47,19 @@ namespace OpenRA.Mods.RA
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
.FirstOrDefault(); .FirstOrDefault();
} }
Actor currentTarget;
public void TickIdle( Actor self )
{
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
if (NeedsNewTarget(self))
{
var currentTarget = ChooseTarget(self, range);
if( currentTarget != null )
self.QueueActivity(self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( currentTarget ), false ));
}
} }
} }
} }

View File

@@ -39,33 +39,13 @@ namespace OpenRA.Mods.RA
public void TickIdle( Actor self ) public void TickIdle( Actor self )
{ {
self.QueueActivity( new IdleAttackActivity() );
}
class IdleAttackActivity : Idle
{
Actor currentTarget;
IActivity inner;
public override IActivity Tick( Actor self )
{
if( NextActivity != null && inner != null )
inner.Cancel( self );
if( inner == null )
{
if( NextActivity != null )
return NextActivity;
var attack = self.Trait<AttackBase>(); var attack = self.Trait<AttackBase>();
currentTarget = attack.ScanForTarget(self, null); var currentTarget = attack.ScanForTarget(self, null);
if( currentTarget != null ) if( currentTarget != null )
inner = attack.GetAttackActivity( self, Target.FromActor(currentTarget), self.Info.Traits.Get<AutoTargetInfo>().AllowMovement ); self.QueueActivity(attack.GetAttackActivity( self,
} Target.FromActor(currentTarget),
if( inner != null ) self.Info.Traits.Get<AutoTargetInfo>().AllowMovement
inner = Util.RunActivity( self, inner ); ));
return this;
}
} }
} }
} }

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Mods.RA.Render;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
@@ -20,24 +21,61 @@ namespace OpenRA.Mods.RA
} }
// infantry prone behavior // infantry prone behavior
class IdleAnimation : INotifyDamage, INotifyIdle class IdleAnimation : ITick, INotifyIdle
{ {
IdleAnimationInfo Info; IdleAnimationInfo Info;
string sequence;
int delay;
bool active, waiting;
public IdleAnimation(IdleAnimationInfo info) public IdleAnimation(IdleAnimationInfo info)
{ {
Info = info; Info = info;
} }
public void Damaged(Actor self, AttackInfo e) public void Tick(Actor self)
{ {
if (self.GetCurrentActivity() is Activities.IdleAnimation) if (active)
self.CancelActivity(); {
//System.Console.WriteLine("active: {0} ({1})", self.Info.Name, self.ActorID);
return;
}
if (!self.IsIdle)
{
//System.Console.WriteLine("notidle: {0} ({1}) ",self.Info.Name, self.ActorID);
active = false;
waiting = false;
return;
}
if (delay > 0 && --delay == 0)
{
System.Console.WriteLine("activate: {0} ({1})",self.Info.Name, self.ActorID);
active = true;
waiting = false;
self.Trait<RenderInfantry>().anim.PlayThen(sequence, () =>
{
//System.Console.WriteLine("finished: {0} ({1}) ",self.Info.Name, self.ActorID);
active = false;
});
}
} }
public void TickIdle(Actor self) public void TickIdle(Actor self)
{ {
self.QueueActivity(new Activities.IdleAnimation(Info.Animations.Random(self.World.SharedRandom), //if (active)
Info.IdleWaitTicks)); // System.Console.WriteLine("idleactive: {0} ({1}) ",self.Info.Name, self.ActorID);
//if (waiting)
// System.Console.WriteLine("idlewaiting: {0} ({1}) ",self.Info.Name, self.ActorID);
if (active || waiting)
return;
waiting = true;
sequence = Info.Animations.Random(self.World.SharedRandom);
delay = Info.IdleWaitTicks;
//System.Console.WriteLine("TickIdle: {2} ({3}) set {0} {1}",sequence,delay, self.Info.Name, self.ActorID);
} }
} }
} }

View File

@@ -299,7 +299,6 @@
<Compile Include="HackyAI.cs" /> <Compile Include="HackyAI.cs" />
<Compile Include="RALoadScreen.cs" /> <Compile Include="RALoadScreen.cs" />
<Compile Include="NullLoadScreen.cs" /> <Compile Include="NullLoadScreen.cs" />
<Compile Include="Activities\IdleAnimation.cs" />
<Compile Include="IdleAnimation.cs" /> <Compile Include="IdleAnimation.cs" />
<Compile Include="World\GotoNextBase.cs" /> <Compile Include="World\GotoNextBase.cs" />
<Compile Include="World\SmudgeLayer.cs" /> <Compile Include="World\SmudgeLayer.cs" />

View File

@@ -67,15 +67,17 @@ namespace OpenRA.Mods.RA.Render
{ {
base.Tick(self); base.Tick(self);
if (inAttack) return; if (inAttack) return;
if (self.GetCurrentActivity() is Activities.IdleAnimation) return; if (self.IsIdle) return;
if (ChooseMoveAnim(self)) return; if (ChooseMoveAnim(self)) return;
if (IsProne(self)) // TODO: Pick new animation only on damage or idle notifications
anim.PlayFetchIndex("crawl", () => 0); /* what a hack. */ //if (IsProne(self))
else // anim.PlayFetchIndex("crawl", () => 0); /* what a hack. */
anim.Play("stand"); //else
// anim.Play("stand");
} }
public void Damaged(Actor self, AttackInfo e) public void Damaged(Actor self, AttackInfo e)
{ {
if (e.DamageState == DamageState.Dead) if (e.DamageState == DamageState.Dead)