From 1fc2158f2ea31d59dfb26f0d4879f59a4f7b55c2 Mon Sep 17 00:00:00 2001 From: TheRaffy Date: Tue, 7 Jul 2015 21:10:33 +0200 Subject: [PATCH] Added a WeatherOverlay --- OpenRA.Game/Graphics/WorldRenderer.cs | 1 - OpenRA.Game/Traits/TraitsInterfaces.cs | 1 + OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + .../Traits/World/WeatherOverlay.cs | 310 ++++++++ mods/ra/maps/fort-lonestar/map.yaml | 15 + mods/ra/maps/snow town.oramap | Bin 11875 -> 0 bytes mods/ra/maps/snow town/map.bin | Bin 0 -> 81937 bytes mods/ra/maps/snow town/map.yaml | 695 ++++++++++++++++++ 8 files changed, 1022 insertions(+), 1 deletion(-) create mode 100644 OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs delete mode 100644 mods/ra/maps/snow town.oramap create mode 100644 mods/ra/maps/snow town/map.bin create mode 100644 mods/ra/maps/snow town/map.yaml diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 80eaad3a3f..e274de0557 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -145,7 +145,6 @@ namespace OpenRA.Graphics for (var i = 0; i < renderables.Count; i++) renderables[i].Render(this); - // added for contrails foreach (var a in World.ActorsWithTrait()) if (a.Actor.IsInWorld && !a.Actor.Disposed) a.Trait.RenderAfterWorld(this, a.Actor); diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 01677cfd03..2ee5cfb76c 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -304,6 +304,7 @@ namespace OpenRA.Traits } public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } + public interface IRenderShroud { void RenderShroud(WorldRenderer wr, Shroud shroud); } public interface IPostRenderSelection { IEnumerable RenderAfterWorld(WorldRenderer wr); } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 4fbdae0ae0..7ff12e31dc 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -522,6 +522,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs new file mode 100644 index 0000000000..4b43e24a4d --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs @@ -0,0 +1,310 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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 COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Adds a particle-based overlay.")] + public class WeatherOverlayInfo : ITraitInfo + { + [Desc("Factor for particle density. As higher as more particles will get spawned.")] + public readonly float ParticleDensityFactor = 0.0007625f; + + [Desc("Should the level of the wind change over time, or just stick to the first value of WindLevels?")] + public readonly bool ChangingWindLevel = true; + + [Desc("The levels of wind intensity (particles x-axis movement in px/tick).")] + public readonly int[] WindLevels = { -5, -3, -2, 0, 2, 3, 5 }; + + [Desc("Works only if ChangingWindLevel is enabled. Min. and max. ticks needed to change the WindLevel.")] + public readonly int[] WindTick = { 150, 750 }; + + [Desc("Hard or soft fading between the WindLevels.")] + public readonly bool InstantWindChanges = false; + + [Desc("Particles are drawn in squares when enabled, else with lines.")] + public readonly bool UseSquares = true; + + [Desc("Works only with squares enabled. Size min. and max. value in pixels.")] + public readonly int[] PaticleSize = { 1, 3 }; + + [Desc("Scatters falling direction on the x-axis. Scatter min. and max. value in px/tick.")] + public readonly int[] ScatterDirection = { -1, 1 }; + + [Desc("Min. and max. speed at which particles fall in px/tick.")] + public readonly float[] Gravity = { 1.00f, 2.00f }; + + [Desc("The current offset value for the swing movement. SwingOffset min. and max. value in px/tick.")] + public readonly float[] SwingOffset = { 1.0f, 1.5f }; + + [Desc("The value that particles swing to the side each update. SwingSpeed min. and max. value in px/tick.")] + public readonly float[] SwingSpeed = { 0.001f, 0.025f }; + + [Desc("The value range that can be swung to the left or right. SwingAmplitude min. and max. value in px/tick.")] + public readonly float[] SwingAmplitude = { 1.0f, 1.5f }; + + [Desc("The randomly selected ArgbColors for the particles. Use this order: a,r,g,b, a,r,g,b, a,...")] + public readonly Color[] ParticleColors = { + Color.FromArgb(255, 236, 236, 236), + Color.FromArgb(255, 228, 228, 228), + Color.FromArgb(255, 208, 208, 208), + Color.FromArgb(255, 188, 188, 188) + }; + + [Desc("Works only with line enabled and can get used to fade out the tail of the line like a contrail.")] + public readonly byte LineTailAlphaValue = 200; + + public object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); } + } + + public class WeatherOverlay : ITick, IPostRender + { + readonly WeatherOverlayInfo info; + readonly World world; + struct Particle + { + public float PosX; + public float PosY; + public int Size; + public float DirectionScatterX; + public float Gravity; + public float SwingOffset; + public float SwingSpeed; + public int SwingDirection; + public float SwingAmplitude; + public Color Color; + public Color TailColor; + } + + readonly List particleList = new List(); + readonly int maxParticleCount; + + enum ParticleCountFaderType { Hold, FadeIn, FadeOut } + ParticleCountFaderType particleCountFader = ParticleCountFaderType.FadeIn; + + float targetWindXOffset = 0f; + float currentWindXOffset = 0f; + int currentWindIndex = 0; + long windTickCountdown = 1500; + float2 antiScrollPrevTopLeft; + + public WeatherOverlay(World world, WeatherOverlayInfo info) + { + this.info = info; + this.world = world; + currentWindIndex = info.WindLevels.Length / 2; + targetWindXOffset = info.WindLevels[0]; + maxParticleCount = CalculateParticleCount(Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height); + } + + int CalculateParticleCount(int x, int y) + { + return (int)(x * y * info.ParticleDensityFactor); + } + + void SpawnParticles(int count, int rangeY, int spawnChancePercent) + { + for (var i = 0; i < count; i++) + { + if (Game.CosmeticRandom.Next(100) < spawnChancePercent) + { + var tempColor = info.ParticleColors.Random(Game.CosmeticRandom); + var tempColorTail = Color.FromArgb(info.LineTailAlphaValue, tempColor.R, tempColor.G, tempColor.B); + var tempSwingDirection = Game.CosmeticRandom.Next(2) == 0 ? 1 : -1; + + particleList.Add( + new Particle + { + PosX = Game.CosmeticRandom.Next(Game.Renderer.Resolution.Width), + PosY = Game.CosmeticRandom.Next(rangeY), + Size = Game.CosmeticRandom.Next(info.PaticleSize[0], info.PaticleSize[1] + 1), + DirectionScatterX = info.ScatterDirection[0] + Game.CosmeticRandom.Next(info.ScatterDirection[1] - info.ScatterDirection[0]), + Gravity = float2.Lerp(info.Gravity[0], info.Gravity[1], Game.CosmeticRandom.NextFloat()), + SwingOffset = float2.Lerp(info.SwingOffset[0], info.SwingOffset[1], Game.CosmeticRandom.NextFloat()), + SwingSpeed = float2.Lerp(info.SwingSpeed[0], info.SwingSpeed[1], Game.CosmeticRandom.NextFloat()), + SwingDirection = tempSwingDirection, + SwingAmplitude = float2.Lerp(info.SwingAmplitude[0], info.SwingAmplitude[1], Game.CosmeticRandom.NextFloat()), + Color = tempColor, + TailColor = tempColorTail + }); + } + } + } + + void ParticlesCountLogic(WorldRenderer wr) + { + // Logic to switch between the states of the particleCountFader + if (particleCountFader == ParticleCountFaderType.Hold && particleList.Count < maxParticleCount) + particleCountFader = ParticleCountFaderType.FadeIn; + else if (particleCountFader == ParticleCountFaderType.FadeIn && particleList.Count >= maxParticleCount) + particleCountFader = ParticleCountFaderType.Hold; + else if (particleCountFader == ParticleCountFaderType.FadeOut && particleList.Count == 0) + particleCountFader = ParticleCountFaderType.Hold; + + // Do the fade functions + if (particleCountFader == ParticleCountFaderType.FadeIn) + FadeInParticleCount(wr); + else if (particleCountFader == ParticleCountFaderType.FadeOut) + FadeOutParticleCount(wr); + } + + void FadeInParticleCount(WorldRenderer wr) + { + SpawnParticles(1, 0, 100); + + // Remove Particles, which are getting replaced from the top to the bottom by the "EdgeCheckReplace", + // when scrolling down, as long as the FadeIn is not completed, + // to avoid having particles at the top and bottom, but not in the middle of the screen. + for (var i = 0; i < particleList.Count; i++) + if (particleList[i].PosY < 0) + particleList.RemoveAt(i); + + // Add Particles when the weather is fading in and scrolling up, to fill areas above + if (antiScrollPrevTopLeft.Y > wr.Viewport.TopLeft.Y) + { + // Get delta Y and limit to the max value + var tempRangeY = antiScrollPrevTopLeft.Y - wr.Viewport.TopLeft.Y; + var tempParticleCount = CalculateParticleCount(Game.Renderer.Resolution.Width, (int)tempRangeY); + if (particleList.Count + tempParticleCount > maxParticleCount) + tempParticleCount = maxParticleCount - particleList.Count; + + SpawnParticles(tempParticleCount, (int)tempRangeY, 50); + } + } + + void FadeOutParticleCount(WorldRenderer wr) + { + for (var i = 0; i < particleList.Count; i++) + if (particleList[i].PosY > (Game.Renderer.Resolution.Height - particleList[i].Gravity)) + particleList.RemoveAt(i); + } + + void XAxisSwing(ref Particle tempParticle) + { + // Direction turn + if (tempParticle.SwingOffset < -tempParticle.SwingAmplitude || tempParticle.SwingOffset > tempParticle.SwingAmplitude) + tempParticle.SwingDirection *= -1; + + // Perform the X-Axis-Swing + tempParticle.SwingOffset += tempParticle.SwingDirection * tempParticle.SwingSpeed; + } + + public void Tick(Actor self) + { + windTickCountdown--; + } + + void WindLogic(ref Particle tempParticle) + { + if (!info.ChangingWindLevel) + targetWindXOffset = info.WindLevels[0]; + else if (windTickCountdown <= 0) + { + windTickCountdown = Game.CosmeticRandom.Next(info.WindTick[0], info.WindTick[1]); + if (Game.CosmeticRandom.Next(2) == 1 && currentWindIndex > 0) + { + currentWindIndex--; + targetWindXOffset = info.WindLevels[currentWindIndex]; + } + else if (currentWindIndex < info.WindLevels.Length - 1) + { + currentWindIndex++; + targetWindXOffset = info.WindLevels[currentWindIndex]; + } + } + + // Fading the wind in little steps towards the TargetWindOffset + if (info.InstantWindChanges) + currentWindXOffset = targetWindXOffset; + else if (currentWindXOffset != targetWindXOffset) + { + if (currentWindXOffset > targetWindXOffset) + currentWindXOffset -= 0.00001f; + else if (currentWindXOffset < targetWindXOffset) + currentWindXOffset += 0.00001f; + } + } + + void Movement(ref Particle tempParticle) + { + tempParticle.PosX += tempParticle.DirectionScatterX + tempParticle.SwingOffset + currentWindXOffset; + tempParticle.PosY += tempParticle.Gravity; + } + + // AntiScroll keeps the particles in place when scrolling the viewport + void AntiScroll(ref Particle tempParticle, WorldRenderer wr) + { + tempParticle.PosX += antiScrollPrevTopLeft.X - wr.Viewport.TopLeft.X; + tempParticle.PosY += antiScrollPrevTopLeft.Y - wr.Viewport.TopLeft.Y; + } + + void EdgeCheckReplace(ref Particle tempParticle, WorldRenderer wr) + { + tempParticle.PosX %= Game.Renderer.Resolution.Width; + if (tempParticle.PosX < 0) + tempParticle.PosX += Game.Renderer.Resolution.Width; + + tempParticle.PosY %= Game.Renderer.Resolution.Height; + if (tempParticle.PosY < 0 && particleCountFader != ParticleCountFaderType.FadeIn) + tempParticle.PosY += Game.Renderer.Resolution.Height; + } + + void UpdateWeatherOverlay(WorldRenderer wr) + { + ParticlesCountLogic(wr); + + for (var i = 0; i < particleList.Count; i++) + { + Particle tempParticle = particleList[i]; + + XAxisSwing(ref tempParticle); + WindLogic(ref tempParticle); + Movement(ref tempParticle); + AntiScroll(ref tempParticle, wr); + EdgeCheckReplace(ref tempParticle, wr); + + particleList[i] = tempParticle; + } + + antiScrollPrevTopLeft = wr.Viewport.TopLeft; + } + + void DrawWeatherOverlay(WorldRenderer wr) + { + var topLeft = wr.Viewport.TopLeft; + foreach (var item in particleList) + { + var tempPos = new float2(item.PosX + topLeft.X, item.PosY + topLeft.Y); + + if (info.UseSquares) + Game.Renderer.WorldQuadRenderer.FillRect(new RectangleF(tempPos.X, tempPos.Y, item.Size, item.Size), item.Color); + else + { + var tempPosTail = new float2(topLeft.X + item.PosX - currentWindXOffset, item.PosY - (item.Gravity * 2 / 3) + topLeft.Y); + Game.Renderer.WorldLineRenderer.DrawLine(tempPos, tempPosTail, item.Color, item.TailColor); + } + } + } + + public void RenderAfterWorld(WorldRenderer wr, Actor self) + { + if (!world.Paused) + UpdateWeatherOverlay(wr); + + DrawWeatherOverlay(wr); + } + } +} diff --git a/mods/ra/maps/fort-lonestar/map.yaml b/mods/ra/maps/fort-lonestar/map.yaml index 5a122b4ceb..c32d4787c9 100644 --- a/mods/ra/maps/fort-lonestar/map.yaml +++ b/mods/ra/maps/fort-lonestar/map.yaml @@ -501,6 +501,21 @@ Rules: CrateActors: fortcrate -SpawnMPUnits: -MPStartLocations: + WeatherOverlay: + ParticleDensityFactor: 0.0007625 + ChangingWindLevel: true + WindLevels: -5, -3, -2, 0, 2, 3, 5 + WindTick: 150, 550 + InstantWindChanges: false + UseSquares: false + PaticleSize: 0, 0 + ScatterDirection: 0, 0 + Gravity: 8.00, 12.00 + SwingOffset: 0, 0 + SwingSpeed: 0, 0 + SwingAmplitude: 0, 0 + ParticleColors: 255,48,64,116, 255,40,56,108, 255,32,44,96, 255,24,44,84 + LineTailAlphaValue: 150 GlobalLightingPaletteEffect: Red: 0.75 Green: 0.85 diff --git a/mods/ra/maps/snow town.oramap b/mods/ra/maps/snow town.oramap deleted file mode 100644 index b99cb56e825d6620e16c56a80dd49a8588e3c90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11875 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 I%YRn?4Nf!TS^xk5 diff --git a/mods/ra/maps/snow town/map.bin b/mods/ra/maps/snow town/map.bin new file mode 100644 index 0000000000000000000000000000000000000000..7decc8ecd8bd90060455cc8b0f19878e43457ec6 GIT binary patch literal 81937 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