diff --git a/core/biome_generator/rails.gd b/core/biome_generator/rails.gd index b6ee959..b11c634 100644 --- a/core/biome_generator/rails.gd +++ b/core/biome_generator/rails.gd @@ -10,6 +10,7 @@ const TRACK_ZERO_SPACING_TARGET_RATIO: float = 0.97 const TRACK_ZERO_SPACING_MIN_DISTANCE: float = 1.0 enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION } +enum TrainFacingDirection { KEEP_PATH_DIRECTION, LOCOMOTIVE_LEFT, LOCOMOTIVE_RIGHT } @export_group("Train") ##train speed @@ -46,6 +47,7 @@ enum TrainStartMode { RANDOM_POSITION, SPECIFIED_STATION, SPECIFIED_POSITION } @export var train_start_delay_seconds: float = 0.0 @export var train_start_after_delay: bool = true @export var train_start_acceleration_seconds: float = 4.0 +@export_enum("keep_path_direction", "locomotive_left", "locomotive_right") var train_facing_direction: int = TrainFacingDirection.KEEP_PATH_DIRECTION @export_group("Rails Bulding") ##distance between sleepers of the rails @@ -103,6 +105,7 @@ var wagon_instances: Array[Node3D] = [] var wagon_progress_offsets: Array[float] = [] var _initial_is_inmotion: bool = true var _is_photo_mode_active: bool = false +var _train_direction_sign: float = 1.0 func _ready() -> void: randomize() @@ -144,8 +147,32 @@ func _apply_initial_train_start() -> void: train_progress = wrapf(train_start_position, 0.0, total_length) _update_next_stop_index_from_progress() + _apply_train_facing_direction(total_length) + _update_next_stop_index_from_progress() _snap_train_to_progress() +func _apply_train_facing_direction(total_length: float) -> void: + _train_direction_sign = 1.0 + if train_facing_direction == TrainFacingDirection.KEEP_PATH_DIRECTION or curve == null: + return + if total_length <= 0.0: + return + + var center_progress: float = wrapf(train_progress, 0.0, total_length) + var center_position: Vector3 = to_global(curve.sample_baked(center_progress, true)) + var forward_progress: float = wrapf(center_progress + 2.0, 0.0, total_length) + var forward_position: Vector3 = to_global(curve.sample_baked(forward_progress, true)) + var forward_direction: Vector3 = forward_position - center_position + if forward_direction.length_squared() <= 0.0001 or is_zero_approx(forward_direction.x): + return + + var desired_x_sign: float = -1.0 if train_facing_direction == TrainFacingDirection.LOCOMOTIVE_LEFT else 1.0 + if forward_direction.x * desired_x_sign < 0.0: + _train_direction_sign = -1.0 + + if not is_zero_approx(train_speed): + train_speed = absf(train_speed) * _train_direction_sign + func _apply_train_start_delay() -> void: if not _initial_is_inmotion: return @@ -207,13 +234,9 @@ func _snap_train_to_progress() -> void: train_progress = wrapf(train_progress, 0.0, total_length) var center_position: Vector3 = to_global(curve.sample_baked(train_progress, true)) - var prog_forward: float = wrapf(train_progress + 2.0, 0.0, total_length) - var forward_position: Vector3 = to_global(curve.sample_baked(prog_forward, true)) train_instance.global_position = center_position - if center_position.distance_to(forward_position) > 0.01: - train_instance.look_at(forward_position, Vector3.UP) - train_instance.rotate_y(PI) + _orient_vehicle_to_track(train_instance, train_progress, total_length) if cameras: cameras.global_position = center_position @@ -452,8 +475,7 @@ func train_move(delta: float) -> void: if center_position.distance_to(forward_position) > 0.01: train_instance.global_position = center_position - train_instance.look_at(forward_position, Vector3.UP) - train_instance.rotate_y(PI) + _orient_vehicle_to_track(train_instance, train_progress, total_length) if cameras: cameras.global_position = center_position @@ -658,7 +680,7 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void: if i < wagon_progress_offsets.size(): wagon_offset = wagon_progress_offsets[i] - var wagon_progress: float = train_progress - wagon_offset + var wagon_progress: float = train_progress - wagon_offset * _train_direction_sign var segment_spacing: float = maxf(wagon_offset - previous_wagon_offset, 0.1) var vehicle_progress: float = wrapf(wagon_progress, 0.0, total_length) @@ -670,18 +692,27 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void: vehicle_progress = _lerp_progress_on_track(vehicle_progress, corrected_progress, zero_spacing_fix_weight, total_length) center_position = to_global(curve.sample_baked(vehicle_progress, true)) - var prog_forward: float = wrapf(vehicle_progress + 2.0, 0.0, total_length) - var forward_position: Vector3 = to_global(curve.sample_baked(prog_forward, true)) - wagon.global_position = center_position - if center_position.distance_to(forward_position) > 0.01: - wagon.look_at(forward_position, Vector3.UP) - wagon.rotate_y(PI) + _orient_vehicle_to_track(wagon, vehicle_progress, total_length) previous_progress = vehicle_progress previous_position = center_position previous_wagon_offset = wagon_offset +func _orient_vehicle_to_track(vehicle: Node3D, progress: float, total_length: float) -> void: + if vehicle == null or curve == null or total_length <= 0.0: + return + + var center_progress: float = wrapf(progress, 0.0, total_length) + var center_position: Vector3 = to_global(curve.sample_baked(center_progress, true)) + var forward_progress: float = wrapf(center_progress + 2.0 * _train_direction_sign, 0.0, total_length) + var forward_position: Vector3 = to_global(curve.sample_baked(forward_progress, true)) + if center_position.distance_to(forward_position) <= 0.01: + return + + vehicle.look_at(forward_position, Vector3.UP) + vehicle.rotate_y(PI) + func _get_zero_spacing_fix_weight(previous_progress: float, vehicle_progress: float, total_length: float) -> float: var distance_to_zero: float = minf( _get_progress_distance_to_zero(previous_progress, total_length), @@ -699,13 +730,13 @@ func _get_zero_spacing_target_distance(segment_spacing: float) -> float: func _find_zero_spacing_progress(previous_progress: float, previous_position: Vector3, segment_spacing: float, minimum_distance: float, total_length: float) -> float: var start_distance: float = minf(minimum_distance, segment_spacing) - var best_progress: float = wrapf(previous_progress - start_distance, 0.0, total_length) + var best_progress: float = wrapf(previous_progress - start_distance * _train_direction_sign, 0.0, total_length) var search_limit: float = minf(maxf(segment_spacing, minimum_distance) + TRACK_ZERO_SPACING_SEARCH_EXTRA, total_length) var search_distance: float = start_distance var previous_search_distance: float = start_distance while search_distance <= search_limit: - var candidate_progress: float = wrapf(previous_progress - search_distance, 0.0, total_length) + var candidate_progress: float = wrapf(previous_progress - search_distance * _train_direction_sign, 0.0, total_length) var candidate_position: Vector3 = to_global(curve.sample_baked(candidate_progress, true)) best_progress = candidate_progress if previous_position.distance_to(candidate_position) >= minimum_distance: diff --git a/core/daynight/grass_leaves.gdshader b/core/daynight/grass_leaves.gdshader index 4733d32..7d933b2 100644 --- a/core/daynight/grass_leaves.gdshader +++ b/core/daynight/grass_leaves.gdshader @@ -15,6 +15,8 @@ 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; +const float GRASS_FULL_SNOW_START = 0.58; +const float GRASS_FULL_SNOW_END = 0.86; // --- PARAMETRI ESTETICI --- uniform bool billboard_enabled = true; @@ -141,7 +143,7 @@ void fragment() { float snow_mask = smoothstep(snow_start, 1.0, top_mask) * snow_amount * snow_visibility; snow_mask *= step(0.01, snow_amount); snow_mask = clamp(snow_mask, 0.0, 1.0); - float full_snow_mask = smoothstep(0.72, 1.0, snow_amount) * step(0.01, snow_visibility); + float full_snow_mask = smoothstep(GRASS_FULL_SNOW_START, GRASS_FULL_SNOW_END, snow_amount) * step(0.01, snow_visibility); float final_snow_mask = max(snow_mask, full_snow_mask); vec3 snow_base_color = max(snow_color.rgb, global_snow_color.rgb); diff --git a/core/daynight/tree_leaves.gdshader b/core/daynight/tree_leaves.gdshader index 6fc87b0..74a1078 100644 --- a/core/daynight/tree_leaves.gdshader +++ b/core/daynight/tree_leaves.gdshader @@ -13,6 +13,8 @@ global uniform float global_snow_melt_speed = 0.1; global uniform float global_snow_amount = 0.0; global uniform vec4 global_snow_color; global uniform float global_rain_intensity; +const float LEAVES_FULL_SNOW_START = 0.58; +const float LEAVES_FULL_SNOW_END = 0.86; uniform sampler2D wind_noise : filter_linear_mipmap; uniform bool billboard_enabled = true; @@ -110,7 +112,7 @@ void fragment() { float top_mask = 1.0 - shifted_uv.y; 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); - float full_snow_mask = smoothstep(0.78, 1.0, snow_amount) * clamp(snow_visibility, 0.0, 1.0); + float full_snow_mask = smoothstep(LEAVES_FULL_SNOW_START, LEAVES_FULL_SNOW_END, snow_amount) * clamp(snow_visibility, 0.0, 1.0); float final_snow_mask = max(snow_mask, full_snow_mask); float snow_light = mix(0.82, 1.0, max(v_shade_factor, 0.35)); diff --git a/core/daynight/weather_overlay.gdshader b/core/daynight/weather_overlay.gdshader index 2a47e23..62444cc 100644 --- a/core/daynight/weather_overlay.gdshader +++ b/core/daynight/weather_overlay.gdshader @@ -17,6 +17,8 @@ global uniform float global_snow_cap_flatness_end = 0.96; global uniform float global_snow_cap_noise_scale = 0.22; global uniform float global_snow_cap_noise_strength = 0.18; const float SNOW_VISUAL_RESPONSE = 0.55; +const float FULL_SNOW_VISUAL_START = 0.82; +const float FULL_SNOW_VISUAL_END = 0.98; uniform bool snow_noise_enabled = true; uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15; uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.2; @@ -156,6 +158,8 @@ void fragment() { float snow_factor = max(snow_edge * snow_coverage, flat_accumulation); float snow_opacity = clamp(snow_factor, 0.0, 1.0); snow_opacity = max(snow_opacity, flat_accumulation * mix(0.45, 0.9, snow_noise_mask)); + float full_snow_opacity = snow_edge * smoothstep(FULL_SNOW_VISUAL_START, FULL_SNOW_VISUAL_END, snow_progress); + snow_opacity = max(snow_opacity, full_snow_opacity); float shade = mix(-snow_color_variation, snow_color_variation, noise_val); vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0); diff --git a/tgcc/main menu/main_menu_test.tscn b/tgcc/main menu/main_menu_test.tscn index da80c6d..67ba1aa 100644 --- a/tgcc/main menu/main_menu_test.tscn +++ b/tgcc/main menu/main_menu_test.tscn @@ -324,6 +324,7 @@ train_start_mode = 2 train_start_stop_index = 0 train_start_position = 540.0 train_start_after_delay = false +train_facing_direction = 2 sleepers_model = ExtResource("10_00nq7") fireworks_scene = ExtResource("11_aylkj")