diff --git a/entities/player/mario/mario.tscn b/entities/player/mario/mario.tscn index 2cdec33b..84a56f2d 100644 --- a/entities/player/mario/mario.tscn +++ b/entities/player/mario/mario.tscn @@ -440,7 +440,7 @@ animations = [{ "speed": 5.0 }] -[sub_resource type="Resource" id="Resource_nxfaa"] +[sub_resource type="Resource" id="Resource_kuq6s"] resource_local_to_scene = true script = ExtResource("23_bbld7") doll_path = NodePath("Doll") @@ -450,19 +450,18 @@ frame_offsets = Dictionary[int, Vector2i]({ 0: Vector2i(0, 0) }) frame_fludd = Dictionary[int, String]({ -0: "rot_y090", -1: "rot_y090" +0: "default" }) frame_fludd_offsets = Dictionary[int, Vector2i]({ -0: Vector2i(1, 1), -1: Vector2i(1, 2) +0: Vector2i(0, 6), +1: Vector2i(0, 7) }) -animation = "die" +animation = "butt_slide_forwards" frame = 0 preview = false frame_offset = Vector2i(0, 0) -fludd_animation = "rot_y090" -fludd_offset = Vector2i(1, 1) +fludd_animation = "default" +fludd_offset = Vector2i(0, 6) metadata/_custom_type_script = "uid://cb4g1yl24gj7m" [sub_resource type="AtlasTexture" id="AtlasTexture_f3xbj"] @@ -1774,15 +1773,15 @@ frame_fludd = Dictionary[int, String]({ 0: "default" }) frame_fludd_offsets = Dictionary[int, Vector2i]({ -0: Vector2i(0, 5), -1: Vector2i(0, 6) +0: Vector2i(0, 6), +1: Vector2i(0, 7) }) animation = "butt_slide_jump" frame = 0 preview = false frame_offset = Vector2i(0, 3) fludd_animation = "default" -fludd_offset = Vector2i(0, 5) +fludd_offset = Vector2i(0, 6) metadata/_custom_type_script = "uid://cb4g1yl24gj7m" [sub_resource type="Resource" id="Resource_jo8kb"] @@ -2306,6 +2305,76 @@ overwrite_other = false cutoff_sfx = false metadata/_custom_type_script = "uid://dvlt5sb8enmu8" +[sub_resource type="Resource" id="Resource_msjg8"] +resource_local_to_scene = true +script = ExtResource("23_bbld7") +doll_path = NodePath("Doll") +fludd_f_path = NodePath("FluddInfront") +fludd_b_path = NodePath("FluddBehind") +frame_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 0) +}) +frame_fludd_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 6), +1: Vector2i(0, 7) +}) +animation = "butt_slide" +frame = 0 +preview = false +frame_offset = Vector2i(0, 0) +fludd_animation = "default" +fludd_offset = Vector2i(0, 6) +metadata/_custom_type_script = "uid://cb4g1yl24gj7m" + +[sub_resource type="Resource" id="Resource_rev7q"] +resource_local_to_scene = true +script = ExtResource("23_bbld7") +doll_path = NodePath("Doll") +fludd_f_path = NodePath("FluddInfront") +fludd_b_path = NodePath("FluddBehind") +frame_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 0) +}) +frame_fludd = Dictionary[int, String]({ +0: "default" +}) +frame_fludd_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 6), +1: Vector2i(0, 7) +}) +animation = "butt_slide_backwards" +frame = 0 +preview = false +frame_offset = Vector2i(0, 0) +fludd_animation = "default" +fludd_offset = Vector2i(0, 6) +metadata/_custom_type_script = "uid://cb4g1yl24gj7m" + +[sub_resource type="Resource" id="Resource_ddfva"] +resource_local_to_scene = true +script = ExtResource("23_bbld7") +doll_path = NodePath("Doll") +fludd_f_path = NodePath("FluddInfront") +fludd_b_path = NodePath("FluddBehind") +frame_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 3), +1: Vector2i(0, 3) +}) +frame_fludd = Dictionary[int, String]({ +0: "default" +}) +frame_fludd_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 6), +1: Vector2i(0, 7) +}) +animation = "butt_slide_jump" +frame = 0 +preview = false +frame_offset = Vector2i(0, 3) +fludd_animation = "default" +fludd_offset = Vector2i(0, 6) +metadata/_custom_type_script = "uid://cb4g1yl24gj7m" + [sub_resource type="Resource" id="Resource_ifrah"] resource_local_to_scene = true script = ExtResource("23_bbld7") @@ -2403,6 +2472,31 @@ fludd_animation = "default" fludd_offset = Vector2i(0, 0) metadata/_custom_type_script = "uid://cb4g1yl24gj7m" +[sub_resource type="Resource" id="Resource_nxfaa"] +resource_local_to_scene = true +script = ExtResource("23_bbld7") +doll_path = NodePath("Doll") +fludd_f_path = NodePath("FluddInfront") +fludd_b_path = NodePath("FluddBehind") +frame_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(0, 0) +}) +frame_fludd = Dictionary[int, String]({ +0: "rot_y090", +1: "rot_y090" +}) +frame_fludd_offsets = Dictionary[int, Vector2i]({ +0: Vector2i(1, 1), +1: Vector2i(1, 2) +}) +animation = "die" +frame = 0 +preview = false +frame_offset = Vector2i(0, 0) +fludd_animation = "rot_y090" +fludd_offset = Vector2i(1, 1) +metadata/_custom_type_script = "uid://cb4g1yl24gj7m" + [sub_resource type="Resource" id="Resource_cux1t"] script = ExtResource("49_apkmk") sfx_list = [ExtResource("152_2h0ab")] @@ -2448,19 +2542,17 @@ offset_bottom = -33.0 visible = false position = Vector2(0, -24) sprite_frames = SubResource("SpriteFrames_e1ut2") -animation = &"rot_y090" [node name="Doll" type="AnimatedSprite2D" parent="." unique_id=1876045562] position = Vector2(0, -24) sprite_frames = ExtResource("4_xenv0") -animation = &"die" -metadata/last_previewed = SubResource("Resource_nxfaa") +animation = &"butt_slide_forwards" +metadata/last_previewed = SubResource("Resource_kuq6s") [node name="FluddInfront" type="AnimatedSprite2D" parent="." unique_id=1928286412] visible = false position = Vector2(0, -24) sprite_frames = SubResource("SpriteFrames_1i10v") -animation = &"rot_y090" [node name="Hitbox" type="CollisionShape2D" parent="." unique_id=76578262] position = Vector2(0, -15) @@ -2604,7 +2696,6 @@ max_speed = 180.0 term_vel = 480.0 min_grav = 774.0 max_grav = 792.0 -snap_length = 8.0 swim_speed = 180.0 min_slide_incline = 0.4 @@ -2981,18 +3072,17 @@ sfx_layers = Array[ExtResource("49_apkmk")]([SubResource("Resource_ujdp5"), SubR [node name="ButtSlide" type="Node" parent="StateManager/Dry" unique_id=720337721] script = ExtResource("140_lfmwr") -speed = 750.0 -min_speed = 300.0 -max_speed = 1200.0 +friction_coefficient_default = 0.3 +friction_coefficient_overspeed = 1.4 +accel_gravity_multiplier = 1.5 +max_speed_decel = 150.0 +max_speed = 300.0 +max_speed_accel = 500.0 min_remain_speed = 6.0 -friction = 7.5 -max_accel = 13.2 -turn_forgiveness = 1.5 -shallow_penalty = 0.25 -incline_friction = 90.0 -animation_forward = &"butt_slide_forwards" -animation_backward = &"butt_slide_backwards" -animation_airborne = &"butt_slide_jump" +default_animation_data = SubResource("Resource_msjg8") +forward_animation_data = SubResource("Resource_kuq6s") +backward_animation_data = SubResource("Resource_rev7q") +airborne_animation_data = SubResource("Resource_ddfva") hitbox_type = "Small" animation_data = SubResource("Resource_ifrah") particles = Array[ExtResource("55_bxnxc")]([SubResource("Resource_d3rr6")]) diff --git a/entities/player/shared/player_movement.gd b/entities/player/shared/player_movement.gd index 41fbea1e..a250dfb2 100644 --- a/entities/player/shared/player_movement.gd +++ b/entities/player/shared/player_movement.gd @@ -48,8 +48,6 @@ var return_timer: float ## Amount of units the player needs to be above the ground to perform an airborne action. @export var air_margin: int = 10 -## Sets the floor_snap_length of the actor. -@export var snap_length: float = 16 ## The y position of the point you walljumped from. ## Used to avoid being able to scale a wall infinitely. diff --git a/entities/player/shared/states/dry/airborne/airborne.gd b/entities/player/shared/states/dry/airborne/airborne.gd index a794bac7..63e449df 100644 --- a/entities/player/shared/states/dry/airborne/airborne.gd +++ b/entities/player/shared/states/dry/airborne/airborne.gd @@ -4,8 +4,6 @@ extends PlayerState func _physics_tick(_delta: float): - actor.set_floor_snap_length(0.0) - actor.stomp_hurtbox.monitoring = actor.velocity.y > 0 if actor.is_on_ceiling() and actor.velocity.y < 0 and not live_substate is GroundPound: diff --git a/entities/player/shared/states/dry/butt_slide.gd b/entities/player/shared/states/dry/butt_slide.gd index 453b990b..4af5f5f2 100644 --- a/entities/player/shared/states/dry/butt_slide.gd +++ b/entities/player/shared/states/dry/butt_slide.gd @@ -1,73 +1,59 @@ class_name ButtSlide extends PlayerState -## Crouching while on a slope (or being forced.) - -## Default sliding speed. -@export var speed: float = 10 -## Minimum sliding speed (through decelerating by holding the opposite direction you're sliding in.) -@export var min_speed: float = 5 -## Maximum sliding speed (through accelerating by holding the direction you're sliding in.) -@export var max_speed: float = 20 -## Minimum sliding speed necessary to remain in a buttslide state. -## (In practice: how much you'll be sliding on flat ground after sliding off a slope.) -@export var min_remain_speed: float = 0.1 - -## Friction applied when sliding along flat or shallow ground. -@export var friction: float = 0.125 - -## Maximum acceleration from sliding, when a slope is as steep as possible. -@export var max_accel: float = 0.22 - -## How much speed is lost when changing slope angle. -## Higher turn forgiveness means more speed is lost. -@export_exp_easing() var turn_forgiveness: float = 2.0 - -## Higher shallowness penalty means shallow slopes will decrease speed more. -@export_exp_easing() var shallow_penalty: float = 0.5 -## Higher friction means less speed conservation on steep slopes. -@export_exp_easing() var incline_friction: float = 10.0 +## Crouching while on a slope. + +## See [member CharacterBody2D.floor_snap_length]. +@export var floor_snap_length: float = 32.0 +## The default frictional coefficient +@export var friction_coefficient_default: float +## The frictional coefficient when over the maximum speed. +@export var friction_coefficient_overspeed: float +## The gravity multiplier when holding the direction you're sliding in. +@export var accel_gravity_multiplier: float + +## How quickly you can slide when decelerating. +@export var max_speed_decel: float +## How quickly you can slide when not accelerating or decelerating. +@export var max_speed: float +## How quickly you can slide when accelerating. +@export var max_speed_accel: float + +## How much speed the [Player] needs to remain in a sliding state. +@export var min_remain_speed: float @export_category(&"Animation (Unique to State)") -@export var animation_forward: StringName -@export var anim_offset_f: Vector2 -@export var animation_backward: StringName -@export var anim_offset_b: Vector2 -@export var animation_airborne: StringName -@export var anim_offset_a: Vector2 - -## Speed at which the player slides. -var slide_speed: float = 0.0 - -## Stored previous direction, for changing slope angle. -var old_direction: Vector2 - -## True when the player does not have a slide direction yet. -var no_direction: bool - -var input_dir: int +## Animation used by default. +@export var default_animation_data: PStateAnimData +## Animation used when holding downhill. +@export var forward_animation_data: PStateAnimData +## Animation used when holding uphill. +@export var backward_animation_data: PStateAnimData +## Animation used when sliding off a ledge. +## Not to be confused with [ButtSlideJump]. +@export var airborne_animation_data: PStateAnimData func _on_enter(handover_speed): - actor.set_floor_snap_length(movement.snap_length) + actor.set_floor_snap_length(floor_snap_length) + # Convert vertical speed from ground pounding into sliding speed if handover_speed is float: - old_direction = Vector2.DOWN - slide_speed = handover_speed - else: - no_direction = true - slide_speed = 0 + actor.velocity = (Vector2.DOWN * handover_speed).slide(actor.get_floor_normal()) func _physics_tick(delta: float): + # Apply physics if actor.is_on_floor(): _grounded(delta) else: _airborne(delta) - + + # Set animations _set_appropriate_anim() func _subsequent_ticks(_delta: float): + # Emit particles and play sound effects if actor.is_on_floor(): particles[0].emit_at(actor) @@ -79,168 +65,85 @@ func _subsequent_ticks(_delta: float): ## Buttsliding on the ground / slope. func _grounded(delta: float): - var floor_normal: Vector2 = actor.get_floor_normal() - - var slide_direction: Vector2 - - slide_direction = _get_slide_dir(floor_normal) - input_dir = InputManager.get_x_dir() - - if no_direction: - _apply_slide_direction(floor_normal, slide_direction) + # Equal to 1 if accelerating, -1 if decelerating, 0 otherwise. + var accel_dir: int = InputManager.get_x_dir() * sign(actor.velocity.x) + + var slide_accel: float + var speed_limit: float + var friction: float = friction_coefficient_default + var overspeed_friction: float = friction_coefficient_overspeed + match accel_dir: + -1: # decelerating + slide_accel = movement.max_grav + speed_limit = max_speed_decel + 0: # not holding a direction + slide_accel = movement.max_grav + speed_limit = max_speed + 1: # accelerating + slide_accel = movement.max_grav * accel_gravity_multiplier + speed_limit = max_speed_accel + + # Apply gravity + actor.velocity += Vector2.DOWN.slide(actor.get_floor_normal()) * slide_accel * delta + + # Calculate normal acceleration + var normal_accel = Vector2.UP.dot(actor.get_floor_normal()) * slide_accel + + # Check if under the speed limit: + if actor.velocity.length() <= speed_limit: + # If yes, apply regular friction + actor.velocity = actor.velocity.move_toward(Vector2.ZERO, friction * normal_accel * delta) else: - # If we're changing direction, redirect current sliding speed into the new direction - if not slide_direction.is_equal_approx(old_direction): - _redirect_slide(slide_direction, old_direction) - - # Modify slide_speed prior to setting velocity - _modify_speed(floor_normal) - - actor.velocity = slide_direction * slide_speed - actor.velocity.y += 6.0 * delta - - # Store the sliding direction so we can check for changes - old_direction = slide_direction + # If no, apply overspeed friction. Speed should not go below the speed limit. + actor.velocity = actor.velocity.move_toward(actor.velocity.limit_length(speed_limit), + overspeed_friction * normal_accel * delta) ## Buttsliding in the air. func _airborne(delta: float): - no_direction = true - slide_speed = 0 - movement.apply_gravity(delta) -## Get the slide direction downwards along the slope. -func _get_slide_dir(floor_normal: Vector2) -> Vector2: - var direction: Vector2 - - if floor_normal == Vector2.UP: - # On flat ground, just go right. - direction = Vector2.RIGHT - else: - direction = floor_normal.orthogonal() - - if direction.dot(Vector2.DOWN) < 0: - direction = -direction - - return direction - - -## Integrate current velocity and direction to a slide. -func _apply_slide_direction(floor_normal: Vector2, slide_direction: Vector2): - # If we have only just started sliding, - # we need to convert the player's velocity into sliding speed. - if floor_normal == Vector2.UP: - slide_speed = actor.velocity.x - else: - if abs(actor.velocity.x) > abs(actor.velocity.dot(slide_direction)): - slide_speed = actor.velocity.x * sign(floor_normal.x) - else: - slide_speed = actor.velocity.dot(slide_direction) - - no_direction = false - - -## Calculates acceleration, deceleration, and target speed; then applies them. -func _modify_speed(floor_normal: Vector2): - # How flat the floor is, 0-1 - var flatness: float = floor_normal.dot(Vector2.UP) - # How steep the floor is (opposite of flatness, just for convenience) - var steepness: float = 1 - flatness - var slope_dir: int = sign(floor_normal.x) - - var accel_ease: float = ease(steepness, shallow_penalty) - - var slide_accel: float = accel_ease * max_accel - var slide_decel: float = ease(flatness, incline_friction) * friction - - var target_speed: float = accel_ease * speed - - if input_dir != 0: - # Holding the direction of the slope (accel) - if input_dir == slope_dir: - target_speed = accel_ease * max_speed - # Holding the opposite direction of the slope (decel) - elif input_dir == -slope_dir: - target_speed = accel_ease * min_speed - - slide_decel = max(slide_decel, 6.0) - - # Accelerate down the slope - _accelerate(slide_accel, target_speed) - # Decelerate due to friction - _decelerate(slide_decel, target_speed) - - -func _redirect_slide(new: Vector2, old: Vector2): - # Calculate how similar the new direction is to the old direction - var preserved = new.dot(old) - - # Store the sign: -1 if we have moved from an upward slope to a downward slope - # or vice versa - var new_sign = sign(preserved) - - # Take absolute value so we can work with 0 to 1 instead of -1 to 1 - preserved = abs(preserved) - - # Calculate how much speed would be lost - var lost = 1 - preserved - # Apply forgiveness to what was lost - var lost_forgiven = ease(lost, turn_forgiveness) - - # Subtract the reduced loss from 1 - var final_preserved = 1 - lost_forgiven - - slide_speed *= final_preserved * new_sign - - -func _accelerate(amount: Variant, speed_cap: float): - if slide_speed + amount < speed_cap: - slide_speed += amount - elif slide_speed < speed_cap: - slide_speed = speed_cap - - -func _decelerate(amount: float, target: float): - var direction = sign(slide_speed) - var abs_speed = abs(slide_speed) - - if abs_speed > target: - abs_speed = max(abs_speed - amount, target) - - slide_speed = abs_speed * direction - - ## Set the animation based on how you're moving on a slope. func _set_appropriate_anim(): + # Play airborne animation if not on floor if not actor.is_on_floor(): - actor.doll.play(animation_airborne) - return - if input_dir != 0: - actor.doll.play( - animation_forward if input_dir == movement.facing_direction else animation_backward - ) + overwrite_animation(airborne_animation_data) return - actor.doll.play(animation_data.animation) + + var x_dir := InputManager.get_x_dir() + + # Play forwards animation when moving in the same direction as the slide + if x_dir == movement.facing_direction: + overwrite_animation(forward_animation_data) + # Play backwards animation when moving in opposite direction as the slide + elif x_dir == -movement.facing_direction: + overwrite_animation(backward_animation_data) + # Play normal slide animation + else: + overwrite_animation(default_animation_data) func _trans_rules(): + # When slow enough on flat ground, exit the sliding state. if not movement.is_slide_slope() and abs(actor.velocity.x) < min_remain_speed: - return [&"Crouch", [true, false]] + if Input.is_action_pressed(&"down"): + return [&"Crouch", [true, false]] + else: + return &"Idle" - if not Input.is_action_pressed(&"down"): + # Exit the sliding state when up is pressed. + if input.buffered_input(&"up"): if actor.is_on_floor(): - if old_direction.y == 0 and input_dir != 0 or Input.is_action_just_pressed(&"up"): - return &"Idle" - if input_dir == -sign(old_direction.x): - return &"Walk" + return &"Idle" else: return &"Fall" + # Jump out of a buttslide: if actor.is_on_floor() and input.buffered_input(&"jump"): return &"ButtSlideJump" + # Spin out of a buttslide: if input.buffered_input(&"spin"): return &"Spin" diff --git a/entities/player/shared/states/dry/dive_states/dive.gd b/entities/player/shared/states/dry/dive_states/dive.gd index 4337a6cc..fe9bb18e 100644 --- a/entities/player/shared/states/dry/dive_states/dive.gd +++ b/entities/player/shared/states/dry/dive_states/dive.gd @@ -25,7 +25,6 @@ func _on_enter(dive_direction): movement.consec_jumps = 0 movement.dived = true - actor.set_floor_snap_length(movement.snap_length) actor.dive_hurtbox.monitoring = true if actor.is_on_floor(): diff --git a/entities/player/shared/states/dry/grounded/grounded.gd b/entities/player/shared/states/dry/grounded/grounded.gd index afc0176f..a47d1c24 100644 --- a/entities/player/shared/states/dry/grounded/grounded.gd +++ b/entities/player/shared/states/dry/grounded/grounded.gd @@ -9,8 +9,6 @@ func _on_enter(play_land_sfx): movement.air_spun = false movement.dived = false - actor.set_floor_snap_length(movement.snap_length) - if play_land_sfx: # Normal footsteps sfx_layers[0].play_sfx_at(self)