From 2804d103aee9b679e8c933188ca73892b25e0a30 Mon Sep 17 00:00:00 2001 From: Gustas <37534529+PunkPun@users.noreply.github.com> Date: Sat, 27 Sep 2025 19:02:18 +0300 Subject: [PATCH] Add smooth shellmap movement --- OpenRA.Game/Graphics/Viewport.cs | 5 ++ .../Traits/World/CameraMover.cs | 65 +++++++++++++++++++ mods/d2k/maps/shellmap/d2k-shellmap.lua | 16 ----- mods/d2k/maps/shellmap/rules.yaml | 2 + .../maps/desert-shellmap/desert-shellmap.lua | 11 ---- mods/ra/maps/desert-shellmap/rules.yaml | 1 + 6 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 OpenRA.Mods.Common/Traits/World/CameraMover.cs diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index 6b585a813d..224d0aa40b 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -71,6 +71,8 @@ namespace OpenRA.Graphics float defaultScale; bool overrideUserScale; + public Func ViewportCenterProvider; + public float Zoom { get => zoom; @@ -177,6 +179,9 @@ namespace OpenRA.Graphics { if (lastViewportDistance != graphicSettings.ViewportDistance) UpdateViewportZooms(); + + if (ViewportCenterProvider != null) + Center(ViewportCenterProvider()); } static float CalculateMinimumZoom(float minHeight, float maxHeight) diff --git a/OpenRA.Mods.Common/Traits/World/CameraMover.cs b/OpenRA.Mods.Common/Traits/World/CameraMover.cs new file mode 100644 index 0000000000..dbd7f9f191 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/CameraMover.cs @@ -0,0 +1,65 @@ +#region Copyright & License Information +/* + * Copyright (c) The OpenRA Developers and Contributors + * 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [TraitLocation(SystemActors.World)] + [Desc("Moves the camera in an oval pattern around its starting position.")] + sealed class CameraOvalMoverInfo : TraitInfo + { + [Desc("Starting angle in degrees.")] + public int StartAngle = 45; + + [Desc("How fast the camera moves around the oval.")] + public float DegreesPerSecond = 3f; + + [Desc("The X and Y radius of the oval path. Z is unused.")] + public WVec OvalRadius = new(19200, 20480, 0); + + public override object Create(ActorInitializer init) { return new CameraOvalMover(this); } + } + + sealed class CameraOvalMover : IWorldLoaded + { + readonly CameraOvalMoverInfo info; + public CameraOvalMover(CameraOvalMoverInfo info) + { + this.info = info; + } + + public void WorldLoaded(World world, WorldRenderer wr) + { + var vo = wr.Viewport.CenterPosition; + var viewportOrigin = new float2(vo.X, vo.Y); + + float angle = info.StartAngle; + long lastTime = 0; + wr.Viewport.ViewportCenterProvider = () => + { + var currentTime = Game.RunTime; + var dt = currentTime - lastTime; + lastTime = currentTime; + + // Prevent large jumps when the game is paused or the framerate is very low. + const float MaxStep = 0.25f; + angle += Math.Min(dt / 1000.0f * info.DegreesPerSecond, MaxStep); + + var rad = angle * (Math.PI / 180); + var offset = new float2((float)(info.OvalRadius.X * Math.Sin(rad)), (float)(info.OvalRadius.Y * Math.Cos(rad))); + return viewportOrigin + offset; + }; + } + } +} diff --git a/mods/d2k/maps/shellmap/d2k-shellmap.lua b/mods/d2k/maps/shellmap/d2k-shellmap.lua index cd3e9f27d5..545181aacf 100644 --- a/mods/d2k/maps/shellmap/d2k-shellmap.lua +++ b/mods/d2k/maps/shellmap/d2k-shellmap.lua @@ -139,18 +139,6 @@ InitializeHarvester = function(harvester) harvester.FindResources() end -Ticks = 0 -Speed = 5 - -Tick = function() - Ticks = Ticks + 1 - - if Ticks > 1 or not Map.IsPausedShellmap then - local t = (Ticks + 45) % (360 * Speed) * (math.pi / 180) / Speed; - Camera.Position = ViewportOrigin + WVec.New(19200 * math.sin(t), 28800 * math.cos(t), 0) - end -end - WorldLoaded = function() Atreides = Player.GetPlayer("Atreides") Harkonnen = Player.GetPlayer("Harkonnen") @@ -162,8 +150,6 @@ WorldLoaded = function() Reinforcements.Reinforce(Atreides, { "carryall" }, { atr_carry_2.Location }) Reinforcements.Reinforce(Atreides, { "carryall" }, { atr_carry_3.Location }) - ViewportOrigin = Camera.Position - Utils.Do(Utils.Take(4, Upgrades), function(upgrade) atr_cyard.Produce(upgrade) har_cyard.Produce(upgrade) @@ -201,6 +187,4 @@ WorldLoaded = function() Produce(Corrino, CorrinoTankTypes) Produce(Corrino, CorrinoStarportTypes) end) - - Tick() end diff --git a/mods/d2k/maps/shellmap/rules.yaml b/mods/d2k/maps/shellmap/rules.yaml index dc684cda38..26f94d89c2 100644 --- a/mods/d2k/maps/shellmap/rules.yaml +++ b/mods/d2k/maps/shellmap/rules.yaml @@ -19,6 +19,8 @@ World: DisableWorldSounds: true LuaScript: Scripts: utils.lua, d2k-shellmap.lua + CameraOvalMover: + OvalRadius: 19200, 28800, 0 ^Palettes: -MenuPostProcessEffect: diff --git a/mods/ra/maps/desert-shellmap/desert-shellmap.lua b/mods/ra/maps/desert-shellmap/desert-shellmap.lua index 2094a92864..b253c62975 100644 --- a/mods/ra/maps/desert-shellmap/desert-shellmap.lua +++ b/mods/ra/maps/desert-shellmap/desert-shellmap.lua @@ -170,20 +170,9 @@ ChronoshiftAlliedUnits = function() Trigger.AfterDelay(DateTime.Seconds(60), ChronoshiftAlliedUnits) end -Ticks = 0 -Speed = 5 - -Tick = function() - Ticks = Ticks + 1 - - local t = (Ticks + 45) % (360 * Speed) * (math.pi / 180) / Speed; - Camera.Position = ViewportOrigin + WVec.New(19200 * math.sin(t), 20480 * math.cos(t), 0) -end - WorldLoaded = function() Allies = Player.GetPlayer("Allies") Soviets = Player.GetPlayer("Soviets") - ViewportOrigin = Camera.Position SetupAlliedUnits() SetupFactories() diff --git a/mods/ra/maps/desert-shellmap/rules.yaml b/mods/ra/maps/desert-shellmap/rules.yaml index 56ed715406..0af6b77e14 100644 --- a/mods/ra/maps/desert-shellmap/rules.yaml +++ b/mods/ra/maps/desert-shellmap/rules.yaml @@ -20,6 +20,7 @@ World: LuaScript: Scripts: desert-shellmap.lua -StartGameNotification: + CameraOvalMover: ^Palettes: -MenuPostProcessEffect: