diff --git a/scenes/car.tscn b/scenes/car.tscn index 39a897d..a4fda7a 100644 --- a/scenes/car.tscn +++ b/scenes/car.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=10 format=3 uid="uid://0g7qqh7naniv"] +[gd_scene load_steps=11 format=3 uid="uid://0g7qqh7naniv"] [ext_resource type="Script" path="res://scripts/car_node.gd" id="1_0tin3"] [ext_resource type="Script" path="res://scripts/car.gd" id="1_i5tet"] [ext_resource type="Texture2D" uid="uid://mqdujngircok" path="res://sprites/car_features.png" id="3_ts6mm"] [ext_resource type="Texture2D" uid="uid://e5aeyl47wi8p" path="res://sprites/car_body.png" id="4_lps13"] [ext_resource type="Script" path="res://scripts/label_round.gd" id="5_vheit"] +[ext_resource type="PackedScene" uid="uid://dl7r8s5sxyvlw" path="res://scenes/enginesound.tscn" id="6_v21se"] [sub_resource type="CapsuleShape2D" id="CapsuleShape2D_bj1hp"] radius = 8.0 @@ -106,5 +107,7 @@ libraries = { "": SubResource("AnimationLibrary_55lyd") } +[node name="Enginesound" parent="CharacterBody_Car" instance=ExtResource("6_v21se")] + [connection signal="timeout" from="CharacterBody_Car/resetTimer" to="CharacterBody_Car" method="_on_reset_timer_timeout"] [connection signal="timeout" from="CharacterBody_Car/collisionEnableTimer" to="CharacterBody_Car" method="_on_collision_enable_timer_timeout"] diff --git a/scenes/enginesound.tscn b/scenes/enginesound.tscn new file mode 100644 index 0000000..72c7a4b --- /dev/null +++ b/scenes/enginesound.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=3 format=3 uid="uid://dl7r8s5sxyvlw"] + +[ext_resource type="Script" path="res://scripts/enginesound.gd" id="1_1xhsl"] + +[sub_resource type="AudioStreamGenerator" id="AudioStreamGenerator_kj4va"] +buffer_length = 0.05 + +[node name="Enginesound" type="Node"] +script = ExtResource("1_1xhsl") + +[node name="Player" type="AudioStreamPlayer" parent="."] +stream = SubResource("AudioStreamGenerator_kj4va") +bus = &"Motor" diff --git a/scripts/car.gd b/scripts/car.gd index 1cf6605..8e8ab51 100644 --- a/scripts/car.gd +++ b/scripts/car.gd @@ -22,6 +22,7 @@ const STANDSTILLSPEED=0.5 var wheel_base = 60*0.5 var engine_power = 350 +var applied_engine_power=0 var friction = -0.5 var drag = -0.0005 @@ -70,6 +71,8 @@ var autosteer_enabled=false @onready var collision_shape: CollisionShape2D = $CollisionShape2D @onready var collision_enable_timer: Timer = $collisionEnableTimer +@onready var enginesound: Node = $Enginesound + var playerid=0 var finalTime=-1 @@ -81,7 +84,7 @@ func _ready() -> void: func _physics_process(delta: float) -> void: acceleration=Vector2.ZERO check_markers() - get_input() + get_input(delta) apply_friction() calculate_steering(delta) velocity +=acceleration*delta @@ -108,6 +111,10 @@ func _physics_process(delta: float) -> void: if velocity.length() > resetcar_movingspeed: reset_timer.stop() + + enginesound.setCarSpeed(velocity.length()) + enginesound.setCarAcceleration(applied_engine_power/engine_power,delta) + #print("Car Accel="+str(acceleration.length()) +"/"+str(engine_power)) func _on_reset_timer_timeout() -> void: @@ -121,7 +128,7 @@ func apply_friction(): acceleration+=drag_force+friction_force -func get_input(): +func get_input(delta:float): const distance_inf=1000 @@ -157,11 +164,12 @@ func get_input(): steer_direction=0 #drive straight - + applied_engine_power=0 if running: if Input.is_action_pressed(Gamestate.userinput_prefix+str(playerid)): #velocity = transform.x * 500 - acceleration = transform.x * engine_power + applied_engine_power=engine_power + if not autosteer_enabled: #start autosteer when accelerate is pressed autosteer_enabled=true @@ -172,7 +180,8 @@ func get_input(): autoreset=false #if Input.is_action_pressed("ui_down"): #acceleration = transform.x * braking - + + acceleration = transform.x * applied_engine_power if autoreset and running: acceleration = transform.x * braking #drive backwards diff --git a/scripts/enginesound.gd b/scripts/enginesound.gd new file mode 100644 index 0000000..90a1873 --- /dev/null +++ b/scripts/enginesound.gd @@ -0,0 +1,74 @@ +extends Node + + +var sample_hz = 44100.0 # Keep the number of samples to mix low, GDScript is not super fast. +@onready var noise = FastNoiseLite.new() + +var phase_rotation = 0.0 + +var vol_master=20.0 +var vol_overtones=0.0 +var vol_overtones_sample=0 +var vol_basefrequency=0.0 +var vol_basefrequency_sample=0 + +var playback: AudioStreamPlayback = null # Actual playback stream, assigned in _ready(). + +var carspeed=0 #m/s +var caraccel:float=0 #0 to 1 +var increment_motorrotation=1.0/2 +var offset_rotation=0 + + + +func setCarSpeed(s): + carspeed=s +func setCarAcceleration(a,delta): + a=min(1.0,max(a,0.0)) + var maxchange=2.0*delta + caraccel+=min(maxchange,max(a-caraccel,-maxchange)) + + +func _fill_buffer(): + var increment_motorrotation = carspeed*increment_motorrotation / sample_hz + + + var to_fill = playback.get_frames_available() + while to_fill > 0: + var sample=0 + + var maxsamplevolumechange=100/sample_hz + vol_basefrequency_sample+=clamp(vol_basefrequency-vol_basefrequency_sample,-maxsamplevolumechange,maxsamplevolumechange) + vol_overtones_sample+=clamp(vol_overtones-vol_overtones_sample,-maxsamplevolumechange,maxsamplevolumechange) + + sample+=noise.get_noise_2d(cos(phase_rotation*TAU)*2,sin(phase_rotation*TAU)*2)*vol_basefrequency_sample + sample+=noise.get_noise_2d(cos(phase_rotation*6*TAU)*0.5,sin(phase_rotation*3*TAU)*0.5)*vol_overtones_sample/2 + sample+=noise.get_noise_2d(cos(phase_rotation*3*TAU)*1,sin(phase_rotation*2*TAU)*1)*vol_overtones_sample + + + + playback.push_frame(Vector2.ONE * sample*vol_master) # Audio frames are stereo. + + + phase_rotation = fmod(phase_rotation + increment_motorrotation, 1.0) + + to_fill -= 1 + + +func _process(_delta): + + + vol_basefrequency=caraccel*clamp(remap(carspeed,20.0,100.0,0.0,1.0),0,1)*clamp(remap(carspeed,200.0,500.0,1.0,0.5),0,1) + vol_overtones=clamp(remap(carspeed,20.0,100.0,0.0,1.0),0,1)*clamp(remap(carspeed,200.0,500.0,1.0,0.5),0,1) + + _fill_buffer() + + +func _ready(): + # Setting mix rate is only possible before play(). + $Player.stream.mix_rate = sample_hz + $Player.play() + playback = $Player.get_stream_playback() + # `_fill_buffer` must be called *after* setting `playback`, + # as `fill_buffer` uses the `playback` member variable. + _fill_buffer()