Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow WeatherOverlay fade in/out when enabled/disabled #21182

Merged
merged 1 commit into from
Dec 15, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 60 additions & 13 deletions OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits
{
[Desc("Adds a particle-based overlay.")]
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore
public class WeatherOverlayInfo : ConditionalTraitInfo, ILobbyCustomRulesIgnore
{
[Desc("Average number of particles per 100x100 px square.")]
public readonly int ParticleDensityFactor = 8;
Expand Down Expand Up @@ -69,10 +69,19 @@ public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore
[Desc("Works only with line enabled and can be used to fade out the tail of the line like a contrail.")]
public readonly byte LineTailAlphaValue = 200;

[Desc("Time to fade out once the trait becomes disabled.")]
public readonly int FadeOutTicks = 1000;

[Desc("Time to fade in once the trait becomes enabled.")]
public readonly int FadeInTicks = 1000;

[Desc("Percentage of the initial particle when enabled and the game start.")]
public readonly int InitialParticlePercentage = 100;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit speculatively general IMO. Do we have a realistic usecase for needing a value that isn't 100 when it starts enabled and 0 when it starts disabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option is used for when player want to start from mid-stage of the weather, any weather. For example, a map starts from mid-stage of a thundershower: there is only mid rain but get heavier as time goes by, when it at max stage there will be lightning and thunder by using FlashPostProcessEffect (we can make it conditional and scriptable later).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to have this option


public override object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); }
}

public class WeatherOverlay : ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged
public class WeatherOverlay : ConditionalTrait<WeatherOverlayInfo>, ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged
{
readonly struct Particle
{
Expand Down Expand Up @@ -133,23 +142,29 @@ public Particle(in Particle source, float2 pos, int swingDirection, float swingO
}
}

readonly WeatherOverlayInfo info;
readonly World world;
readonly int fadeInTick;
readonly int fadeOutTick;

float windStrength;
int targetWindStrengthIndex;
long windUpdateCountdown;
Particle[] particles;
Size viewportSize;
long lastRender;
bool initialTick = true;
int fadingInTick;
int fadingOutTick;

public WeatherOverlay(World world, WeatherOverlayInfo info)
: base(info)
{
this.info = info;
this.world = world;
targetWindStrengthIndex = info.ChangingWindLevel ? world.LocalRandom.Next(info.WindLevels.Length) : 0;
windUpdateCountdown = world.LocalRandom.Next(info.WindTick[0], info.WindTick[1]);
windStrength = info.WindLevels[targetWindStrengthIndex];
fadeInTick = info.FadeInTicks > 0 ? info.FadeInTicks : 1;
fadeOutTick = info.FadeOutTicks > 0 ? info.FadeOutTicks : 1;
}

void INotifyViewportZoomExtentsChanged.ViewportZoomExtentsChanged(float minZoom, float maxZoom)
Expand All @@ -159,30 +174,60 @@ void INotifyViewportZoomExtentsChanged.ViewportZoomExtentsChanged(float minZoom,
viewportSize = new Size(s.X, s.Y);

// Randomly distribute particles within the initial viewport
var particleCount = viewportSize.Width * viewportSize.Height * info.ParticleDensityFactor / 10000;
var particleCount = viewportSize.Width * viewportSize.Height * Info.ParticleDensityFactor / 10000;
particles = new Particle[particleCount];
var rect = new Rectangle(int2.Zero, viewportSize);
for (var i = 0; i < particles.Length; i++)
particles[i] = new Particle(info, world.LocalRandom, rect);
particles[i] = new Particle(Info, world.LocalRandom, rect);
}

protected override void TraitEnabled(Actor self)
{
if (!initialTick)
fadingInTick = (fadeOutTick - fadingOutTick) * 1000 * fadeInTick / fadeOutTick / 1000;
}

protected override void TraitDisabled(Actor self)
{
if (!initialTick)
fadingOutTick = (fadeInTick - fadingInTick) * 1000 * fadeOutTick / fadeInTick / 1000;
}

void ITick.Tick(Actor self)
{
if (!info.ChangingWindLevel || info.WindLevels.Length == 1)
if (initialTick)
{
initialTick = false;
var initialPercentage = Exts.Clamp(Info.InitialParticlePercentage, 0, 100);
if (IsTraitDisabled)
fadingOutTick = fadeOutTick * (100 - initialPercentage) / 100;
else
fadingInTick = fadeInTick * initialPercentage / 100;
}

if (IsTraitDisabled)
{
if (fadingOutTick < fadeOutTick)
fadingOutTick++;
}
else if (fadingInTick < fadeInTick)
fadingInTick++;

if (!Info.ChangingWindLevel || Info.WindLevels.Length == 1)
return;

if (--windUpdateCountdown <= 0)
{
windUpdateCountdown = self.World.LocalRandom.Next(info.WindTick[0], info.WindTick[1]);
windUpdateCountdown = self.World.LocalRandom.Next(Info.WindTick[0], Info.WindTick[1]);
if (targetWindStrengthIndex > 0 && self.World.LocalRandom.Next(2) == 1)
targetWindStrengthIndex--;
else if (targetWindStrengthIndex < info.WindLevels.Length - 1)
else if (targetWindStrengthIndex < Info.WindLevels.Length - 1)
targetWindStrengthIndex++;
}

// Fading the wind in little steps towards the TargetWindOffset
var targetWindLevel = info.WindLevels[targetWindStrengthIndex];
if (info.InstantWindChanges)
var targetWindLevel = Info.WindLevels[targetWindStrengthIndex];
if (Info.InstantWindChanges)
windStrength = targetWindLevel;
else if (Math.Abs(windStrength - targetWindLevel) > 0.01f)
{
Expand All @@ -205,7 +250,9 @@ void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
var tickFraction = Math.Min((runtime - lastRender) * 1f / world.Timestep, 1);
lastRender = runtime;

for (var i = 0; i < particles.Length; i++)
var spawnNum = particles.Length * (IsTraitDisabled ? (fadeOutTick - fadingOutTick) * 1000 / fadeOutTick : fadingInTick * 1000 / fadeInTick) / 1000;

for (var i = 0; i < spawnNum; i++)
{
// Simulate wind and gravity effects on the particle
var p = particles[i];
Expand Down Expand Up @@ -238,7 +285,7 @@ void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
// Render the particle
// We must provide a z coordinate to stop the GL near and far Z limits from culling the geometry
var a = new float3(p.Pos.X, p.Pos.Y, p.Pos.Y);
if (info.UseSquares)
if (Info.UseSquares)
{
var b = a + new float2(p.Size, p.Size);
wcr.FillRect(a, b, p.Color);
Expand Down