Terasology / ClimateConditions

A module for managing temperature, humidity, and other climate factors
0 stars 6 forks source link

feat: Introduce Body Temperature System #17

Closed ktksan closed 4 years ago

ktksan commented 4 years ago

This is a prototype for a system to keep a check on body temperature of the player entity. Currently the temperature is updated every second and displayed in the chat message every 10 seconds along with the environment temperature for that location.

skaldarnar commented 4 years ago

Body Temperature System

Here are some thoughts on the body temperature system and how it can be used.

Fundamental System

The first question we tried to answer is how to model the fundamental system to track and modify the body temperature of the player (or more general, of any entity). We eventually came up with a basic numeric system serving as base for anything related to body temperatures. To mitigate the problem how to related the body temperature scale to other temperatures (e.g., the environment temperature as given by the WeatherManager) we propose some abstraction on top of these numeric values.

public class BodyTemperatureComponent implements Component {
  public float temperature;
}

Similar to systems like Health or Thirst modifications and notifications should be handled via events. The base body temperature authority system should be a periodic system. It will update all temperature components periodically after some fixed time interval, e.g., every second (1000ms). Without any system reacting on this, the temperature value will stay to the initial (default) value.

Events

The base system will work with a set of events, some being for internal processes and others for external communication (API).

To simplify the interpretation of these numeric values we propose to add an abstraction that introduces discrete categories or levels to track body temperature.

Body Temperature Levels

Each game mode would have to provide information on how to interpret a temperature value (scale and unit of measurement). To mitigate this, we thought about a game play simplification that will provide a configurable interpretation as temperature levels. The level is always derived from the numeric value and cannot be changed otherwise. In fact, it's not even persisted with the component but just available as semantic information by sending an event. Systems that need this information may need to persist it themselves.

public enum BodyTemperatureLevel {
  CRITICAL_LOW, LOW, REDUCED, NORMAL, RAISED, HIGH, CRITICAL_HIGH;
}

Whenever the temperature changes in a way that the temperature level change an event is sent out to notify systems about this:

We could aim at implementing the logic to send out the event based thresholds to be defined in the BodyTemperature component. The following properties make the system flexible yet functional:

Integration with Climate Conditions

Climate conditions would have to provide a delta prefab for the player to define the thresholds for the temperature levels. Hypothermia and Hyperthermia will just listen for BodyTemperatureLevelChanged. The strength of the weakening effect could be directly derived from the temperature levels.

We would favor in implementation where the body temperature delta is derived from the environment temperature and environment humidity, without any threshold computations. The formulas need to be constructed in a way that they only slowly converge against the environment temperature to give the player time to react to the change. As was mentioned before, this is probably best play-tested to find the right parameters.

We also came up with a possible mitigation for "dying after leaving the danger zone", e.g., the (numeric) body temperature being so far off the (interpreted) vital range that the temperature cannot adjust fast enough. This could be improved by flattening or steepening the curve depending on whether the temperature delta goes in the "right" direction. However, this assumes that we know the _target temperature_². Mathematically speaking, the temperature delta goes into the right direction if difference to environment and difference to target temperature have the same sign:

Δt_env    = t_env - t
Δt_target = t_target - t

sgn(Δt_env) == sgn(Δt_target)

Limitations

This proposal is not free of limitations, but we think (or rather hope) that they will help to focus more on game play simplifications. Limiting the levels to a fixed set "forces" modules to reduce their complexity to match with the granularity of levels if they want to use that abstraction. However, it is possible to ignore the default abstraction for temperature levels and build around it, as the numeric values are still exposed, and the levels are served on top of the numeric representation.


¹ For periodic systems, the Affect… events should probably hold information about the time delta. Otherwise, we are locked in to use fixed interval as we cannot change it without affecting all game play logic reacting to it. This is a general flaw which does not need to be addressed right now, but we can keep it in mind to be more resilient against changes in the future.

² The target temperature may be tracked as configuration in the BodyTemperature component. If we assume the temperature to be within [0, 1] a good default value for the target temperature might be the mean value 0.5.

ktksan commented 4 years ago

Alright I have the first edition after the new proposal. 🙂 I have tried to incorporate some of the things .. .although not completely but I figured it's better to let you guys take a look at it and check if it is in the direction of what you were thinking.. For the first edition I have only used three of the temperature levels namely high, normal, low and have used arbitrary values which were easier for me to test with and a BodyTemperatureChangedEvent with the BodyTemperatureLevel enum. Changing level to high triggers hyperthermia, to low triggers hypothermia, to normal removes either of the two which the player is affected with. I have tried introducing a delta prefab too. I also tried incorporating affectBodyTemperature but then something weird started happening, for some reason the bodyTemperature stopped changing in regular intervals, it was being displayed but deltaTemp was probably getting a zero value from the affectBodyTemperatureEvent.getResultValue(). I don't understand what was triggering that so I have left that portion in the form of a comment. Please take a look.