From 082ea6ba73cf510eba86b450216ea9aae5c22281 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Wed, 14 Oct 2015 22:33:14 +0100 Subject: [PATCH] Refactor animation classes. Specify pause function in constructors of Animation if required, and remove the unused pause function from AnimationWithOffset. Cleanup Animation.cs and reduce code duplication. --- OpenRA.Game/Graphics/Animation.cs | 83 ++++++++++--------- OpenRA.Game/Graphics/AnimationWithOffset.cs | 18 ++-- OpenRA.Mods.Common/Effects/Bullet.cs | 2 +- OpenRA.Mods.Common/Effects/RepairIndicator.cs | 3 +- .../Traits/Attack/AttackGarrisoned.cs | 1 - .../Traits/Render/WithDecoration.cs | 3 +- .../Traits/Render/WithHarvestOverlay.cs | 1 - .../Traits/Render/WithIdleOverlay.cs | 4 +- .../Traits/Render/WithMuzzleOverlay.cs | 1 - .../Traits/Render/WithParachute.cs | 1 - .../Traits/Render/WithRepairOverlay.cs | 4 +- .../Traits/Render/WithSpriteBarrel.cs | 2 +- .../Traits/Render/WithSpriteBody.cs | 11 +-- .../Traits/Render/WithSpriteRotorOverlay.cs | 2 +- .../Traits/Render/WithSpriteTurret.cs | 2 +- 15 files changed, 67 insertions(+), 71 deletions(-) diff --git a/OpenRA.Game/Graphics/Animation.cs b/OpenRA.Game/Graphics/Animation.cs index 6637e4b1ac..0cd0f91d2b 100644 --- a/OpenRA.Game/Graphics/Animation.cs +++ b/OpenRA.Game/Graphics/Animation.cs @@ -17,36 +17,35 @@ namespace OpenRA.Graphics { public class Animation { - readonly int defaultTick = 40; // 25 fps == 40 ms public ISpriteSequence CurrentSequence { get; private set; } - public bool IsDecoration = false; - public Func Paused; - - readonly Func facingFunc; - - int frame = 0; - bool backwards = false; - - string name; - - bool tickAlways; - - public string Name { get { return name; } } + public string Name { get; private set; } + public bool IsDecoration { get; set; } readonly SequenceProvider sequenceProvider; + readonly Func facingFunc; + readonly Func paused; + + int frame; + bool backwards; + bool tickAlways; + int timeUntilNextFrame; + Action tickFunc = () => { }; public Animation(World world, string name) : this(world, name, () => 0) { } public Animation(World world, string name, Func facingFunc) - : this(world.Map.SequenceProvider, name, facingFunc) { } + : this(world, name, facingFunc, null) { } - public Animation(SequenceProvider sequenceProvider, string name, Func facingFunc) + public Animation(World world, string name, Func paused) + : this(world, name, () => 0, paused) { } + + public Animation(World world, string name, Func facingFunc, Func paused) { - this.sequenceProvider = sequenceProvider; - this.name = name.ToLowerInvariant(); - this.tickFunc = () => { }; + sequenceProvider = world.Map.SequenceProvider; + Name = name.ToLowerInvariant(); this.facingFunc = facingFunc; + this.paused = paused; } public int CurrentFrame { get { return backwards ? CurrentSequence.Start + CurrentSequence.Length - frame - 1 : frame; } } @@ -76,12 +75,23 @@ namespace OpenRA.Graphics PlayThen(sequenceName, null); } + int CurrentSequenceTickOrDefault() + { + const int DefaultTick = 40; // 25 fps == 40 ms + return CurrentSequence != null ? CurrentSequence.Tick : DefaultTick; + } + + void PlaySequence(string sequenceName) + { + CurrentSequence = GetSequence(sequenceName); + timeUntilNextFrame = CurrentSequenceTickOrDefault(); + } + public void PlayRepeating(string sequenceName) { backwards = false; tickAlways = false; - CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); - timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + PlaySequence(sequenceName); frame = 0; tickFunc = () => @@ -97,9 +107,8 @@ namespace OpenRA.Graphics if (!HasSequence(sequenceName)) return false; - CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); - var tick = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; - timeUntilNextFrame = Math.Min(tick, timeUntilNextFrame); + CurrentSequence = GetSequence(sequenceName); + timeUntilNextFrame = Math.Min(CurrentSequenceTickOrDefault(), timeUntilNextFrame); frame %= CurrentSequence.Length; return true; } @@ -108,8 +117,7 @@ namespace OpenRA.Graphics { backwards = false; tickAlways = false; - CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); - timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + PlaySequence(sequenceName); frame = 0; tickFunc = () => @@ -134,8 +142,7 @@ namespace OpenRA.Graphics { backwards = false; tickAlways = true; - CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); - timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + PlaySequence(sequenceName); frame = func(); tickFunc = () => frame = func(); @@ -144,8 +151,7 @@ namespace OpenRA.Graphics public void PlayFetchDirection(string sequenceName, Func direction) { tickAlways = false; - CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); - timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + PlaySequence(sequenceName); frame = 0; tickFunc = () => @@ -159,17 +165,12 @@ namespace OpenRA.Graphics }; } - int timeUntilNextFrame; - Action tickFunc; - public void Tick() { - if (Paused == null || !Paused()) + if (paused == null || !paused()) Tick(40); // tick one frame } - public bool HasSequence(string seq) { return sequenceProvider.HasSequence(name, seq); } - public void Tick(int t) { if (tickAlways) @@ -180,7 +181,7 @@ namespace OpenRA.Graphics while (timeUntilNextFrame <= 0) { tickFunc(); - timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + timeUntilNextFrame += CurrentSequenceTickOrDefault(); } } } @@ -189,17 +190,19 @@ namespace OpenRA.Graphics { newImage = newImage.ToLowerInvariant(); - if (name != newImage) + if (Name != newImage) { - name = newImage.ToLowerInvariant(); + Name = newImage; if (!ReplaceAnim(CurrentSequence.Name)) ReplaceAnim(newAnimIfMissing); } } + public bool HasSequence(string seq) { return sequenceProvider.HasSequence(Name, seq); } + public ISpriteSequence GetSequence(string sequenceName) { - return sequenceProvider.GetSequence(name, sequenceName); + return sequenceProvider.GetSequence(Name, sequenceName); } public string GetRandomExistingSequence(string[] sequences, MersenneTwister random) diff --git a/OpenRA.Game/Graphics/AnimationWithOffset.cs b/OpenRA.Game/Graphics/AnimationWithOffset.cs index 804bd74b19..88ce5a4e14 100644 --- a/OpenRA.Game/Graphics/AnimationWithOffset.cs +++ b/OpenRA.Game/Graphics/AnimationWithOffset.cs @@ -18,22 +18,20 @@ namespace OpenRA.Graphics public readonly Animation Animation; public readonly Func OffsetFunc; public readonly Func DisableFunc; - public readonly Func Paused; public readonly Func ZOffset; public AnimationWithOffset(Animation a, Func offset, Func disable) - : this(a, offset, disable, () => false, null) { } + : this(a, offset, disable, null) { } public AnimationWithOffset(Animation a, Func offset, Func disable, int zOffset) - : this(a, offset, disable, () => false, _ => zOffset) { } + : this(a, offset, disable, _ => zOffset) { } - public AnimationWithOffset(Animation a, Func offset, Func disable, Func pause, Func zOffset) + public AnimationWithOffset(Animation a, Func offset, Func disable, Func zOffset) { - this.Animation = a; - this.Animation.Paused = pause; - this.OffsetFunc = offset; - this.DisableFunc = disable; - this.ZOffset = zOffset; + Animation = a; + OffsetFunc = offset; + DisableFunc = disable; + ZOffset = zOffset; } public IEnumerable Render(Actor self, WorldRenderer wr, PaletteReference pal, float scale) @@ -47,7 +45,7 @@ namespace OpenRA.Graphics public static implicit operator AnimationWithOffset(Animation a) { - return new AnimationWithOffset(a, null, null, null, null); + return new AnimationWithOffset(a, null, null, null); } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/Effects/Bullet.cs b/OpenRA.Mods.Common/Effects/Bullet.cs index 71c998fb69..5bc476fd63 100644 --- a/OpenRA.Mods.Common/Effects/Bullet.cs +++ b/OpenRA.Mods.Common/Effects/Bullet.cs @@ -120,7 +120,7 @@ namespace OpenRA.Mods.Common.Effects if (!string.IsNullOrEmpty(info.Image)) { - anim = new Animation(world, info.Image, GetEffectiveFacing); + anim = new Animation(world, info.Image, new Func(GetEffectiveFacing)); anim.PlayRepeating(info.Sequences.Random(world.SharedRandom)); } diff --git a/OpenRA.Mods.Common/Effects/RepairIndicator.cs b/OpenRA.Mods.Common/Effects/RepairIndicator.cs index f491ad14df..05c3c32bee 100644 --- a/OpenRA.Mods.Common/Effects/RepairIndicator.cs +++ b/OpenRA.Mods.Common/Effects/RepairIndicator.cs @@ -29,8 +29,7 @@ namespace OpenRA.Mods.Common.Effects this.building = building; rb = building.Trait(); - anim = new Animation(building.World, rb.Info.IndicatorImage); - anim.Paused = () => !rb.RepairActive || rb.IsTraitDisabled; + anim = new Animation(building.World, rb.Info.IndicatorImage, () => !rb.RepairActive || rb.IsTraitDisabled); CycleRepairer(); } diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs b/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs index b36c0da401..727fbb4d35 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs @@ -165,7 +165,6 @@ namespace OpenRA.Mods.Common.Traits var muzzleFlash = new AnimationWithOffset(muzzleAnim, () => PortOffset(self, port), () => false, - () => false, p => RenderUtils.ZOffsetFromCenter(self, p, 1024)); muzzles.Add(muzzleFlash); diff --git a/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs index 23b41d285a..6acfeb4aea 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs @@ -79,8 +79,7 @@ namespace OpenRA.Mods.Common.Traits this.info = info; this.self = self; image = info.Image ?? self.Info.Name; - anim = new Animation(self.World, image); - anim.Paused = () => self.World.Paused; + anim = new Animation(self.World, image, () => self.World.Paused); anim.PlayRepeating(info.Sequence); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs index fecdb4bfac..aa6e953e6a 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs @@ -46,7 +46,6 @@ namespace OpenRA.Mods.Common.Traits rs.Add(new AnimationWithOffset(anim, () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => !visible, - () => false, p => ZOffsetFromCenter(self, p, 0)), info.Palette); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs index a3cad29148..32b2cba906 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs @@ -69,7 +69,8 @@ namespace OpenRA.Mods.Common.Traits var body = self.Trait(); buildComplete = !self.Info.HasTraitInfo(); // always render instantly for units - overlay = new Animation(self.World, rs.GetImage(self)); + overlay = new Animation(self.World, rs.GetImage(self), + () => (info.PauseOnLowPower && self.IsDisabled()) || !buildComplete); if (info.StartSequence != null) overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.StartSequence), () => overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence))); @@ -79,7 +80,6 @@ namespace OpenRA.Mods.Common.Traits var anim = new AnimationWithOffset(overlay, () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => IsTraitDisabled || !buildComplete, - () => (info.PauseOnLowPower && self.IsDisabled()) || !buildComplete, p => RenderUtils.ZOffsetFromCenter(self, p, 1)); rs.Add(anim, info.Palette, info.IsPlayerPalette); diff --git a/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs index 0acff4e932..6042ca0c59 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs @@ -69,7 +69,6 @@ namespace OpenRA.Mods.Common.Traits new AnimationWithOffset(muzzleFlash, () => info.IgnoreOffset ? WVec.Zero : armClosure.MuzzleOffset(self, barrel), () => IsTraitDisabled || !visible[barrel], - () => false, p => RenderUtils.ZOffsetFromCenter(self, p, 2))); } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs index bddf9ec297..55f0a6ac4c 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs @@ -105,7 +105,6 @@ namespace OpenRA.Mods.Common.Traits anim = new AnimationWithOffset(overlay, () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => IsTraitDisabled && !renderProlonged, - () => false, p => RenderUtils.ZOffsetFromCenter(self, p, 1)); var rs = self.Trait(); diff --git a/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs index 3bbb52a100..0d09674917 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs @@ -47,13 +47,13 @@ namespace OpenRA.Mods.Common.Traits var body = self.Trait(); buildComplete = !self.Info.HasTraitInfo(); // always render instantly for units - overlay = new Animation(self.World, rs.GetImage(self)); + overlay = new Animation(self.World, rs.GetImage(self), + () => info.PauseOnLowPower && self.IsDisabled()); overlay.PlayThen(info.Sequence, () => visible = false); var anim = new AnimationWithOffset(overlay, () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => !visible || !buildComplete, - () => info.PauseOnLowPower && self.IsDisabled(), p => RenderUtils.ZOffsetFromCenter(self, p, 1)); rs.Add(anim, info.Palette, info.IsPlayerPalette); diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs index 301075580a..ca507a8549 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Traits DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => turreted.TurretFacing); DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); rs.Add(new AnimationWithOffset( - DefaultAnimation, () => BarrelOffset(), () => IsTraitDisabled, () => false, p => RenderUtils.ZOffsetFromCenter(self, p, 0))); + DefaultAnimation, () => BarrelOffset(), () => IsTraitDisabled, p => RenderUtils.ZOffsetFromCenter(self, p, 0))); // Restrict turret facings to match the sprite turreted.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings; diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs index 24ee8239fc..5cdb19d28a 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs @@ -51,7 +51,12 @@ namespace OpenRA.Mods.Common.Traits { var rs = init.Self.Trait(); - DefaultAnimation = new Animation(init.World, rs.GetImage(init.Self), baseFacing); + Func paused = null; + if (info.PauseAnimationWhenDisabled) + paused = () => init.Self.IsDisabled() && + DefaultAnimation.CurrentSequence.Name == NormalizeSequence(init.Self, Info.Sequence); + + DefaultAnimation = new Animation(init.World, rs.GetImage(init.Self), baseFacing, paused); rs.Add(new AnimationWithOffset(DefaultAnimation, null, () => IsTraitDisabled)); if (info.StartSequence != null) @@ -59,10 +64,6 @@ namespace OpenRA.Mods.Common.Traits () => PlayCustomAnimationRepeating(init.Self, info.Sequence)); else DefaultAnimation.PlayRepeating(NormalizeSequence(init.Self, info.Sequence)); - - if (info.PauseAnimationWhenDisabled) - DefaultAnimation.Paused = () => - init.Self.IsDisabled() && DefaultAnimation.CurrentSequence.Name == NormalizeSequence(init.Self, Info.Sequence); } public string NormalizeSequence(Actor self, string sequence) diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteRotorOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteRotorOverlay.cs index 876a7cf03b..c5b221532e 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteRotorOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteRotorOverlay.cs @@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits rotorAnim.PlayRepeating(info.Sequence); rs.Add(new AnimationWithOffset(rotorAnim, () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), - null, () => false, p => ZOffsetFromCenter(self, p, 1))); + null, p => ZOffsetFromCenter(self, p, 1))); } public void Tick(Actor self) diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs index a3b1513740..6a3d23ad31 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs @@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Traits DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing); DefaultAnimation.PlayRepeating(NormalizeSequence(self, info.Sequence)); rs.Add(new AnimationWithOffset( - DefaultAnimation, () => TurretOffset(self), () => IsTraitDisabled, () => false, p => RenderUtils.ZOffsetFromCenter(self, p, 1))); + DefaultAnimation, () => TurretOffset(self), () => IsTraitDisabled, p => RenderUtils.ZOffsetFromCenter(self, p, 1))); // Restrict turret facings to match the sprite t.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings;