diff --git a/menu/main_menu.gd b/menu/main_menu.gd index 07e6150..13d16d6 100644 --- a/menu/main_menu.gd +++ b/menu/main_menu.gd @@ -1,19 +1,26 @@ extends Panel + func _ready() -> void: + # gdlint: ignore=max-line-length $MarginContainer/VSplitContainer/VSplitContainer/CenterContainer/VBoxContainer/StartButton.grab_focus() + func _on_StartButton_pressed() -> void: get_tree().change_scene("res://menu/start_menu.tscn") + func _on_ExitButton_pressed() -> void: get_tree().quit() + func _on_SettingsButton_pressed() -> void: get_tree().change_scene("res://menu/settings_menu.tscn") + func _on_AboutButton_pressed() -> void: get_tree().change_scene("res://menu/about.tscn") + func _on_GodotButton_pressed() -> void: OS.shell_open("https://godotengine.org") diff --git a/menu/settings_menu.gd b/menu/settings_menu.gd index dae05b3..8dc0620 100644 --- a/menu/settings_menu.gd +++ b/menu/settings_menu.gd @@ -4,15 +4,24 @@ onready var master_bus := AudioServer.get_bus_index("Master") onready var sound_bus := AudioServer.get_bus_index("Sound") onready var music_bus := AudioServer.get_bus_index("Music") +# gdlint: ignore=max-line-length onready var master_slider: HSlider = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/MasterSlider +# gdlint: ignore=max-line-length onready var sound_slider: HSlider = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/SoundEffectsSlider +# gdlint: ignore=max-line-length onready var music_slider: HSlider = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/MusicSlider +# gdlint: ignore=max-line-length onready var auto_clutch_cb: CheckBox = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/AutoClutchCheckBox +# gdlint: ignore=max-line-length onready var automatic_transmission_cb: CheckBox = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/AutomaticTransmissionCheckBox +# gdlint: ignore=max-line-length onready var debug_cb: CheckBox = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/DebugModeCheckBox +# gdlint: ignore=max-line-length onready var fullscreen_cb: CheckBox = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/FullscreenCheckBox +# gdlint: ignore=max-line-length onready var borderless_cb: CheckBox = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/BorderlessCheckBox + func _ready() -> void: master_slider.value = db2linear(AudioServer.get_bus_volume_db(master_bus)) sound_slider.value = db2linear(AudioServer.get_bus_volume_db(sound_bus)) diff --git a/menu/start_menu.gd b/menu/start_menu.gd index 944f2c6..b2141d0 100644 --- a/menu/start_menu.gd +++ b/menu/start_menu.gd @@ -1,17 +1,20 @@ extends Panel -const buggy = preload("res://vehicles/buggy.tscn") -const beetle = preload("res://vehicles/beetlecar.tscn") -const bugmobile = preload("res://vehicles/bugmobile.tscn") -const test_scene = preload("res://scenes/test_level.tscn") -const infinite_loop_scene = preload("res://scenes/infinite_loop_track_level.tscn") -const gui_scene = preload("res://player/gui.tscn") +const BUGGY = preload("res://vehicles/buggy.tscn") +const BEETLE = preload("res://vehicles/beetlecar.tscn") +const BUGMOBILE = preload("res://vehicles/bugmobile.tscn") +const TEST_SCENE = preload("res://scenes/test_level.tscn") +const INFINITE_LOOP_SCENE = preload("res://scenes/infinite_loop_track_level.tscn") +const GUI_SCENE = preload("res://player/gui.tscn") +var vehicles = [BEETLE, BUGGY, BUGMOBILE] +var tracks = [TEST_SCENE, INFINITE_LOOP_SCENE] + +# gdlint: ignore=max-line-length onready var vehicle_selector = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/VehicleSelector +# gdlint: ignore=max-line-length onready var track_selector = $MarginContainer/VSplitContainer/CenterContainer/VBoxContainer/TrackSelector -var vehicles = [beetle, buggy, bugmobile] -var tracks = [test_scene, infinite_loop_scene] func _ready() -> void: vehicle_selector.grab_focus() @@ -22,6 +25,7 @@ func _ready() -> void: track_selector.add_item("Test track") track_selector.add_item("Infinite Loop") + func _on_StartButton_pressed() -> void: if vehicle_selector.get_selected_id() < 0: return @@ -31,8 +35,9 @@ func _on_StartButton_pressed() -> void: var track = tracks[track_selector.get_selected_id()] _start_track_with_vehicle(track.instance(), vehicle.instance()) + func _start_track_with_vehicle(track: Node, vehicle: Node) -> void: - var gui = gui_scene.instance() + var gui = GUI_SCENE.instance() vehicle.connect("speed_updated", gui, "update_speed") vehicle.connect("rpm_updated", gui, "update_rpm") vehicle.connect("gear_updated", gui, "update_gear") @@ -40,5 +45,6 @@ func _start_track_with_vehicle(track: Node, vehicle: Node) -> void: get_tree().root.call_deferred("add_child", track) queue_free() + func _on_BackButton_pressed() -> void: get_tree().change_scene("res://menu/main_menu.tscn") diff --git a/player/camera.gd b/player/camera.gd index fe93ff6..dfdee34 100644 --- a/player/camera.gd +++ b/player/camera.gd @@ -1,24 +1,26 @@ extends Camera -export (NodePath) var follow_target_path = null +export(NodePath) var follow_target_path = null export var target_distance: float = 3.0 export var target_height: float = 2.0 var follow_target: Node = null var last_lookat: Vector3 + # Called when the node enters the scene tree for the first time. func _ready(): follow_target = get_node(follow_target_path) last_lookat = follow_target.global_transform.origin + func _physics_process(delta): var delta_v = global_transform.origin - follow_target.global_transform.origin var target_pos = global_transform.origin delta_v.y = 0.0 - if (delta_v.length() > target_distance): + if delta_v.length() > target_distance: delta_v = delta_v.normalized() * target_distance delta_v.y = target_height target_pos = follow_target.global_transform.origin + delta_v @@ -27,6 +29,8 @@ func _physics_process(delta): global_transform.origin = global_transform.origin.linear_interpolate(target_pos, delta * 20.0) - last_lookat = last_lookat.linear_interpolate(follow_target.global_transform.origin, delta * 20.0) + last_lookat = last_lookat.linear_interpolate( + follow_target.global_transform.origin, delta * 20.0 + ) look_at(last_lookat, Vector3(0.0, 1.0, 0.0)) diff --git a/player/gui.gd b/player/gui.gd index 8993784..a4ee615 100644 --- a/player/gui.gd +++ b/player/gui.gd @@ -1,5 +1,7 @@ extends MarginContainer +var min_rotation = -85 +var max_rotation = 75 onready var rpm_needle = $HBoxContainer/RPMGauge/RPMNeedle onready var rpm_label = $HBoxContainer/RPMGauge/Panel/RPMLabel @@ -7,20 +9,21 @@ onready var speed_needle = $HBoxContainer/SpeedGauge/SpeedNeedle onready var speed_label = $HBoxContainer/SpeedGauge/Panel/SpeedLabel onready var gear_label = $HBoxContainer/GearLabel -var min_rotation = -85 -var max_rotation = 75 func _get_rotation(percent: float) -> float: return min_rotation + (max_rotation - min_rotation) * percent + func update_speed(speed: int, speed_percent: float) -> void: speed_needle.rect_rotation = _get_rotation(speed_percent) speed_label.text = str(speed) + func update_rpm(rpm: int, rpm_percent: float) -> void: rpm_needle.rect_rotation = _get_rotation(rpm_percent) rpm_label.text = str(rpm) + func update_gear(gear: int) -> void: if gear == -1: gear_label.text = "R" diff --git a/scenes/base_track_level.gd b/scenes/base_track_level.gd index 1c85b47..e0407f9 100644 --- a/scenes/base_track_level.gd +++ b/scenes/base_track_level.gd @@ -1,18 +1,20 @@ class_name BaseTrackLevel extends Spatial -const camera = preload("res://player/camera.tscn") -onready var spawn_point = $PlayerSpawnLocation -onready var track = $Track +const CAMERA = preload("res://player/CAMERA.tscn") + var player_node: Node var gui: Node +onready var spawn_point = $PlayerSpawnLocation +onready var track = $Track + func _ready() -> void: player_node.global_transform = spawn_point.global_transform add_child(player_node) add_child(gui) - var player_camera = camera.instance() + var player_camera = CAMERA.instance() player_camera.global_transform = spawn_point.global_transform player_camera.global_transform.origin -= spawn_point.global_transform.basis.z * 1000 player_camera.follow_target_path = player_node.get_path() diff --git a/scenes/trackgui.gd b/scenes/trackgui.gd index 6acae4f..243cba0 100644 --- a/scenes/trackgui.gd +++ b/scenes/trackgui.gd @@ -6,6 +6,7 @@ onready var time_value = $VBoxContainer/HBoxContainer/TimeValue onready var best_time_value = $VBoxContainer/HBoxContainer/BestTimeValue onready var wrong_way_label = $VBoxContainer/WrongWayLabel + func _ready() -> void: time_value.text = "NaN" best_time_value.text = "NaN" diff --git a/scenes/tracks/track.gd b/scenes/tracks/track.gd index 2135fd1..bc1bd27 100644 --- a/scenes/tracks/track.gd +++ b/scenes/tracks/track.gd @@ -3,24 +3,27 @@ extends Spatial signal time_updated(new_time) signal lap_complete(lap_time) -signal wrong_way() +signal wrong_way -export (NodePath) var track_path = null -export (int, 10, 50) var checkpoint_count = 20 -export (Vector2) var checkpoint_dim = Vector2(20, 15) -export (Material) var debug_material = null +export(NodePath) var track_path = null +export(int, 10, 50) var checkpoint_count = 20 +export(Vector2) var checkpoint_dim = Vector2(20, 15) +export(Material) var debug_material = null -onready var checkpoints = $Checkpoints -onready var path: Path = get_node(track_path) var furthest_checkpoint = -1 var last_checkpoint = -1 var start_time = 0 var current_time = 0 +onready var checkpoints = $Checkpoints +onready var path: Path = get_node(track_path) + + func get_last_checkpoint() -> Node: return checkpoints.get_child(max(0, last_checkpoint)) + func _ready() -> void: start_time = OS.get_ticks_msec() var length = path.curve.get_baked_length() @@ -42,17 +45,16 @@ func _ready() -> void: var meshinst = MeshInstance.new() meshinst.mesh = mesh new_checkpoint.add_child(meshinst) - new_checkpoint.connect("body_entered", self, "_on_body_entered_area", [ new_checkpoint ]) + new_checkpoint.connect("body_entered", self, "_on_body_entered_area", [new_checkpoint]) checkpoints.global_transform.origin = path.global_transform.origin -func _process(delta: float) -> void: +func _process(_delta: float) -> void: _update_time() func _on_body_entered_area(body: Node, area: Area) -> void: if body.get_groups().has("car"): - if area.get_index() < last_checkpoint || abs(area.get_index() - last_checkpoint) > 1: emit_signal("wrong_way") @@ -77,6 +79,7 @@ func _build_checkpoint_collision(): collision.shape = shape return collision + func _update_time(): current_time = OS.get_ticks_msec() - start_time emit_signal("time_updated", current_time) diff --git a/scripts/devsetup b/scripts/devsetup new file mode 100755 index 0000000..c37a177 --- /dev/null +++ b/scripts/devsetup @@ -0,0 +1,10 @@ +#!/bin/bash + +echo "Checking for gdtoolkit" +(type gdformat > /dev/null 2>&1 || pip install gdtoolkit || echo "Can't install gdtoolkit. Try to install it manually!" && exit 1) +echo "Gdtoolkit ready!" + +echo "Preparing pre-commit hook" +cp scripts/pre-commit .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +echo "Pre-commit hook ready" diff --git a/scripts/pre-commit b/scripts/pre-commit new file mode 100755 index 0000000..35dc2ab --- /dev/null +++ b/scripts/pre-commit @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +gdformat . && gdlint . diff --git a/settings/GlobalSettings.gd b/settings/GlobalSettings.gd index 98a4d7b..cd8715f 100644 --- a/settings/GlobalSettings.gd +++ b/settings/GlobalSettings.gd @@ -1,6 +1,5 @@ extends Node - var debug: bool = false var auto_clutch: bool = false var automatic_transmission: bool = false diff --git a/vehicles/tire_smoke.gd b/vehicles/tire_smoke.gd index 1ad9b99..fd69dc4 100644 --- a/vehicles/tire_smoke.gd +++ b/vehicles/tire_smoke.gd @@ -4,10 +4,12 @@ extends Particles onready var sound_player: AudioStreamPlayer3D = $tire_sound_player onready var sound_playback: AudioStreamPlayback = $tire_sound_player.get_stream_playback() + func _ready() -> void: _update_sound(1) # sound_player.play() + func update(skidinfo: float) -> void: _update_sound(skidinfo) if skidinfo < 0.5: @@ -15,6 +17,7 @@ func update(skidinfo: float) -> void: else: emitting = false + func _update_sound(skidinfo: float) -> void: sound_player.pitch_scale = 1 + (1 - skidinfo) var to_fill = sound_playback.get_frames_available() diff --git a/vehicles/vehicle.gd b/vehicles/vehicle.gd index 16c4460..e2a7571 100644 --- a/vehicles/vehicle.gd +++ b/vehicles/vehicle.gd @@ -5,22 +5,19 @@ signal speed_updated(speed_kph, speed_percent) signal rpm_updated(rpm, rpm_percent) signal gear_updated(gear) -export(float) var MAX_STEER_ANGLE = 25 -export(float) var SPEED_STEER_ANGLE = 10 -export(float) var MAX_STEER_SPEED = 100.0 -export(float) var MAX_STEER_INPUT = 80.0 +export(float) var max_steer_angle = 25 +export(float) var speed_steer_angle = 10 +export(float) var max_steer_speed = 100.0 +export(float) var max_steer_input = 80.0 -onready var max_steer_angle_rad: float = deg2rad(MAX_STEER_ANGLE) -onready var speed_steer_angle_rad: float = deg2rad(SPEED_STEER_ANGLE) -onready var max_steer_input_rad: float = deg2rad(MAX_STEER_INPUT) export(Curve) var steer_curve = null -export(float) var MAX_ENGINE_FORCE = 85.0 -export(float) var MAX_BRAKE_FORCE = 50.0 -export(float) var THROTTLE_POWER = 6000.0 -export(float) var MAX_RPM_LOSS_PS = 3000.0 -export(float) var BASE_ENGINE_PITCH = 0.5 -export(float) var EXPECTED_MAX_SPEED = 200 +export(float) var max_engine_force = 85.0 +export(float) var max_brake_force = 50.0 +export(float) var throttle_power = 6000.0 +export(float) var max_rpm_loss_ps = 3000.0 +export(float) var base_engine_pitch = 0.5 +export(float) var expected_max_speed = 200 export(Array) var gear_ratios = [3.4, 2.5, 2.0, 1.5, 1.25] export(float) var reverse_ratio = -3 @@ -37,6 +34,9 @@ var gear = 1 var gear_timer = 0 +var traction_wheels: Array +var reset_transform: Transform = Transform.IDENTITY + onready var frwheel: VehicleWheel = $front_right onready var flwheel: VehicleWheel = $front_left onready var rrwheel: VehicleWheel = $rear_right @@ -49,8 +49,9 @@ onready var rlsmoke: TireSmoke = $rl_tire_smoke onready var engine_sound_player: AudioStreamPlayer3D = $engine_sound_player onready var engine_sound_playback: AudioStreamPlayback = $engine_sound_player.get_stream_playback() -var traction_wheels: Array -var reset_transform: Transform = Transform.IDENTITY +onready var max_steer_angle_rad: float = deg2rad(max_steer_angle) +onready var speed_steer_angle_rad: float = deg2rad(speed_steer_angle) +onready var max_steer_input_rad: float = deg2rad(max_steer_input) func _ready(): @@ -61,11 +62,13 @@ func _ready(): _generate_engine_sound(0) engine_sound_player.play() + func _integrate_forces(state: PhysicsDirectBodyState) -> void: if reset_transform != Transform.IDENTITY: state.set_transform(reset_transform) reset_transform = Transform.IDENTITY + func _get_gear_ratio(): if gear == 0: return 0 @@ -107,9 +110,9 @@ func _update_wheels_smoke(): func _lerp_rpm(from, to, delta, factor): var new_val = lerp(from, to, factor) - if abs(from - new_val) > MAX_RPM_LOSS_PS * delta: + if abs(from - new_val) > max_rpm_loss_ps * delta: var new_factor = inverse_lerp( - from, to, from - sign(from - new_val) * MAX_RPM_LOSS_PS * delta + from, to, from - sign(from - new_val) * max_rpm_loss_ps * delta ) new_val = lerp(from, to, new_factor) return new_val @@ -134,9 +137,9 @@ func _physics_process(delta: float): else: rpm = _lerp_rpm(rpm, min_rpm, delta, delta) if _has_traction(): - rpm += throttle * delta * (max(clutch_position, 1 if gear == 0 else 0)) * THROTTLE_POWER + rpm += throttle * delta * (max(clutch_position, 1 if gear == 0 else 0)) * throttle_power else: - rpm += throttle * delta * THROTTLE_POWER + rpm += throttle * delta * throttle_power rpm = clamp(rpm, 0, max_rpm) var rpm_factor = clamp(rpm / max_rpm, 0.0, 1.0) var power_factor = power_curve.interpolate_baked(rpm_factor) @@ -148,15 +151,15 @@ func _physics_process(delta: float): var final_input = transmission_input * final_drive - brake = Input.get_action_strength("brake") * MAX_BRAKE_FORCE - engine_force = throttle * final_input * MAX_ENGINE_FORCE + brake = Input.get_action_strength("brake") * max_brake_force + engine_force = throttle * final_input * max_engine_force var handbrake = Input.get_action_strength("handbrake") - rrwheel.brake = handbrake * MAX_BRAKE_FORCE - rlwheel.brake = handbrake * MAX_BRAKE_FORCE + rrwheel.brake = handbrake * max_brake_force + rlwheel.brake = handbrake * max_brake_force var speed = wheel_rpm * 2.0 * PI * rrwheel.wheel_radius / 60.0 * 3600.0 / 1000.0 - emit_signal("speed_updated", speed, speed / EXPECTED_MAX_SPEED) + emit_signal("speed_updated", speed, speed / expected_max_speed) emit_signal("rpm_updated", rpm, rpm_factor) var steering_input = ( @@ -171,13 +174,13 @@ func _physics_process(delta: float): else: steering_input = steer_curve.interpolate_baked(steering_input) - var steer_speed_factor = clamp(speed / MAX_STEER_SPEED, 0.0, 1.0) + var steer_speed_factor = clamp(speed / max_steer_speed, 0.0, 1.0) steering = steering_input * lerp(max_steer_angle_rad, speed_steer_angle_rad, steer_speed_factor) func _generate_engine_sound(rpm_factor): - engine_sound_player.pitch_scale = BASE_ENGINE_PITCH + 2 * rpm_factor + engine_sound_player.pitch_scale = base_engine_pitch + 2 * rpm_factor var to_fill = engine_sound_playback.get_frames_available() var factor = rpm_factor if to_fill <= 0: