Conversation
|
Play this branch at https://play.threadbare.game/branches/endlessm/timeofday-and-weather. (This launches the game from the start, not directly at the change(s) in this pull request.) |
b5c3322 to
8d04009
Compare
|
Update: I tweaked a bit the animation and made the lightspots transition. Also added a Ligth2D to the player to be give it a vignette effect during night (as seen in Silksong and many other games). recording.webm |
c1ed82d to
40b94c5
Compare
|
I added 3 random weather events: fog (during night or early morning), rain, and cloud shadows (during daytime). To simplify they are mutually exclusive and happen very often in the branch, for testing. recording.webmFor fog and cloud shadows I used the existing ones as reference: Shadow Journey "neblina" and the old clouds overlay. Looking at them, it looks like the tricky part is how to pass the camera offset to the canvas shader. The old clouds overlay does it through a shader parameter, with an offset that needs to be constantly calculated and updated (every process loop, from GDScript to the shader). Shadow Journey does it through repeating the ColorRect with a parallax effect. I went with the parallax effect (updating it to the new Parallax2D node) mainly because the old clouds were removed for performance reasons. Another difference is that the old clouds overlay has a huge noise texture (1920x1080, the old game resolution), while Shadow Journey's has a small one (320x180 px) that is then upscaled. So maybe the performance issue was the huge texture? In any case, I also went with smaller textures: 256x256 for the fog and 170x256 for the cloud shadows. The shadow height is 2/3 its width, to look like it's in perspective. These textures are upscaled to 1024x1024 and then tiled by the Parallax2D node. Both shaders are the same, except the fog uses "add" render mode and the shadows uses "sub", and currently the render mode can't be set conditionally in a canvas shader (there is a bug open for Godot). Note that the cloud shadows goes above everything (as the old one did). Is not realistically considering elevations. I also randomized these noise textures by changing their seed, and waiting for the texture resource to have changed before showing it. There are more things that can be randomized in the textures. But I already spent too much time with these effects for a prototype! For the rain I used a particle system, after looking at other games. The nice thing about using this and not a shader is that the amount of particles can be animated, so it can start as a drizzle and become a storm. But the problem of a particle solution is that I couldn't manage to make it scroll well with the camera. I also wanted to add a splat (like in Stardew Valley, they use the same regardless of the rain drop falling in terrain or water!) and Godot has sub emitters for it. But unfortunately particle sub emitters don't work in the Compatibility renderer mode :( . I spent far less time with rain than with the other two. These effects need to be kept subtle. Because they are only cosmetic. It could be fun to add a small chance to have a very foggy morning, so foggy that nothing can be seen. But it would interfere with gameplay. Thanks @pablitar and the @endlessm/suenos-nocturnos for the initial efforts. |
e8163be to
6a91db2
Compare
|
Last week I discussed this prototype a bit with @wjt. Time passing and weather changing seems viable for the main areas of the world. Currently, just Fray's End. The proposal is to add time passing in these main areas, while keeping the levels inside quests (either lore or StoryQuests) standstill. The rationale is:
Even if levels don't have automatic time-passing or weather changes, they can use the individual components. For example, we can promote the fog node in Sueños Nocturnos storyquest to be in the main game as a reusable node. |
|
My £0.05: I love this and I think it makes the world seem much more alive. Suppose we have a second scene connected to Fray's End by a walkable route. I think that the time-of-day and weather should persist between those. So it's dawn & raining when you walk down a path away from Fray's End, it should still be dawn & raining immediately after the scene transition. I think it matters less whether the time of day and weather persist if you quit the game and immediately reload it. Personally I would love for us to not have any HUD element that tells you the time, but instead have clocks on buildings in the world that show the time; e.g. a clock in the spire of whatever equivalents of a church the Threadbare world's religions have; or a clock nailed to the side of a tree, or a signpost. I don't know whether it would really be possible to have a legible clock at that size though. :( Maybe we don't need to show the time at all. Let's indeed make it possible to apply a specific weather effect to a scene. e.g. maybe I want it always to be raining in the musician rock puzzle. We should document how to:
|
|
Oh, and while I don't think it's necessary for a first iteration, this is crying out for sound effects like a dawn chorus. A great space to leave open to contributors: give each time of day/weather a AudioStreamRandomizer of sound effects, and contributors can add more, e.g. the sound of a typical evening insect in your region. |
6a91db2 to
46cbe63
Compare
|
Thanks for your £0.05 @wjt. So to conclude this exploration:
|
ddd2f1d to
afb21de
Compare
Add a TimeAndWeather node with the default settings. And remove the clouds shadow overlay effect.
afb21de to
1e83c34
Compare
| var unix_time := Time.get_unix_time_from_system() | ||
| var system_seconds := fmod(unix_time, 24 * 60 * 60) | ||
| var system_hour := system_seconds / 60.0 / 60.0 | ||
| var scaled_hour := fmod((system_hour / 24) * 24 * time_scale, 24) |
There was a problem hiding this comment.
You could consider:
var system_hour := Time.get_datetime_dict_from_system()["hour"]There was a problem hiding this comment.
var scaled_hour := fmod((system_hour / 24) * 24 * time_scale, 24)This looks suspicious to me, you're dividing by 24 and immediately multiplying by 24.
There was a problem hiding this comment.
You could consider:
var system_hour := Time.get_datetime_dict_from_system()["hour"]
Oh but gives me the total hour, eg. 15. For the AnimationPlayer etc I need a floating point number between 0 and 24.0, for example 18.9613.
There was a problem hiding this comment.
OK. So the current UTC time as I type this is 09:24:00. You want to get (24 * 60) / (60 * 60), i.e. the fraction of the current real world hour, and then multiply this by 24 to get the in-game time, so that one hour of real-world time is one day of in-game time, with xx:00:00 being midnight (0.0) in game and xx:30:00 being noon (12.0) in game.
In that case I think you want:
const SECONDS_PER_MINUTE := 60.0
const MINUTES_PER_HOUR := 60.0
const SECONDS_PER_HOUR := SECONDS_PER_MINUTE * MINUTES_PER_HOUR
var seconds_of_real_world_hour := fmod(Time.get_unix_time_from_system(), SECONDS_PER_HOUR)
var fraction_of_real_world_hour := seconds_of_real_world_hour / SECONDS_PER_HOUR
var hour_of_in_game_day := 24.0 * fraction_of_real_world_hourThere was a problem hiding this comment.
Sorry that I didn't explain my thinking before asking for advice! I was planning to do it when opening the pull request.
OK. So the current UTC time as I type this is 09:24:00. You want to get (24 * 60) / (60 * 60), i.e. the fraction of the current real world hour, and then multiply this by 24 to get the in-game time, so that one hour of real-world time is one day of in-game time, with xx:00:00 being midnight (
0.0) in game and xx:30:00 being noon (12.0) in game.
In this case I need the 09:24:00 datetime converted to a float so it would be 9 + (24 / 60) = 9.4 . And I'm not going with one hour of real-wrld -> one day in game, but I'm making it configurable. I took this image from my notebook:
Let's suppose it's 15 o'clock. Then if the time scale is 1x, (1 day in game = 1 day in reality) the hour_of_in_game_day is also 15. From the documentation string:
## - 1: 15 (same time in game than in system).
## - 2: 6 (30 hours in game have passed today).
## - 4: 12 (noon in game, exactly 2 and a half days have passed in game today).
## - 8: 0 (midnight in game, exactly 5 days have passed in game today).
For the default time scale, I've been looking at what other games do. In Stardew Valley 14 mins in game is 1 day. Since Threadbare is pretty short (the time you spend today in Fray's End is short), I went for 10 mins in game = 1 day (time scale = 144x). But that can be changed later!
In that case I think you want:
const SECONDS_PER_MINUTE := 60.0 const MINUTES_PER_HOUR := 60.0 const SECONDS_PER_HOUR := SECONDS_PER_MINUTE * MINUTES_PER_HOUR var seconds_of_real_world_hour := fmod(Time.get_unix_time_from_system(), SECONDS_PER_HOUR) var fraction_of_real_world_hour := seconds_of_real_world_hour / SECONDS_PER_HOUR var hour_of_in_game_day := 24.0 * fraction_of_real_world_hour

Here is a quick prototype for how a day/night transition can be added to Threadbare. I added it to Fray's End but this is reusable. This could either be a global that is turned off in special levels (like Stealth) or a node to add to every single scene that needs it. The time of day can also be persisted in the game state.
While doing this I did a quick research and remembered my knowledge in photography, filmmaking, and what other games do.
Days depend a lot on the season and the time of the year, and the geographic position. I think it is fine to simplify and make all days the same. At least for now. Also it is better to simplify and make the change bolder, more evident for aesthetics, than making it realistically accurate. For example: making sunrise/sunset happen for a longer time.
I tried to make sunrise and sunset significantly different. Usually sunrise has cooler tones due to atmosphere conditions, while sunsets are more dramatic and turning gold.
About night: Games (or movies) don't usually have a completely dark night (no moon or stars) because players need to see what's going on! So it's an "american night" as it's called in filmmaking. I used exactly the same darkness as the Stealth game, I only tinted it a bit blue. This is a top-down game so we don't see the sky anyways. Although we see its color reflected in the water. We could certainly add a shader to the water, to make its color vary during the time of day.
Night really needs some artificial lights for better effect. Maybe the player should have a spot light too? I made these lights turn on/off with the same time-of-day cycle.
This is only visual, but shouldn't be! A morning is not a morning without the sign of birds. Ambient sound at night is very different: insects, frogs, the sudden scream of an owl.
Next: Improve it a bit. For example, I don't like how artificial lights pop up all at once. Also I would like to play with some simple weather conditions (rain, fog).
recording.webm
On the technical side, the time-of-day cycle is just an animation that tweaks values from a CanvasModulate and WorldEnvironment nodes. For convenience and easy editing it, it's a 24 seconds animation that is then scaled. The animation also changes a property to turn lights on/off.