-
Notifications
You must be signed in to change notification settings - Fork 7
Weather and Climate System
The ClimateController
is a class that contains all of the climate information for the GameArea
. It manages so called WeatherEvent
s, which occur periodically, or as a result of completing certain in-game quests.
ClimateController
instances will be properties of GameArea
s rather than the ServiceLocator
, as the climate should only affect entities of the given GameArea
.
The ClimateController
keeps track of a List
of WeatherEvent
s, representing WeatherEvent
s that are either currently happening, or scheduled to happen within a finite amount of time.
Of the WeatherEvent
s that are active at any given moment, only one will occur at a given time (this WeatherEvent
is referenced by the private member variable currentWeatherEvent
). The currentWeatherEvent
will modify the game environment in some way, as determined by the type and severity of the event (see section on the WeatherEvent
class below).
Random WeatherEvent
s by default have a chance to occur once every in-game day. Every in-game day the addDailyEvent()
method is called, determining whether or not an event should be added. The stats and the type of the event are also randomly generated. There is a 93% chance every in-game day that an event will be created. Given that an event is generated, it has a 40% chance of being a RainStormEvent
, a 30% chance of being a BlizzardEvent
, a 20% chance of being a SolarSurgeEvent
, and a 10% chance of being a AcidShowerEvent
. The stats of the event will also be randomly generated, as detailed below:
-
numHoursUntil
will be a random integer in the range[1, 23]
-
duration
will be a random integer in the range[1, 8]
-
priority
will be a random integer in the range[0, 3]
-
severity
will be a random float in the range[0.0f, 1.2f)
A WeatherEvent
can be added by calling the ClimateController
’s addWeatherEvent()
method passing in an instance of WeatherEvent
.
All tracked WeatherEvents
will be updated every hour using their updateTime()
method. Then, for each active WeatherEvent
s, the ClimateController
will determine which has the highest priority, and assign this WeatherEvent
to be the currentWeatherEvent
(in the case where 2 events have the same priority, the event added to the ClimateController
first will be made the currentWeatherEvent
). Note that all tracked WeatherEvent
s will be updated every hour, regardless of which WeatherEvent
s are active or occurring.
When a WeatherEvent
is the currentWeatherEvent
, its startEffect()
method will be triggered. At the end of the hour (i.e., when updateWeatherEvent()
is called again), its stopEffect()
method will be triggered (if the currentWeatherEvent
has not yet expired, and remains the currentWeatherEvent
after all WeatherEvent
s are updated, then startEffect()
will be triggered again).
The ClimateController
has an EventHandler
, which can be accessed through the getEvents()
method. This EventHandler
will be used by certain WeatherEvent
s to trigger miscellaneous in-game effects (see the section on WeatherEvent
s for more information). Hence, other components and entities may provide event listeners to this EventHandler
in order to trigger miscellaneous changes to their state based on certain WeatherEvent
s.
For instance, AcidShowerEvent
s will periodically damage plants in the world. This is achieved by having PlantComponent
add a listener to the "damagePlants"
event on the ClimateController
’s EventHandler
, which will be cause damage to itself.
In addition to affecting the game mechanics, certain WeatherEvent
s may trigger changes in global lighting. A global brightness multiplier can be set from each event's respective startEffect()
and stopEffect()
methods, but the ClimateController
also provides a way for WeatherEvent
s to add periodic dynamic lighting changes (e.g., to simulate lightning strikes or to simulate an aurora during a solar surge).
This is achieved via triggering an event added to the ClimateController
's EventHandler
by default, called "lightingEffect"
. The event listener for this event is the method setLightingEffect()
, which takes in a float duration
and a Function<Float, Color> colourGradient
. The duration
represents the duration of the lighting effect in seconds. The colourGradient
is a function that accepts a float
in the range [0.0f, 1.0f]
, and returns a Color
representing the colour offset at that time.
While a lighting effect is active (i.e., the time elapsed since setLightingEffect()
was called is less than duration
seconds), the ClimateController
will update the global ambient lighting by the specified colourGradient
. The lighting effect is updated every frame the game is not paused, along with the ClimateController
's EventHandler
(using the EventHandler
's update()
method) in the updateClimate()
method.
A WeatherEvent
is an abstract class representing any form of weather event. Implementations of this class include AcidShowerEvent
, BlizzardEvent
, RainStormEvent
, and SolarSurgeEvent
.
WeatherEvent
s have the following properties, which are initialised when a WeatherEvent
is created:
-
numHoursUntil
- The number of hours until theWeatherEvent
becomes active -
duration
- The duration of theWeatherEvent
once it becomes active. Note that aWeatherEvent
’s duration will decrease while it is active, even if it is not occurring -
priority
- An integer representing the importance of theWeatherEvent
. For instance, if there are 3 activeWeatherEvent
s, theWeatherEvent
with the highestpriority
integer value will occur. In the instance where at least 2WeatherEvent
s are active simultaneously, theWeatherEvent
added to theClimateController
first will occur -
severity
- A float representing how 'severe' theWeatherEvent
is (this will be used in the specific implementations for a variety of in-game effects). This float should be in the range[0.0f, 1.5f]
.
WeatherEvent
s also have the following publicly accessible methods which can be invoked by the ClimateController
(not counting getters for each of the above properties):
-
updateTime()
- Will decrement thenumHoursUntil
property if theWeatherEvent
is inactive, or decrement theduration
property -
isActive()
- Returns a boolean value representing whether theWeatherEvent
is active (i.e.,numHoursUntil
is 0, butduration
is greater than 0) -
isExpired()
- Returns a boolean value representing whether theWeatherEvent
has expired (i.e.,numHoursUntil
andduration
are less than or equal to 0) -
startEffect()
(abstract) - This starts aWeatherEvent
's in-game effects, and should include triggering sound effects, lighting changes, and game mechanic effects -
stopEffect()
(abstract) - This stops aWeatherEvent
's in-game effects, and should include stopping sound effects, reverting lighting changes, and stopping game mechanic effects
An AcidShowerEvent
is a WeatherEvent
that periodically causes an acid burn, which damages plants and causes animals to panic
The following in-game effects occur when an AcidShowerEvent
occurs:
- All open flames (from placeable lights) are doused
- The rate at which crop tiles dry decreases. The least severe
AcidShowerEvent
s have no effect on the dry rate, while the most severeAcidShowerEvent
s result in crop tiles being watered at a rate equal to their typical dry rate
Additionally, every 2 to 4 seconds (2 seconds for the most severe AcidShowerEvent
s, 4 seconds for the least severe), an "acidBurn"
will trigger. When an "acidBurn"
triggers, all plants take 1 point of damage, and animals panic (by starting the PanicTask
).
A global lighting multiplier is applied, with a value in the range [0.75f, 0.95f]
(higher severity AcidShowerEvent
s result in a lower multiplier), which darkens the screen.
Using the particle system, a rain effect is added to the screen.
A rolling storm sound effect is started, which loops for the duration of the AcidShowerEvent
. Additionally, each time the "acidBurn"
is triggered, a hissing sound effect plays to signify an acid burn.
An AcidShowerEvent
is a WeatherEvent
that slows the player and decreases the effectiveness of plant AOE effects.
The following in-game effects occur when a BlizzardEvent
occurs:
- All placed lights are ignited, even if it is daytime
- A round of fireflies spawn if it is not currently nighttime. These fireflies will remain until the blizzard event stops (unless the blizzard ends while it is still nighttime)
- The rate at which crop tiles dry increases. The least severe
BlizzardEvent
s have no effect on the dry rate, while the most severeBlizzardEvent
s double the rate at which crop tiles dry - The Aoe effects of plants decrease in effectiveness by 1 point for
BlizzardEvent
s of severity less than or equal to0.75f
, or by 2 points for more severe events. That is, the healing aura ofHammer Plant
s heal 1 or 2 fewer points each time its effect is triggered, the poison aura ofDeadly Nightshade
s deal 1 or 2 points less damage each time its effect is triggered, and the damage caused by plant decay is 1 or 2 points greater each time the effect is triggered - The player movement speed is reduced to between
0.45f
and0.95f
(the most severeBlizzardEvent
s reduce the player's speed the most)
A global lighting multiplier is applied, with a value in the range [0.5f, 0.7f]
(higher severity BlizzardEvent
s result in a lower multiplier), which darkens the screen.
Using the particle system, a snow effect is added to the screen.
A gentle rumble with occasional whistles of wind sound effect is started, which loops for the duration of the BlizzardEvent
.
A RainStormEvent
is a WeatherEvent
that waters plants, and periodically triggers a lighning strike.
The following in-game effects occur when a RainStormEvent
occurs:
- All open flames (from placeable lights) are doused
- Crop tiles will be watered. The least severe
RainStormEvent
s result in crop tiles not drying at all, while the most severeRainStormEvent
s result in crop tiles being watered at a rate equal to 4x their typical dry rate
Additionally, a "lightningStrike"
will trigger in random intervals. The bounds of these intervals are determined by the severity
of the event. The bounds are (higher severities are on the lower ends of these bounds):
- Lower bound:
[2.0f, 5.0f]
- Upper bound:
[6.0f, 14.0f]
When a "lightningStrike"
occurs, animals panic.
A global lighting multiplier is applied, with a value in the range [0.6f, 0.9f]
(higher severity RainStormEvent
s result in a lower multiplier), which darkens the screen.
Using the particle system, a rain effect is added to the screen. Additionally, each time the "lightningStrike"
is triggered, a global colour offset is added to brighten the screen briefly (simulating a lightning strike). The duration for which the screen is brightened is a random number, with a range determined by the severity
of the event. The upper and lower bounds for this random duration are (higher severities are on the upper ends of these bounds):
- Lower bound:
[0.2f, 0.4f]
- Upper bound:
[0.8f, 1.2f]
A rolling storm sound effect is started, which loops for the duration of the RainStormEvent
. Additionally, each time the "lightningStrike"
is triggered, a rumbling thunder sound effect plays.
A SolarSurgeEvent
is a WeatherEvent
that dries out plants, and periodically damages them (if the severity is high enough).
The following in-game effects occur when a SolarSurgeEvent
occurs:
- The rate at which crop tiles dry increases. The least severe
SolarSurgeEvent
s double the drying rate, while the most severeSolarSurgeEvent
s result in crop tiles being dried at 20x their regular rate - The Aoe effects of plants increase in effectiveness by 1 point for
SolarSurgeEvent
s of severity less than or equal to0.75f
, or by 2 points for more severe events. That is, the healing aura ofHammer Plant
s heal 1 or 2 more points each time its effect is triggered, the poison aura ofDeadly Nightshade
s deal 1 or 2 points more damage each time its effect is triggered, and the damage caused by plant decay is 1 or 2 points greater each time the effect is triggered
Additionally, every 2 to 4 seconds (2 seconds for the most severe AcidShowerEvent
s, 4 seconds for the least severe), a "surge"
will trigger. When an "surge"
triggers, if the event has a severity greater than 1.2f, all plants take 1 point of damage, and animals panic.
A global lighting multiplier of 0 is applied, and a lighting effect is triggered. This lighting effect alters the red, green and blue channels of the global colour offset in a sinusoidal pattern (each channel is randomly offset, and changes at different rates).
SolarSurgeEvent
s do not spawn associated particle effects.
A rolling static and phaser sound effect is started, which loops for the duration of the SolarSurgeEvent
. Additionally, each time a "surge"
is triggered, a phaser sound effect plays to indicate to the player that a surge is occurring.
Below is a UML overview of the core classes in the system (ignoring specific implementations).