Allow all sprites to use interpolated facings.

This commit is contained in:
Paul Chote
2022-12-29 14:31:26 +13:00
committed by Gustas
parent b051211842
commit a6f3db0a45
4 changed files with 16 additions and 22 deletions

View File

@@ -24,7 +24,6 @@ namespace OpenRA.Graphics
string Name { get; } string Name { get; }
int Length { get; } int Length { get; }
int Facings { get; } int Facings { get; }
int InterpolatedFacings { get; }
int Tick { get; } int Tick { get; }
int ZOffset { get; } int ZOffset { get; }
int ShadowZOffset { get; } int ShadowZOffset { get; }

View File

@@ -85,7 +85,6 @@ namespace OpenRA.Mods.Common.Graphics
string ISpriteSequence.Name => throw exception; string ISpriteSequence.Name => throw exception;
int ISpriteSequence.Length => throw exception; int ISpriteSequence.Length => throw exception;
int ISpriteSequence.Facings => throw exception; int ISpriteSequence.Facings => throw exception;
int ISpriteSequence.InterpolatedFacings => throw exception;
int ISpriteSequence.Tick => throw exception; int ISpriteSequence.Tick => throw exception;
int ISpriteSequence.ZOffset => throw exception; int ISpriteSequence.ZOffset => throw exception;
int ISpriteSequence.ShadowZOffset => throw exception; int ISpriteSequence.ShadowZOffset => throw exception;
@@ -144,13 +143,12 @@ namespace OpenRA.Mods.Common.Graphics
[Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")] [Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")]
static readonly SpriteSequenceField<int> Facings = new SpriteSequenceField<int>(nameof(Facings), 1); static readonly SpriteSequenceField<int> Facings = new SpriteSequenceField<int>(nameof(Facings), 1);
int ISpriteSequence.Facings => facings; int ISpriteSequence.Facings => interpolatedFacings ?? facings;
protected int facings; protected int facings;
[Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")] [Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")]
static readonly SpriteSequenceField<int> InterpolatedFacings = new SpriteSequenceField<int>(nameof(InterpolatedFacings), 1); static readonly SpriteSequenceField<int?> InterpolatedFacings = new SpriteSequenceField<int?>(nameof(InterpolatedFacings), null);
int ISpriteSequence.InterpolatedFacings => interpolatedFacings; protected int? interpolatedFacings;
protected int interpolatedFacings;
[Desc("Time (in milliseconds at default game speed) to wait until playing the next frame in the animation.")] [Desc("Time (in milliseconds at default game speed) to wait until playing the next frame in the animation.")]
static readonly SpriteSequenceField<int> Tick = new SpriteSequenceField<int>(nameof(Tick), 40); static readonly SpriteSequenceField<int> Tick = new SpriteSequenceField<int>(nameof(Tick), 40);
@@ -282,10 +280,9 @@ namespace OpenRA.Mods.Common.Graphics
var zRamp = LoadField(ZRamp, data, defaults); var zRamp = LoadField(ZRamp, data, defaults);
facings = LoadField(Facings, data, defaults); facings = LoadField(Facings, data, defaults);
interpolatedFacings = LoadField(InterpolatedFacings.Key, -1, data, defaults); interpolatedFacings = LoadField(InterpolatedFacings, data, defaults);
if (interpolatedFacings != -1 && (interpolatedFacings <= 1 || interpolatedFacings <= Math.Abs(facings) || interpolatedFacings > 1024 if (interpolatedFacings != null && (interpolatedFacings <= 1 || interpolatedFacings <= Math.Abs(facings) || interpolatedFacings > 1024 || !Exts.IsPowerOf2(interpolatedFacings.Value)))
|| !Exts.IsPowerOf2(interpolatedFacings))) throw new YamlException($"Sequence {image}.{sequence}: InterpolatedFacings must be greater than Facings, within the range of 2 to 1024, and a power of 2.");
throw new YamlException($"InterpolatedFacings must be greater than Facings, within the range of 2 to 1024, and a power of 2.");
if (facings < 0) if (facings < 0)
{ {
@@ -508,10 +505,8 @@ namespace OpenRA.Mods.Common.Graphics
public (Sprite, WAngle) GetSpriteWithRotation(int frame, WAngle facing) public (Sprite, WAngle) GetSpriteWithRotation(int frame, WAngle facing)
{ {
var rotation = WAngle.Zero; var rotation = WAngle.Zero;
if (interpolatedFacings != null)
// Note: Error checking is not done here as it is done on load rotation = Util.GetInterpolatedFacingRotation(facing, Math.Abs(facings), interpolatedFacings.Value);
if (interpolatedFacings != -1)
rotation = Util.GetInterpolatedFacing(facing, Math.Abs(facings), interpolatedFacings);
return (GetSprite(start, frame, facing), rotation); return (GetSprite(start, frame, facing), rotation);
} }

View File

@@ -23,14 +23,13 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Defines sequence to derive facings from.")] [Desc("Defines sequence to derive facings from.")]
public readonly string Sequence = "idle"; public readonly string Sequence = "idle";
public int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race) public int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequences, string faction)
{ {
if (string.IsNullOrEmpty(Sequence)) if (string.IsNullOrEmpty(Sequence))
throw new InvalidOperationException("Actor " + ai.Name + " is missing sequence to quantize facings from."); throw new InvalidOperationException($"Actor {ai.Name} is missing sequence to quantize facings from.");
var rsi = ai.TraitInfo<RenderSpritesInfo>(); var rsi = ai.TraitInfo<RenderSpritesInfo>();
var seq = sequenceProvider.GetSequence(rsi.GetImage(ai, race), Sequence); return sequences.GetSequence(rsi.GetImage(ai, faction), Sequence).Facings;
return seq.InterpolatedFacings == -1 ? seq.Facings : seq.InterpolatedFacings;
} }
public override object Create(ActorInitializer init) { return new QuantizeFacingsFromSequence(this); } public override object Create(ActorInitializer init) { return new QuantizeFacingsFromSequence(this); }

View File

@@ -84,16 +84,17 @@ namespace OpenRA.Mods.Common
return new WAngle(a % step - step / 2); return new WAngle(a % step - step / 2);
} }
public static WAngle GetInterpolatedFacing(WAngle facing, int facings, int interpolatedFacings) /// <summary>Returns the angle that the closest facing sprite should be rotated by to achieve the closest interpolated facing.</summary>
public static WAngle GetInterpolatedFacingRotation(WAngle facing, int facings, int interpolatedFacings)
{ {
var step = 1024 / interpolatedFacings; var step = 1024 / interpolatedFacings;
return new WAngle(AngleDiffToStep(facing, facings).Angle / step * step); return new WAngle(AngleDiffToStep(facing, facings).Angle / step * step);
} }
/// <summary>Rounds the given facing value to the nearest quantized step.</summary> /// <summary>Rounds the given facing value to the nearest quantized facing.</summary>
public static WAngle QuantizeFacing(WAngle facing, int steps) public static WAngle QuantizeFacing(WAngle facing, int facings)
{ {
return new WAngle(IndexFacing(facing, steps) * (1024 / steps)); return new WAngle(IndexFacing(facing, facings) * (1024 / facings));
} }
/// <summary>Wraps an arbitrary integer facing value into the range 0 - 255</summary> /// <summary>Wraps an arbitrary integer facing value into the range 0 - 255</summary>