diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 2e0add3797..cfce604caf 100644 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -13,5 +13,6 @@ namespace OpenRa.Game public float2 location; public int palette; public abstract Sprite[] CurrentImages { get; } + public abstract void Tick( double t ); } } diff --git a/OpenRa.Game/Mcv.cs b/OpenRa.Game/Mcv.cs index ec63e68281..dcc1187189 100644 --- a/OpenRa.Game/Mcv.cs +++ b/OpenRa.Game/Mcv.cs @@ -10,6 +10,8 @@ namespace OpenRa.Game class Mcv : Actor { static Range? mcvRange = null; + MoveOrder currentOrder = null; + int facing = 0; public Mcv( float2 location, int palette ) { @@ -20,20 +22,82 @@ namespace OpenRa.Game mcvRange = UnitSheetBuilder.AddUnit("mcv"); } - int GetFacing() { return (Environment.TickCount >> 6) % 32; } + static float2[] fvecs; + + static Mcv() + { + fvecs = new float2[32]; + for (int i = 0; i < 32; i++) + { + float angle = i / 16.0f * (float)Math.PI; + fvecs[i] = new float2(-(float)Math.Sin(angle), -(float)Math.Cos(angle)); + } + } + + int GetFacing(float2 d) + { + if (float2.WithinEpsilon(d, float2.Zero, 0.001f)) + return facing; + + int highest = -1; + float highestDot = -1.0f; + + for (int i = 0; i < 32; i++) + { + float dot = float2.Dot(fvecs[i], d); + if (dot > highestDot) + { + highestDot = dot; + highest = i; + } + } + + return highest; + } public override Sprite[] CurrentImages { get { - return new Sprite[] { UnitSheetBuilder.sprites[GetFacing() + mcvRange.Value.Start] }; + return new Sprite[] { UnitSheetBuilder.sprites[facing + mcvRange.Value.Start] }; } } public void Accept(MoveOrder o) { - // HACK HACK HACK TELEPORT - this.location = o.Destination; + currentOrder = o; + } + + const float Speed = 48.0f; + + public override void Tick( double t ) + { + if (currentOrder == null) + return; + + if (float2.WithinEpsilon(location, currentOrder.Destination, 1.0f)) + return; + + Range r = new Range( + new float2(-Speed * (float)t, -Speed * (float)t), + new float2(Speed * (float)t, Speed * (float)t)); + + float2 d = (currentOrder.Destination - location).Constrain(r); + + int desiredFacing = GetFacing(d); + if (desiredFacing == facing) + location += d; + else + { + int df = desiredFacing - facing; + if (df < 0) + df = 32 - df; + + if (df < 32 - df) + facing = (facing + 1) % 32; + else + facing = (facing + 31) % 32; + } } } } diff --git a/OpenRa.Game/MoveOrder.cs b/OpenRa.Game/MoveOrder.cs index 7b6e679825..1a18e92abb 100644 --- a/OpenRa.Game/MoveOrder.cs +++ b/OpenRa.Game/MoveOrder.cs @@ -10,7 +10,7 @@ namespace OpenRa.Game public MoveOrder(float2 destination) { - this.Destination = destination; + this.Destination = destination - new float2(24,24); //HACK account for MCV size } } } diff --git a/OpenRa.Game/Refinery.cs b/OpenRa.Game/Refinery.cs index 3feca0bfea..c1a0a56062 100644 --- a/OpenRa.Game/Refinery.cs +++ b/OpenRa.Game/Refinery.cs @@ -29,5 +29,7 @@ namespace OpenRa.Game return new Sprite[] { UnitSheetBuilder.sprites[refineryRange.Value.Start + GetFrame()] }; } } + + public override void Tick(double t) { } } } diff --git a/OpenRa.Game/Tree.cs b/OpenRa.Game/Tree.cs index 8230450efe..cfd2ff9c99 100644 --- a/OpenRa.Game/Tree.cs +++ b/OpenRa.Game/Tree.cs @@ -19,5 +19,7 @@ namespace OpenRa.Game { get { return currentImages; } } + + public override void Tick(double t){} } } diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index 4445791673..39929fc153 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -25,14 +25,22 @@ namespace OpenRa.Game public void Add(Actor a) { actors.Add(a); } + double lastTime = Environment.TickCount / 1000.0; + void Draw() { + double t = Environment.TickCount / 1000.0; + double dt = t - lastTime; + lastTime = t; + Range range = new Range(viewport.Location, viewport.Location + viewport.Size); foreach (Actor a in actors) { Sprite[] images = a.CurrentImages; + a.Tick( dt ); + if (images == null) continue; diff --git a/OpenRa.Game/float2.cs b/OpenRa.Game/float2.cs index 5bea593388..99096c3ac7 100644 --- a/OpenRa.Game/float2.cs +++ b/OpenRa.Game/float2.cs @@ -48,5 +48,28 @@ namespace OpenRa.Game { return new float2(a.X / b.X, a.Y / b.Y); } + + public static bool WithinEpsilon(float2 a, float2 b, float e) + { + float2 d = a - b; + return Math.Abs(d.X) < e && Math.Abs(d.Y) < e; + } + + static float Sign(float f) + { + if (f > 0) return 1; + if (f < 0) return -1; + return 0; + } + + public float2 Sign() + { + return new float2(Sign(X), Sign(Y)); + } + + public static float Dot(float2 a, float2 b) + { + return a.X * b.X + a.Y * b.Y; + } } }