|
|
|
|
@@ -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:
|
|
|
|
|
|