From d501e08995ce78ac8257c1918ddbd4d9fead8ea2 Mon Sep 17 00:00:00 2001 From: KirbyKidJ <70983335+KirbyKid256@users.noreply.github.com> Date: Mon, 22 Sep 2025 00:24:52 -0700 Subject: [PATCH 1/4] Hitbox Change for When Small and Crouching Adds a quick change to parallel SMM2. I noticed when trying to duck under a Rocky Wrench's wrench while small, I still got hit. So I added an extra hitbox for when you crouch and are small. It was actually incredibly hard to test if this was accurate in SMM2 since the enemy had Stormtrooper aim. But when it throws a wrench directly at your face and you duck, you can dodge it. --- Scenes/Prefabs/Entities/Player.tscn | 21 ++++++++++++++++++++- Scripts/Classes/Entities/Player.gd | 12 ++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Scenes/Prefabs/Entities/Player.tscn b/Scenes/Prefabs/Entities/Player.tscn index 69a2f76..6081579 100644 --- a/Scenes/Prefabs/Entities/Player.tscn +++ b/Scenes/Prefabs/Entities/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=83 format=3 uid="uid://cuh62hlq8errh"] +[gd_scene load_steps=84 format=3 uid="uid://cuh62hlq8errh"] [ext_resource type="Script" uid="uid://dt4rosa5o35xr" path="res://Scripts/Classes/Entities/Player.gd" id="1_f6bau"] [ext_resource type="Script" uid="uid://uribh0f1jttq" path="res://Scripts/Classes/States/StateMachine.gd" id="2_1y62l"] @@ -469,6 +469,10 @@ func _physics_process(_delta: float) -> void: print(Global.level_editor.entity_tiles) " +[sub_resource type="RectangleShape2D" id="RectangleShape2D_fqdtv"] +resource_local_to_scene = true +size = Vector2(4, 4.5) + [sub_resource type="RectangleShape2D" id="RectangleShape2D_d7xah"] resource_local_to_scene = true size = Vector2(4, 6.75) @@ -1039,6 +1043,12 @@ mode = 1 resource_json = ExtResource("10_xy8gq") metadata/_custom_type_script = "uid://cbal8ms2oe1ik" +[node name="CrouchCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] +visible = false +polygon = PackedVector2Array(4, -2, 4, -8, 1, -11, -1, -11, -4, -8, -4, -2, -2, 0, 2, 0) +one_way_collision = true +script = ExtResource("35_nbkfn") + [node name="SmallCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] polygon = PackedVector2Array(4, -2, 4, -8, 1, -14, -1, -14, -4, -8, -4, -2, -2, 0, 2, 0) one_way_collision = true @@ -1090,6 +1100,15 @@ hit_from_inside = true collision_layer = 0 collision_mask = 4 +[node name="CrouchShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] +visible = false +position = Vector2(0, -12.75) +shape = SubResource("RectangleShape2D_fqdtv") +debug_color = Color(1, 0, 0, 0.419608) +script = ExtResource("21_jl70t") +offset = Vector2(0, 10.5) +link = NodePath("../../CrouchCollision") + [node name="SmallShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] visible = false position = Vector2(0, -16.875) diff --git a/Scripts/Classes/Entities/Player.gd b/Scripts/Classes/Entities/Player.gd index b1cab2f..7a49178 100644 --- a/Scripts/Classes/Entities/Player.gd +++ b/Scripts/Classes/Entities/Player.gd @@ -436,10 +436,18 @@ func handle_directions() -> void: var use_big_collision := false func handle_power_up_states(delta) -> void: + var small_crouch := power_state.hitbox_size == "Small" and crouching + var big_crouch := power_state.hitbox_size == "Big" and crouching + for i in get_tree().get_nodes_in_group("SmallCollisions"): + if i.owner == self: + if i.name.begins_with("Crouch"): + i.set_deferred("disabled", power_state.hitbox_size == "Small" and !crouching) + else: + i.set_deferred("disabled", small_crouch or power_state.hitbox_size == "Big" and !crouching) for i in get_tree().get_nodes_in_group("BigCollisions"): if i.owner == self: - i.set_deferred("disabled", power_state.hitbox_size == "Small" or crouching) - $Checkpoint.position.y = -24 if power_state.hitbox_size == "Small" or crouching else -40 + i.set_deferred("disabled", power_state.hitbox_size == "Small" or big_crouch) + $Checkpoint.position.y = -20 if small_crouch else -24 if power_state.hitbox_size == "Small" or big_crouch else -40 power_state.update(delta) func handle_wing_flight(delta: float) -> void: From cd2e7522b518ab208d1827a0ddacfcab2a86227d Mon Sep 17 00:00:00 2001 From: KirbyKidJ <70983335+KirbyKid256@users.noreply.github.com> Date: Mon, 22 Sep 2025 21:51:48 -0700 Subject: [PATCH 2/4] Renamed `CrouchShape` to `SmallCrouchShape` Easier to search for on VSC --- Scenes/Prefabs/Entities/Player.tscn | 6 +++--- Scripts/Classes/Entities/Player.gd | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Scenes/Prefabs/Entities/Player.tscn b/Scenes/Prefabs/Entities/Player.tscn index 6081579..923a7db 100644 --- a/Scenes/Prefabs/Entities/Player.tscn +++ b/Scenes/Prefabs/Entities/Player.tscn @@ -1043,7 +1043,7 @@ mode = 1 resource_json = ExtResource("10_xy8gq") metadata/_custom_type_script = "uid://cbal8ms2oe1ik" -[node name="CrouchCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] +[node name="SmallCrouchCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] visible = false polygon = PackedVector2Array(4, -2, 4, -8, 1, -11, -1, -11, -4, -8, -4, -2, -2, 0, 2, 0) one_way_collision = true @@ -1100,14 +1100,14 @@ hit_from_inside = true collision_layer = 0 collision_mask = 4 -[node name="CrouchShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] +[node name="SmallCrouchShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] visible = false position = Vector2(0, -12.75) shape = SubResource("RectangleShape2D_fqdtv") debug_color = Color(1, 0, 0, 0.419608) script = ExtResource("21_jl70t") offset = Vector2(0, 10.5) -link = NodePath("../../CrouchCollision") +link = NodePath("../../SmallCrouchCollision") [node name="SmallShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] visible = false diff --git a/Scripts/Classes/Entities/Player.gd b/Scripts/Classes/Entities/Player.gd index 7a49178..a5b16dc 100644 --- a/Scripts/Classes/Entities/Player.gd +++ b/Scripts/Classes/Entities/Player.gd @@ -440,7 +440,7 @@ func handle_power_up_states(delta) -> void: var big_crouch := power_state.hitbox_size == "Big" and crouching for i in get_tree().get_nodes_in_group("SmallCollisions"): if i.owner == self: - if i.name.begins_with("Crouch"): + if i.name.begins_with("SmallCrouch"): i.set_deferred("disabled", power_state.hitbox_size == "Small" and !crouching) else: i.set_deferred("disabled", small_crouch or power_state.hitbox_size == "Big" and !crouching) From 3a3340ed887a2f81172d3e3d8a51d9d5613a0829 Mon Sep 17 00:00:00 2001 From: KirbyKidJ <70983335+KirbyKid256@users.noreply.github.com> Date: Fri, 26 Sep 2025 11:46:09 -0700 Subject: [PATCH 3/4] Prevents small crouch if it's not a used animation Also added some functions for debugging and toggling visible collisions. Also fixed some inconsistencies with both small and big collisions. --- Scenes/Prefabs/Entities/Player.tscn | 3 ++- Scripts/Classes/Entities/Player.gd | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Scenes/Prefabs/Entities/Player.tscn b/Scenes/Prefabs/Entities/Player.tscn index 54661da..c7b80ab 100644 --- a/Scenes/Prefabs/Entities/Player.tscn +++ b/Scenes/Prefabs/Entities/Player.tscn @@ -711,7 +711,7 @@ position = Vector2(0, -13) collision_layer = 0 collision_mask = 384 -[node name="SmallShape" type="CollisionShape2D" parent="LavaPoisonDetect"] +[node name="SmallShape" type="CollisionShape2D" parent="LavaPoisonDetect" groups=["SmallCollisions"]] position = Vector2(0, 5.75) shape = SubResource("RectangleShape2D_uwhl4") debug_color = Color(1, 0, 0, 0.419608) @@ -1057,6 +1057,7 @@ script = ExtResource("35_nbkfn") [node name="BigCollision" type="CollisionPolygon2D" parent="." groups=["BigCollisions"]] visible = false polygon = PackedVector2Array(-4, -2, -2, 0, 2, 0, 4, -2, 4, -23, 1, -28, -1, -28, -4, -23) +one_way_collision = true script = ExtResource("35_nbkfn") [node name="FootL" type="CollisionShape2D" parent="." groups=["StepCollision"]] diff --git a/Scripts/Classes/Entities/Player.gd b/Scripts/Classes/Entities/Player.gd index 4698ebf..caf91db 100644 --- a/Scripts/Classes/Entities/Player.gd +++ b/Scripts/Classes/Entities/Player.gd @@ -59,7 +59,10 @@ var total_keys := 0 set_power_state_frame() var character := "Mario" -var crouching := false +var crouching := false: + get(): # You can't crouch if the animation somehow doesn't exist. + if not sprite.sprite_frames.has_animation("Crouch"): return false + return crouching var skidding := false var can_bump_sfx := true @@ -137,6 +140,7 @@ const ANIMATION_FALLBACKS := { "Run": "Move", "PipeWalk": "Move", "LookUp": "Idle", + "Crouch": "Idle", "CrouchFall": "Crouch", "CrouchAttack": "Attack", "FlagSlide": "Climb", @@ -456,14 +460,15 @@ func handle_power_up_states(delta) -> void: var small_crouch := power_state.hitbox_size == "Small" and crouching var big_crouch := power_state.hitbox_size == "Big" and crouching for i in get_tree().get_nodes_in_group("SmallCollisions"): - if i.owner == self: - if i.name.begins_with("SmallCrouch"): - i.set_deferred("disabled", power_state.hitbox_size == "Small" and !crouching) - else: - i.set_deferred("disabled", small_crouch or power_state.hitbox_size == "Big" and !crouching) + if i.name.begins_with("SmallCrouch"): + i.set_deferred("disabled", power_state.hitbox_size == "Small" and !crouching or power_state.hitbox_size == "Big") + i.visible = not i.disabled + else: + i.set_deferred("disabled", small_crouch or power_state.hitbox_size == "Big" and !crouching) + i.visible = not i.disabled for i in get_tree().get_nodes_in_group("BigCollisions"): - if i.owner == self: - i.set_deferred("disabled", power_state.hitbox_size == "Small" or big_crouch) + i.set_deferred("disabled", power_state.hitbox_size == "Small" or big_crouch) + i.visible = not i.disabled $Checkpoint.position.y = -20 if small_crouch else -24 if power_state.hitbox_size == "Small" or big_crouch else -40 power_state.update(delta) From e6bc64affb161f05650ecbd5405b90c69fb1eb3d Mon Sep 17 00:00:00 2001 From: KirbyKidJ <70983335+KirbyKid256@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:16:14 -0700 Subject: [PATCH 4/4] Refactored Small Crouching and Big Crouching - Added new variables to `CharacterInfo.json` - Made it so `BlockCollision` area position is attached to top of `SmallCollision` and `BigCollision` --- .../Sprites/Players/Luigi/CharacterInfo.json | 6 ++-- .../Sprites/Players/Mario/CharacterInfo.json | 8 +++-- .../Sprites/Players/Toad/CharacterInfo.json | 6 ++-- .../Players/Toadette/CharacterInfo.json | 6 ++-- Scenes/Prefabs/Entities/Player.tscn | 29 +++------------ .../Components/ScalableCollisionPolygon.gd | 8 ++++- .../Components/ScalableCollisionShape.gd | 13 ++++--- Scripts/Classes/Entities/Player.gd | 36 ++++++++++--------- 8 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Assets/Sprites/Players/Luigi/CharacterInfo.json b/Assets/Sprites/Players/Luigi/CharacterInfo.json index 2a0cde9..df444e0 100644 --- a/Assets/Sprites/Players/Luigi/CharacterInfo.json +++ b/Assets/Sprites/Players/Luigi/CharacterInfo.json @@ -34,8 +34,10 @@ "DEATH_JUMP_HEIGHT": 300.0, - "can_air_turn": false, + "can_air_turn": false }, "small_hitbox_scale": [1.0, 1.0], - "big_hitbox_scale": [1.0, 1.0] + "small_crouch_scale": 0.75, + "big_hitbox_scale": [1.0, 1.0], + "big_crouch_scale": 0.5 } diff --git a/Assets/Sprites/Players/Mario/CharacterInfo.json b/Assets/Sprites/Players/Mario/CharacterInfo.json index a8afc88..04e7765 100644 --- a/Assets/Sprites/Players/Mario/CharacterInfo.json +++ b/Assets/Sprites/Players/Mario/CharacterInfo.json @@ -34,8 +34,10 @@ "DEATH_JUMP_HEIGHT": 300.0, - "can_air_turn": false, + "can_air_turn": false }, - "small_hitbox_scale": [1, 1], - "big_hitbox_scale": [1.0, 1.0] + "small_hitbox_scale": [1.0, 1.0], + "small_crouch_scale": 0.75, + "big_hitbox_scale": [1.0, 1.0], + "big_crouch_scale": 0.5 } diff --git a/Assets/Sprites/Players/Toad/CharacterInfo.json b/Assets/Sprites/Players/Toad/CharacterInfo.json index 6d81644..6b7492c 100644 --- a/Assets/Sprites/Players/Toad/CharacterInfo.json +++ b/Assets/Sprites/Players/Toad/CharacterInfo.json @@ -34,8 +34,10 @@ "DEATH_JUMP_HEIGHT": 300.0, - "can_air_turn": false, + "can_air_turn": false }, "small_hitbox_scale": [1.0, 1.0], - "big_hitbox_scale": [1.0, 1.0] + "small_crouch_scale": 0.75, + "big_hitbox_scale": [1.0, 1.0], + "big_crouch_scale": 0.5 } diff --git a/Assets/Sprites/Players/Toadette/CharacterInfo.json b/Assets/Sprites/Players/Toadette/CharacterInfo.json index ae4d187..268de71 100644 --- a/Assets/Sprites/Players/Toadette/CharacterInfo.json +++ b/Assets/Sprites/Players/Toadette/CharacterInfo.json @@ -34,8 +34,10 @@ "DEATH_JUMP_HEIGHT": 300.0, - "can_air_turn": false, + "can_air_turn": false }, "small_hitbox_scale": [1.0, 1.0], - "big_hitbox_scale": [1.0, 1.0] + "small_crouch_scale": 0.75, + "big_hitbox_scale": [1.0, 1.0], + "big_crouch_scale": 0.5 } diff --git a/Scenes/Prefabs/Entities/Player.tscn b/Scenes/Prefabs/Entities/Player.tscn index fbc64da..682cb96 100644 --- a/Scenes/Prefabs/Entities/Player.tscn +++ b/Scenes/Prefabs/Entities/Player.tscn @@ -470,10 +470,6 @@ func _physics_process(_delta: float) -> void: print(Global.level_editor.entity_tiles) " -[sub_resource type="RectangleShape2D" id="RectangleShape2D_fqdtv"] -resource_local_to_scene = true -size = Vector2(4, 4.5) - [sub_resource type="RectangleShape2D" id="RectangleShape2D_d7xah"] resource_local_to_scene = true size = Vector2(4, 6.75) @@ -1048,19 +1044,12 @@ mode = 1 resource_json = ExtResource("10_xy8gq") metadata/_custom_type_script = "uid://cbal8ms2oe1ik" -[node name="SmallCrouchCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] -visible = false -polygon = PackedVector2Array(4, -2, 4, -8, 1, -11, -1, -11, -4, -8, -4, -2, -2, 0, 2, 0) -one_way_collision = true -script = ExtResource("35_nbkfn") - [node name="SmallCollision" type="CollisionPolygon2D" parent="." groups=["SmallCollisions"]] polygon = PackedVector2Array(4, -2, 4, -8, 1, -14, -1, -14, -4, -8, -4, -2, -2, 0, 2, 0) one_way_collision = true script = ExtResource("35_nbkfn") [node name="BigCollision" type="CollisionPolygon2D" parent="." groups=["BigCollisions"]] -visible = false polygon = PackedVector2Array(-4, -2, -2, 0, 2, 0, 4, -2, 4, -23, 1, -28, -1, -28, -4, -23) one_way_collision = true script = ExtResource("35_nbkfn") @@ -1106,32 +1095,22 @@ hit_from_inside = true collision_layer = 0 collision_mask = 4 -[node name="SmallCrouchShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] -visible = false -position = Vector2(0, -12.75) -shape = SubResource("RectangleShape2D_fqdtv") -debug_color = Color(1, 0, 0, 0.419608) -script = ExtResource("21_jl70t") -offset = Vector2(0, 10.5) -link = NodePath("../../SmallCrouchCollision") - [node name="SmallShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["SmallCollisions"]] -visible = false -position = Vector2(0, -16.875) +position = Vector2(0, -3.375) shape = SubResource("RectangleShape2D_d7xah") debug_color = Color(1, 0, 0, 0.419608) script = ExtResource("21_jl70t") -offset = Vector2(0, 13.5) link = NodePath("../../SmallCollision") +metadata/scalable = false [node name="BigShape" type="CollisionShape2D" parent="BlockCollision" node_paths=PackedStringArray("link") groups=["BigCollisions"]] -position = Vector2(0, -32) +position = Vector2(0, -6) shape = SubResource("RectangleShape2D_34tqy") disabled = true debug_color = Color(1, 0, 0, 0.419608) script = ExtResource("21_jl70t") -offset = Vector2(0, 26) link = NodePath("../../BigCollision") +metadata/scalable = false [node name="TimerWarn" type="AudioStreamPlayer" parent="."] process_mode = 3 diff --git a/Scripts/Classes/Components/ScalableCollisionPolygon.gd b/Scripts/Classes/Components/ScalableCollisionPolygon.gd index 910209e..1f3c204 100644 --- a/Scripts/Classes/Components/ScalableCollisionPolygon.gd +++ b/Scripts/Classes/Components/ScalableCollisionPolygon.gd @@ -3,10 +3,16 @@ extends CollisionPolygon2D @export var offset := Vector2.ZERO @export var height := 0.0 +@export var hitbox := Vector3.ONE + +var crouching := false func _physics_process(_delta: float) -> void: + scale = Vector2(hitbox.x, hitbox.y) + if crouching and get_meta("scalable", true): scale.y *= hitbox.z update() func update() -> void: var height_to_use = height - position.y = -height_to_use / 2 * scale.y - offset.y + if get_meta("scalable", true): + position.y = -height_to_use / 2 * scale.y - offset.y diff --git a/Scripts/Classes/Components/ScalableCollisionShape.gd b/Scripts/Classes/Components/ScalableCollisionShape.gd index 3f6f3f0..e21b4a4 100644 --- a/Scripts/Classes/Components/ScalableCollisionShape.gd +++ b/Scripts/Classes/Components/ScalableCollisionShape.gd @@ -2,16 +2,19 @@ extends CollisionShape2D @export var offset := Vector2.ZERO -@export var link: Node2D +@export var link: CollisionPolygon2D +@export var hitbox := Vector3.ONE -func _ready() -> void: - set_process(Engine.is_editor_hint()) +var crouching := false -func _process(_delta: float) -> void: +func _physics_process(_delta: float) -> void: + scale = Vector2(hitbox.x, hitbox.y) + if crouching and get_meta("scalable", true): scale.y *= hitbox.z update() func update() -> void: var height_to_use = shape.size.y if link != null: height_to_use *= link.scale.y * link.scale.y - position.y = -height_to_use / 2 * scale.y - offset.y + if get_meta("scalable", true): + position.y = -height_to_use / 2 * scale.y - offset.y diff --git a/Scripts/Classes/Entities/Player.gd b/Scripts/Classes/Entities/Player.gd index 10bf2a3..6f8bbea 100644 --- a/Scripts/Classes/Entities/Player.gd +++ b/Scripts/Classes/Entities/Player.gd @@ -231,12 +231,12 @@ func apply_character_physics() -> void: for i in get_tree().get_nodes_in_group("SmallCollisions"): var hitbox_scale = json.get("small_hitbox_scale", [1, 1]) - i.scale = Vector2(hitbox_scale[0], hitbox_scale[1]) - i.update() + i.hitbox = Vector3(hitbox_scale[0], hitbox_scale[1] if i.get_meta("scalable", true) else 1, json.get("small_crouch_scale", 0.75)) + i._physics_process(0) for i in get_tree().get_nodes_in_group("BigCollisions"): var hitbox_scale = json.get("big_hitbox_scale", [1, 1]) - i.scale = Vector2(hitbox_scale[0], hitbox_scale[1]) - i.update() + i.hitbox = Vector3(hitbox_scale[0], hitbox_scale[1] if i.get_meta("scalable", true) else 1, json.get("big_crouch_scale", 0.5)) + i._physics_process(0) func apply_classic_physics() -> void: var json = JSON.parse_string(FileAccess.open("res://Resources/ClassicPhysics.json", FileAccess.READ).get_as_text()) @@ -470,7 +470,15 @@ func handle_invincible_palette() -> void: func handle_block_collision_detection() -> void: if ["Pipe"].has(state_machine.state.name): return - + match power_state.hitbox_size: + "Small": + var points: Array = $SmallCollision.polygon + points.sort_custom(func(a, b): return a.y < b.y) + $BlockCollision.position.y = points.front().y * $SmallCollision.scale.y + "Big": + var points: Array = $BigCollision.polygon + points.sort_custom(func(a, b): return a.y < b.y) + $BlockCollision.position.y = points.front().y * $BigCollision.scale.y if velocity.y <= FALL_GRAVITY: for i in $BlockCollision.get_overlapping_bodies(): if i is Block: @@ -487,19 +495,15 @@ func handle_directions() -> void: var use_big_collision := false func handle_power_up_states(delta) -> void: - var small_crouch := power_state.hitbox_size == "Small" and crouching - var big_crouch := power_state.hitbox_size == "Big" and crouching for i in get_tree().get_nodes_in_group("SmallCollisions"): - if i.name.begins_with("SmallCrouch"): - i.set_deferred("disabled", power_state.hitbox_size == "Small" and !crouching or power_state.hitbox_size == "Big") - i.visible = not i.disabled - else: - i.set_deferred("disabled", small_crouch or power_state.hitbox_size == "Big" and !crouching) - i.visible = not i.disabled - for i in get_tree().get_nodes_in_group("BigCollisions"): - i.set_deferred("disabled", power_state.hitbox_size == "Small" or big_crouch) + i.disabled = power_state.hitbox_size != "Small" i.visible = not i.disabled - $Checkpoint.position.y = -20 if small_crouch else -24 if power_state.hitbox_size == "Small" or big_crouch else -40 + i.crouching = crouching + for i in get_tree().get_nodes_in_group("BigCollisions"): + i.disabled = power_state.hitbox_size != "Big" + i.visible = not i.disabled + i.crouching = crouching + $Checkpoint.position.y = -24 if power_state.hitbox_size == "Small" else -40 power_state.update(delta) func handle_wing_flight(delta: float) -> void: