Merge branch 'main' into fix-day-nigh-cycle
This commit is contained in:
@@ -2,6 +2,7 @@ extends Path3D
|
||||
|
||||
const STEAM_DISTANCE_STAT: String = "stat_distance_km"
|
||||
const DISTANCE_KM_PER_UNIT: float = 0.01
|
||||
const STATION_STOP_GROUP: StringName = &"railway_station"
|
||||
|
||||
@export_group("Train")
|
||||
##train speed
|
||||
@@ -48,6 +49,10 @@ const DISTANCE_KM_PER_UNIT: float = 0.01
|
||||
@export_group("Train Stops")
|
||||
##if true the train stop the ran on stops
|
||||
@export var enable_stops: bool = true
|
||||
##if true the train only stops on markers with a generated station nearby
|
||||
@export var require_station_for_stop: bool = true
|
||||
##max horizontal distance between a stop marker and a station chunk
|
||||
@export var station_stop_detection_radius: float = 35.0
|
||||
##time of stop
|
||||
@export var stop_time: float = 4.0
|
||||
##distance when the train start to brake
|
||||
@@ -126,15 +131,22 @@ func _apply_initial_train_start() -> void:
|
||||
if total_length <= 0.0:
|
||||
return
|
||||
|
||||
#start from a random position
|
||||
if environment_config != null and environment_config.train_start_from_random_position:
|
||||
train_progress = randf() * total_length
|
||||
_update_next_stop_index_from_progress()
|
||||
elif environment_config != null and not stop_offset.is_empty():
|
||||
#start from a specific stop
|
||||
var stop_index: int = clampi(environment_config.train_start_stop_index, 0, stop_offset.size() - 1)
|
||||
train_progress = stop_offset[stop_index]
|
||||
_set_next_stop_index_from_current(stop_index)
|
||||
if environment_config != null:
|
||||
match environment_config.train_start_from_random_position:
|
||||
EnvironmentConfig.TrainStartMode.RANDOM_POSITION:
|
||||
train_progress = randf() * total_length
|
||||
_update_next_stop_index_from_progress()
|
||||
EnvironmentConfig.TrainStartMode.SPECIFIED_STATION:
|
||||
if stop_offset.is_empty():
|
||||
train_progress = wrapf(train_progress, 0.0, total_length)
|
||||
_update_next_stop_index_from_progress()
|
||||
else:
|
||||
var stop_index: int = clampi(environment_config.train_start_stop_index, 0, stop_offset.size() - 1)
|
||||
train_progress = stop_offset[stop_index]
|
||||
_set_next_stop_index_from_current(stop_index)
|
||||
EnvironmentConfig.TrainStartMode.SPECIFIED_POSITION:
|
||||
train_progress = wrapf(environment_config.train_start_position, 0.0, total_length)
|
||||
_update_next_stop_index_from_progress()
|
||||
else:
|
||||
train_progress = wrapf(train_progress, 0.0, total_length)
|
||||
_update_next_stop_index_from_progress()
|
||||
@@ -145,16 +157,22 @@ func _apply_train_start_delay() -> void:
|
||||
if not _initial_is_inmotion:
|
||||
return
|
||||
|
||||
var should_start_after_delay: bool = true
|
||||
var start_delay_seconds: float = 0.0
|
||||
if environment_config != null:
|
||||
should_start_after_delay = environment_config.train_start_after_delay
|
||||
start_delay_seconds = maxf(environment_config.train_start_delay_seconds, 0.0)
|
||||
if start_delay_seconds <= 0.0:
|
||||
if not should_start_after_delay:
|
||||
is_inmotion = false
|
||||
return
|
||||
|
||||
is_inmotion = false
|
||||
await get_tree().create_timer(start_delay_seconds).timeout
|
||||
if not is_inside_tree():
|
||||
return
|
||||
if not should_start_after_delay:
|
||||
return
|
||||
|
||||
is_inmotion = _initial_is_inmotion
|
||||
|
||||
@@ -271,6 +289,9 @@ func build_rails() -> void:
|
||||
rail_piece.add_child(rail_dx)
|
||||
|
||||
func _plan_stops() -> void:
|
||||
stop_offset.clear()
|
||||
stops_position.clear()
|
||||
|
||||
var current_stops = []
|
||||
for child in get_children():
|
||||
if child is Marker3D:
|
||||
@@ -284,7 +305,57 @@ func _plan_stops() -> void:
|
||||
stop_offset.append(data["offset"])
|
||||
stops_position.append(data["position"])
|
||||
|
||||
func _advance_next_stop_index(go_forward: bool) -> void:
|
||||
if stop_offset.is_empty():
|
||||
next_stop_index = 0
|
||||
return
|
||||
|
||||
if go_forward:
|
||||
next_stop_index += 1
|
||||
if next_stop_index >= stop_offset.size():
|
||||
next_stop_index = 0
|
||||
else:
|
||||
next_stop_index -= 1
|
||||
if next_stop_index < 0:
|
||||
next_stop_index = stop_offset.size() - 1
|
||||
|
||||
func _find_next_valid_stop(go_forward: bool) -> bool:
|
||||
if stop_offset.is_empty():
|
||||
return false
|
||||
|
||||
for i in range(stop_offset.size()):
|
||||
if _is_stop_valid(next_stop_index):
|
||||
return true
|
||||
_advance_next_stop_index(go_forward)
|
||||
|
||||
return false
|
||||
|
||||
func _is_stop_valid(stop_index: int) -> bool:
|
||||
if not require_station_for_stop:
|
||||
return true
|
||||
if stop_index < 0 or stop_index >= stops_position.size():
|
||||
return false
|
||||
|
||||
return _has_station_near_position(stops_position[stop_index])
|
||||
|
||||
func _has_station_near_position(stop_position: Vector3) -> bool:
|
||||
var radius_sq := station_stop_detection_radius * station_stop_detection_radius
|
||||
for station in get_tree().get_nodes_in_group(STATION_STOP_GROUP):
|
||||
var station_node := station as Node3D
|
||||
if station_node == null or not is_instance_valid(station_node):
|
||||
continue
|
||||
|
||||
var delta := station_node.global_position - stop_position
|
||||
var horizontal_dist_sq := delta.x * delta.x + delta.z * delta.z
|
||||
if horizontal_dist_sq <= radius_sq:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if EnvironmentManagerRoot.is_keyboard_input_blocked(get_tree()):
|
||||
return
|
||||
|
||||
if event is InputEventKey and event.pressed and not event.echo:
|
||||
if event.keycode == KEY_T:
|
||||
_goto_next_stop()
|
||||
@@ -313,6 +384,9 @@ func _test_manual_fireworks() -> void:
|
||||
func _goto_next_stop() -> void:
|
||||
if stop_offset.size() == 0 or stop_ongoing or is_restarting:
|
||||
return
|
||||
if not _find_next_valid_stop(train_speed >= 0.0):
|
||||
return
|
||||
|
||||
var target_offset = stop_offset[next_stop_index]
|
||||
train_progress = target_offset
|
||||
_execute_stop(train_speed >= 0)
|
||||
@@ -323,6 +397,7 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
func input_controls_management(delta: float) -> void:
|
||||
if not is_inmotion: return
|
||||
if EnvironmentManagerRoot.is_keyboard_input_blocked(get_tree()): return
|
||||
if Input.is_action_pressed("ui_up"):
|
||||
train_speed += manual_acceleration * delta
|
||||
elif Input.is_action_pressed("ui_down"):
|
||||
@@ -338,15 +413,20 @@ func train_move(delta: float) -> void:
|
||||
|
||||
if not stop_ongoing:
|
||||
var last_progress = train_progress
|
||||
var has_valid_stop := false
|
||||
|
||||
if enable_stops and stop_offset.size() > 0 and not is_restarting:
|
||||
var target_offset = stop_offset[next_stop_index]
|
||||
var dist = target_offset - train_progress
|
||||
dist = wrapf(dist + total_length / 2.0, 0.0, total_length) - total_length / 2.0
|
||||
|
||||
if abs(dist) < brake_distance and sign(dist) == sign(train_speed):
|
||||
var t = abs(dist) / brake_distance
|
||||
stop_multiply = max(smoothstep(0.0, 1.0, t), 0.05)
|
||||
has_valid_stop = _find_next_valid_stop(train_speed >= 0.0)
|
||||
if has_valid_stop:
|
||||
var target_offset = stop_offset[next_stop_index]
|
||||
var dist = target_offset - train_progress
|
||||
dist = wrapf(dist + total_length / 2.0, 0.0, total_length) - total_length / 2.0
|
||||
|
||||
if abs(dist) < brake_distance and sign(dist) == sign(train_speed):
|
||||
var t = abs(dist) / brake_distance
|
||||
stop_multiply = max(smoothstep(0.0, 1.0, t), 0.05)
|
||||
else:
|
||||
stop_multiply = 1.0
|
||||
else:
|
||||
stop_multiply = 1.0
|
||||
|
||||
@@ -354,7 +434,7 @@ func train_move(delta: float) -> void:
|
||||
train_progress += current_speed * delta
|
||||
_track_steam_distance(abs(current_speed) * delta)
|
||||
|
||||
if enable_stops and stop_offset.size() > 0:
|
||||
if enable_stops and stop_offset.size() > 0 and has_valid_stop:
|
||||
var target_offset = stop_offset[next_stop_index]
|
||||
var exceeded_forward = (current_speed > 0 and last_progress < target_offset and train_progress >= target_offset)
|
||||
var exceeded_back = (current_speed < 0 and last_progress > target_offset and train_progress <= target_offset)
|
||||
@@ -441,19 +521,16 @@ func _check_distance_achievements(total_distance_km: int) -> void:
|
||||
AchievementManager.unlock("ACH_DISTANCE_200")
|
||||
|
||||
func _execute_stop(go_forward: bool = true) -> void:
|
||||
if not _find_next_valid_stop(go_forward):
|
||||
stop_multiply = 1.0
|
||||
return
|
||||
|
||||
stop_ongoing = true
|
||||
stop_multiply = 0.0
|
||||
|
||||
var current_stop_index = next_stop_index
|
||||
|
||||
if go_forward:
|
||||
next_stop_index += 1
|
||||
if next_stop_index >= stop_offset.size():
|
||||
next_stop_index = 0
|
||||
else:
|
||||
next_stop_index -= 1
|
||||
if next_stop_index < 0:
|
||||
next_stop_index = stop_offset.size() - 1
|
||||
_advance_next_stop_index(go_forward)
|
||||
|
||||
if fireworks_scene != null:
|
||||
var marker_position = stops_position[current_stop_index]
|
||||
|
||||
@@ -30,6 +30,7 @@ func _ready() -> void:
|
||||
UIEvents.toggle_pause_daytime.connect(_on_toggle_pause_daytime)
|
||||
UIEvents.time_option_item_changed.connect(_time_option_changed)
|
||||
|
||||
paused = environment_config.start_day_time_paused
|
||||
current_time = environment_config.start_time
|
||||
update_time(current_time)
|
||||
|
||||
|
||||
@@ -7,6 +7,14 @@ const DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME: int = 32 #how many update of the en
|
||||
|
||||
@export var environment_config: EnvironmentConfig
|
||||
|
||||
@export_group("Input")
|
||||
@export var block_keyboard_input: bool = false:
|
||||
set(value):
|
||||
if block_keyboard_input == value:
|
||||
return
|
||||
block_keyboard_input = value
|
||||
_apply_keyboard_input_block()
|
||||
|
||||
@export_group("Camera")
|
||||
@export var camera: Camera3D
|
||||
@export var camera_pivot: Node3D
|
||||
@@ -40,8 +48,24 @@ var day_tween: Tween
|
||||
var day_time: float = 0.0
|
||||
var pending_environment_nodes: Dictionary = {}
|
||||
var weather_shader_no_noise: Material
|
||||
var _blocked_keyboard_events_by_action: Dictionary = {}
|
||||
|
||||
static func is_keyboard_input_blocked(tree: SceneTree) -> bool:
|
||||
if tree == null:
|
||||
return false
|
||||
|
||||
for node in tree.get_nodes_in_group("keyboard_input_blocker"):
|
||||
var environment_manager := node as EnvironmentManagerRoot
|
||||
if environment_manager != null and environment_manager.block_keyboard_input:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group("keyboard_input_blocker")
|
||||
|
||||
func _ready() -> void:
|
||||
_apply_keyboard_input_block()
|
||||
|
||||
#connect shader when new node is added
|
||||
get_tree().node_added.connect(_on_tree_node_added)
|
||||
@@ -87,9 +111,51 @@ func _ready() -> void:
|
||||
func _process(_delta: float) -> void:
|
||||
_process_pending_environment_nodes()
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if block_keyboard_input and event is InputEventKey:
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func _exit_tree() -> void:
|
||||
_restore_keyboard_action_events()
|
||||
remove_from_group("keyboard_input_blocker")
|
||||
|
||||
func flush_pending_environment_nodes() -> void:
|
||||
_process_pending_environment_nodes(-1)
|
||||
|
||||
func _apply_keyboard_input_block() -> void:
|
||||
if block_keyboard_input:
|
||||
_remove_keyboard_action_events()
|
||||
else:
|
||||
_restore_keyboard_action_events()
|
||||
|
||||
func _remove_keyboard_action_events() -> void:
|
||||
if not _blocked_keyboard_events_by_action.is_empty():
|
||||
return
|
||||
|
||||
for action in InputMap.get_actions():
|
||||
var keyboard_events: Array[InputEvent] = []
|
||||
for event in InputMap.action_get_events(action):
|
||||
if event is InputEventKey:
|
||||
keyboard_events.append(event)
|
||||
|
||||
if keyboard_events.is_empty():
|
||||
continue
|
||||
|
||||
_blocked_keyboard_events_by_action[action] = keyboard_events
|
||||
Input.action_release(action)
|
||||
for keyboard_event in keyboard_events:
|
||||
InputMap.action_erase_event(action, keyboard_event)
|
||||
|
||||
func _restore_keyboard_action_events() -> void:
|
||||
for action in _blocked_keyboard_events_by_action.keys():
|
||||
if not InputMap.has_action(action):
|
||||
continue
|
||||
|
||||
for keyboard_event in _blocked_keyboard_events_by_action[action]:
|
||||
InputMap.action_add_event(action, keyboard_event)
|
||||
|
||||
_blocked_keyboard_events_by_action.clear()
|
||||
|
||||
func _on_tree_node_added(node: Node) -> void:
|
||||
if node.is_in_group("wind_node") or node.is_in_group("weather_node") or node.is_in_group("weather_vegetables_node"):
|
||||
_queue_dynamic_environment_node(node)
|
||||
|
||||
@@ -13,6 +13,7 @@ global uniform float global_snow_accumulation_speed = 0.005;
|
||||
global uniform float global_snow_melt_time = -1.0;
|
||||
global uniform float global_snow_melt_speed = 0.1;
|
||||
global uniform float global_snow_amount = 0.0;
|
||||
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
|
||||
global uniform float global_rain_intensity;
|
||||
|
||||
// --- PARAMETRI ESTETICI ---
|
||||
@@ -133,7 +134,7 @@ void fragment() {
|
||||
// Applichiamo la variazione al colore finale dell'erba
|
||||
vec3 varied_grass_color = mix(v_final_color, variance_color.rgb, noise_sample * variance_intensity);
|
||||
|
||||
float snow_amount = smoothstep(0.0, 1.0, get_snow_progress());
|
||||
float snow_amount = pow(get_snow_progress(), 0.55);
|
||||
|
||||
float top_mask = 1.0 - shifted_uv.y;
|
||||
float snow_start = 1.0 - clamp(snow_coverage, 0.05, 1.0);
|
||||
@@ -141,8 +142,9 @@ void fragment() {
|
||||
snow_mask *= step(0.01, snow_amount);
|
||||
snow_mask = clamp(snow_mask, 0.0, 1.0);
|
||||
|
||||
vec3 dark_snow = snow_color.rgb * (1.0 - shadow_intensity);
|
||||
vec3 shaded_snow = mix(dark_snow, snow_color.rgb, v_shade_factor);
|
||||
vec3 snow_base_color = max(snow_color.rgb, global_snow_color.rgb);
|
||||
float snow_light = mix(0.82, 1.0, max(v_shade_factor, 0.35));
|
||||
vec3 shaded_snow = clamp(snow_base_color * snow_light, 0.0, 1.0);
|
||||
|
||||
// Mescoliamo il colore variato con la neve
|
||||
vec3 final_albedo = mix(varied_grass_color, shaded_snow, snow_mask);
|
||||
|
||||
@@ -111,8 +111,8 @@ void fragment() {
|
||||
float snow_mask = smoothstep(1.0 - snow_amount * 1.35, 1.08 - snow_amount * 1.35, top_mask) * snow_visibility;
|
||||
snow_mask *= step(0.01, snow_amount);
|
||||
|
||||
vec3 dark_snow = global_snow_color.rgb * (1.0 - shadow_intensity);
|
||||
vec3 shaded_snow = mix(dark_snow, global_snow_color.rgb, v_shade_factor);
|
||||
float snow_light = mix(0.82, 1.0, max(v_shade_factor, 0.35));
|
||||
vec3 shaded_snow = clamp(global_snow_color.rgb * snow_light, 0.0, 1.0);
|
||||
vec3 final_albedo = mix(v_final_color, shaded_snow, snow_mask);
|
||||
|
||||
// Rain wetness: darken and make shinier
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
class_name EnvironmentConfig
|
||||
extends Resource
|
||||
|
||||
enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION }
|
||||
|
||||
@export_group("Day")
|
||||
@export var start_time: float = 0.0 #start time of the day
|
||||
@export var day_duration: float = 300.0 #Duration of a full day cycle in seconds
|
||||
@export var start_day_time_paused: bool = false #Start with day time paused, without advancing the day cycle
|
||||
@export var sunrise: float = 0.25 #day_time 1.0→2.0 (night colors → morning colors)
|
||||
@export var day: float = 0.45 #day_time 2.0→2.0 (stays morning/afternoon)
|
||||
@export var sunset: float = 0.80 #day_time 2.0→3.0 (afternoon colors → night colors)
|
||||
@@ -156,9 +159,11 @@ extends Resource
|
||||
|
||||
#Train start settings
|
||||
@export_group("Train Start")
|
||||
@export var train_start_from_random_position: bool = true #When enabled the train starts from a random offset on the rail curve instead of a stop
|
||||
@export_enum("random_position", "specified_station", "specified_position") var train_start_from_random_position: int = TrainStartMode.RANDOM_POSITION #Train start mode
|
||||
@export_range(0, 64, 1, "or_greater") var train_start_stop_index: int = 1 #Stop index used for the train start when random start is disabled
|
||||
@export var train_start_delay_seconds: float = 3.0 #Seconds the train waits before starting at game launch
|
||||
@export var train_start_position: float = 0.0 #Offset on the rail curve used when train_start_from_random_position is specified_position
|
||||
@export var train_start_delay_seconds: float = 0.0 #Seconds the train waits before starting at game launch
|
||||
@export var train_start_after_delay: bool = true #When enabled the train starts after train_start_delay_seconds, otherwise it stays stopped
|
||||
@export var train_start_acceleration_seconds: float = 4.0 #Seconds used to progressively reach normal train speed after launch
|
||||
|
||||
#Snow settings
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_resource type="Resource" script_class="SceneConfig" format=3 uid="uid://dr612tmciq8pg"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://btcpge7cj2041" path="res://core/main_menu/main_menu.tscn" id="1_72aup"]
|
||||
[ext_resource type="PackedScene" uid="uid://cgkqj51u6p8dn" path="res://tgcc/main menu/main_menu_test.tscn" id="1_ayiwx"]
|
||||
[ext_resource type="Script" uid="uid://bbgyhmb8a17i7" path="res://core/scene_manager/scene_config.gd" id="1_km45g"]
|
||||
[ext_resource type="PackedScene" uid="uid://vjf4bdxd8saj" path="res://tgcc/main_scene.tscn" id="2_prsyo"]
|
||||
[ext_resource type="PackedScene" uid="uid://ri5kxx4mipo" path="res://core/splash_screen/splash_screen.tscn" id="3_aasbo"]
|
||||
@@ -8,7 +8,7 @@
|
||||
[resource]
|
||||
script = ExtResource("1_km45g")
|
||||
scenes = Dictionary[int, PackedScene]({
|
||||
0: ExtResource("1_72aup"),
|
||||
0: ExtResource("1_ayiwx"),
|
||||
1: ExtResource("2_prsyo"),
|
||||
2: ExtResource("3_aasbo")
|
||||
})
|
||||
|
||||
@@ -148,8 +148,8 @@ func change_scene_with_standard_fade(scene_enum: SceneConfig.SceneName, show_loa
|
||||
|
||||
color_rect.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
|
||||
await cover(fade_in_duration)
|
||||
get_tree().change_scene_to_packed(target_scene)
|
||||
await cover(3.0)
|
||||
|
||||
if show_loading_label:
|
||||
_setup_logo_safety()
|
||||
|
||||
@@ -26,4 +26,4 @@ func _ready() -> void:
|
||||
# Aspetta lo schermo nero prima di caricare il menu principale
|
||||
await get_tree().create_timer(black_screen_delay).timeout
|
||||
|
||||
get_tree().change_scene_to_packed(main_menu_scene)
|
||||
SceneManager.change_scene_with_standard_fade(SceneConfig.SceneName.MAIN_MENU, true)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[ext_resource type="Script" uid="uid://ckj2pcoxi5j3" path="res://core/splash_screen/splash_screen.gd" id="1_elsnp"]
|
||||
[ext_resource type="Texture2D" uid="uid://dp3qxncy8u184" path="res://core/splash_screen/jmp_logo.png" id="1_jkpgl"]
|
||||
[ext_resource type="PackedScene" uid="uid://btcpge7cj2041" path="res://core/main_menu/main_menu.tscn" id="2_qmlqp"]
|
||||
[ext_resource type="PackedScene" uid="uid://cgkqj51u6p8dn" path="res://tgcc/main menu/main_menu_test.tscn" id="2_qmlqp"]
|
||||
|
||||
[node name="Control" type="Control" unique_id=163470013]
|
||||
layout_mode = 3
|
||||
@@ -13,7 +13,11 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_elsnp")
|
||||
main_menu_scene = ExtResource("2_qmlqp")
|
||||
initial_delay = null
|
||||
logo_fade_in_time = null
|
||||
logo_display_time = 1.25
|
||||
logo_fade_out_time = null
|
||||
black_screen_delay = null
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="." unique_id=1599828641]
|
||||
layout_mode = 1
|
||||
|
||||
Reference in New Issue
Block a user