mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-12-06 03:30:22 -08:00
Small patch time. There were a few glaring issues with the classic physics accuracy before. This commit tries to fix the majority of those issues. - "Bounce Jump Speed" is changed from 248.0 -> 310.0. The reason for this is from a community poll which suggested that Bounce Speed be changed. - Due to how close the NES version was, I decided to only change "Bounce Jump Speed" meaning that classic physics technically will have both the NES and All-Stars bounce speeds, just depending on if you hold A or not. I think it feels nice this way and will do fine for now as a compromise until CharacterInfo variations can be implemented. - Fixes: - Projectile and Particle file paths in the default POWER_PARAMS for Fire have been updated and should no longer cause issues with characters that don't set them. - You can no longer stand on the lip of the pipe in 1-2 that allows you to access the minus world. - Accuracy changes: - Classic Physics "Ground Decel" lowered from 3.05 to 2.23, which matches closer to the original game's deceleration. - New parameter "Minimum Speed" which determines the minimum speed value the player can travel at when attempting to move. - New parameter "Run Stop Buffer" which determines how much time in seconds the player will continue running for if they - New parameter "Clamp Ground Speed" which clamps the player's movement speed based on their current target speed like the original SMB (i.e. if you run and jump while moving in the original, and let go of run, your character upon landing will instantly revert to max walking speed.) - New parameter "Can Run Accel Early" which allows the player to gain running acceleration and speed without needing to be at walk speed like the original SMB. - New parameter "Control Run Air Accel" for disabling the ability for the player to control their air speed once reaching running speed like the original SMB. - New parameter "Classic Skid Conditions" which attempts to replicate the same conditions required in the original SMB to start skidding. (This one needs more work, it isn't too accurate as of yet...)
353 lines
14 KiB
GDScript
353 lines
14 KiB
GDScript
extends PlayerState
|
|
|
|
var swim_up_meter := 0.0
|
|
|
|
var jump_queued := false
|
|
|
|
var jump_buffer := 0
|
|
|
|
var run_buffer := 0
|
|
|
|
var walk_frame := 0
|
|
|
|
var bubble_meter := 0.0
|
|
|
|
var wall_pushing := false
|
|
|
|
var can_wall_push := false
|
|
|
|
func enter(_msg := {}) -> void:
|
|
jump_queued = false
|
|
|
|
func physics_update(delta: float) -> void:
|
|
if player.is_actually_on_floor():
|
|
grounded(delta)
|
|
else:
|
|
in_air()
|
|
handle_movement(delta)
|
|
handle_animations()
|
|
handle_death_pits()
|
|
|
|
func handle_death_pits() -> void:
|
|
if player.global_position.y > 64 and not Level.in_vine_level and player.auto_death_pit and player.gravity_vector == Vector2.DOWN:
|
|
player.die(true)
|
|
elif player.global_position.y < Global.current_level.vertical_height - 32 and player.gravity_vector == Vector2.UP:
|
|
player.die(true)
|
|
|
|
func handle_movement(delta: float) -> void:
|
|
jump_buffer -= 1
|
|
run_buffer -= 1
|
|
if jump_buffer <= 0:
|
|
jump_queued = false
|
|
if Global.player_action_pressed("run", player.player_id):
|
|
run_buffer = player.physics_params("RUN_STOP_BUFFER") / delta
|
|
player.apply_gravity(delta)
|
|
if player.is_actually_on_floor():
|
|
var player_transform = player.global_transform
|
|
player_transform.origin += Vector2.UP * 1
|
|
if player.is_actually_on_floor():
|
|
handle_ground_movement(delta)
|
|
elif player.in_water or player.flight_meter > 0:
|
|
handle_swimming(delta)
|
|
else:
|
|
handle_air_movement(delta)
|
|
player.move_and_slide()
|
|
player.moved.emit()
|
|
|
|
func grounded(delta: float) -> void:
|
|
player.jump_cancelled = false
|
|
if player.velocity.y >= 0:
|
|
player.has_jumped = false
|
|
player.has_spring_jumped = false
|
|
if Global.player_action_just_pressed("jump", player.player_id):
|
|
player.handle_water_detection()
|
|
if player.in_water or player.flight_meter > 0:
|
|
swim_up()
|
|
return
|
|
else:
|
|
player.jump()
|
|
if jump_queued and not (player.in_water or player.flight_meter > 0):
|
|
if player.spring_bouncing == false:
|
|
player.jump()
|
|
jump_queued = false
|
|
if not player.crouching:
|
|
if Global.player_action_pressed("move_down", player.player_id):
|
|
player.crouching = true
|
|
AudioManager.play_sfx("crouch", player.global_position)
|
|
AudioManager.kill_sfx("uncrouch")
|
|
else:
|
|
can_wall_push = player.test_move(player.global_transform, Vector2.UP * 8 * player.gravity_vector.y) and player.physics_params("CAN_BE_WALL_EJECTED")
|
|
if Global.player_action_pressed("move_down", player.player_id) == false:
|
|
if can_wall_push:
|
|
wall_pushing = true
|
|
else:
|
|
wall_pushing = false
|
|
player.crouching = false
|
|
AudioManager.play_sfx("uncrouch", player.global_position)
|
|
AudioManager.kill_sfx("crouch")
|
|
else:
|
|
player.crouching = true
|
|
wall_pushing = false
|
|
if wall_pushing:
|
|
player.global_position.x += (-50 * player.direction * delta)
|
|
if not player.looking_up:
|
|
if Global.player_action_pressed("move_up", player.player_id) and not player.crouching:
|
|
player.looking_up = true
|
|
AudioManager.play_sfx("look_up", player.global_position)
|
|
AudioManager.kill_sfx("stop_look_up")
|
|
else:
|
|
if not Global.player_action_pressed("move_up", player.player_id) and not player.crouching:
|
|
player.looking_up = false
|
|
AudioManager.play_sfx("stop_look_up", player.global_position)
|
|
AudioManager.kill_sfx("look_up")
|
|
|
|
func handle_ground_movement(delta: float) -> void:
|
|
var skid_conditions = sign(player.input_direction * player.velocity_direction) < 0.0 and abs(player.velocity.x) > player.physics_params("SKID_THRESHOLD") if not player.physics_params("CLASSIC_SKID_CONDITIONS") else sign(player.direction * player.velocity_direction) < 0.0
|
|
if player.skidding:
|
|
ground_skid(delta)
|
|
elif not player.crouching and skid_conditions:
|
|
player.skidding = true # TODO: player skids regardless of current input direction, add it as a param
|
|
elif player.input_direction != 0 and not player.crouching:
|
|
ground_acceleration(delta)
|
|
else:
|
|
deceleration(delta)
|
|
|
|
func ground_acceleration(delta: float) -> void:
|
|
var target_move_speed: float = player.physics_params("WALK_SPEED")
|
|
if player.in_water or player.flight_meter > 0:
|
|
target_move_speed = player.physics_params("SWIM_GROUND_SPEED")
|
|
var target_accel: float = player.physics_params("GROUND_WALK_ACCEL")
|
|
var walk_speed_requirement = abs(player.velocity.x) >= player.physics_params("WALK_SPEED") if not player.physics_params("CAN_RUN_ACCEL_EARLY") else true
|
|
if ((Global.player_action_pressed("run", player.player_id) or run_buffer > 0) and walk_speed_requirement) and (not player.in_water and player.flight_meter <= 0) and player.can_run:
|
|
target_move_speed = player.physics_params("RUN_SPEED")
|
|
target_accel = player.physics_params("GROUND_RUN_ACCEL")
|
|
if player.input_direction != player.velocity_direction:
|
|
if Global.player_action_pressed("run", player.player_id) and player.can_run:
|
|
target_accel = player.physics_params("RUN_SKID")
|
|
else:
|
|
target_accel = player.physics_params("WALK_SKID")
|
|
var clamp_values = [-target_move_speed, target_move_speed] if player.physics_params("CLAMP_GROUND_SPEED") else [-INF, INF]
|
|
player.velocity.x = clamp(move_toward(player.velocity.x, target_move_speed * player.input_direction, (target_accel / delta) * delta), clamp_values[0], clamp_values[1])
|
|
if abs(player.velocity.x) < player.physics_params("MINIMUM_SPEED"):
|
|
player.velocity.x = player.physics_params("MINIMUM_SPEED") * player.input_direction
|
|
|
|
func deceleration(delta: float, airborne := false) -> void:
|
|
var decel_type = player.physics_params("GROUND_DECEL") if not airborne else player.physics_params("AIR_DECEL")
|
|
if player.in_water: decel_type = player.physics_params("SWIM_DECEL")
|
|
player.velocity.x = move_toward(player.velocity.x, 0, (decel_type / delta) * delta)
|
|
|
|
func ground_skid(delta: float) -> void:
|
|
var target_skid: float = player.physics_params("RUN_SKID") if Global.player_action_pressed("run", player.player_id) and player.can_run else player.physics_params("WALK_SKID")
|
|
player.skid_frames += 1
|
|
player.velocity.x = move_toward(player.velocity.x, 1 * player.input_direction, (target_skid / delta) * delta)
|
|
if abs(player.velocity.x) < player.physics_params("SKID_STOP_THRESHOLD") or sign(player.input_direction * player.velocity_direction) > 0:
|
|
player.skidding = false
|
|
player.skid_frames = 0
|
|
if abs(player.velocity.x) < player.physics_params("SKID_STOP_THRESHOLD") and player.physics_params("CAN_INSTANT_STOP_SKID"):
|
|
player.velocity.x = 0
|
|
|
|
func in_air() -> void:
|
|
if Global.player_action_just_pressed("jump", player.player_id):
|
|
if player.in_water or player.flight_meter > 0:
|
|
swim_up()
|
|
else:
|
|
jump_queued = true
|
|
jump_buffer = 4
|
|
|
|
func handle_air_movement(delta: float) -> void:
|
|
if player.input_direction != 0 and player.velocity_direction != player.input_direction:
|
|
air_skid(delta)
|
|
elif player.input_direction != 0:
|
|
air_acceleration(delta)
|
|
else:
|
|
deceleration(delta, true)
|
|
|
|
if Global.player_action_pressed("jump", player.player_id) == false and player.has_jumped and not player.jump_cancelled:
|
|
player.jump_cancelled = true
|
|
if sign(player.gravity_vector.y * player.velocity.y) < 0.0:
|
|
player.velocity.y /= player.physics_params("JUMP_CANCEL_DIVIDE")
|
|
player.gravity = player.calculate_speed_param("FALL_GRAVITY")
|
|
|
|
func air_acceleration(delta: float) -> void:
|
|
var backwards_accel = 1
|
|
if sign(player.velocity.x * player.direction) < 0.0:
|
|
backwards_accel = player.physics_params("AIR_BACKWARDS_ACCEL_MULT")
|
|
elif sign(player.input_direction * player.direction) < 0.0:
|
|
backwards_accel = 1 / player.physics_params("AIR_BACKWARDS_ACCEL_MULT")
|
|
var target_speed = player.physics_params("WALK_SPEED")
|
|
var target_accel = player.physics_params("AIR_WALK_ACCEL") * backwards_accel
|
|
var lock_air_speed = (abs(player.velocity.x) > player.physics_params("WALK_SPEED") or player.has_spring_jumped) if player.physics_params("LOCK_AIR_ACCEL") else abs(player.velocity.x) >= player.physics_params("WALK_SPEED")
|
|
var air_accel_control = Global.player_action_pressed("run", player.player_id) and player.can_run if player.physics_params("CONTROL_RUN_AIR_ACCEL") else true
|
|
if lock_air_speed and air_accel_control:
|
|
target_speed = player.physics_params("RUN_SPEED")
|
|
target_accel = player.physics_params("AIR_RUN_ACCEL") * backwards_accel
|
|
if not player.physics_params("CAN_BACKWARDS_ACCEL_RUN") and sign(player.velocity.x * player.direction) < 0.0:
|
|
target_accel = player.physics_params("AIR_WALK_ACCEL") * backwards_accel
|
|
player.velocity.x = move_toward(player.velocity.x, target_speed * player.input_direction, (target_accel / delta) * delta)
|
|
|
|
func air_skid(delta: float) -> void:
|
|
var backwards_accel = 1
|
|
if sign(player.velocity.x * player.direction) < 0.0:
|
|
backwards_accel = player.physics_params("AIR_BACKWARDS_ACCEL_MULT")
|
|
elif sign(player.input_direction * player.direction) < 0.0:
|
|
backwards_accel = 1 / player.physics_params("AIR_BACKWARDS_ACCEL_MULT")
|
|
var target_speed = player.physics_params("WALK_SPEED")
|
|
var target_accel = player.physics_params("AIR_SKID") * backwards_accel
|
|
var lock_air_speed = (abs(player.velocity.x) > player.physics_params("WALK_SPEED") or player.has_spring_jumped) if player.physics_params("LOCK_AIR_ACCEL") else abs(player.velocity.x) >= player.physics_params("WALK_SPEED")
|
|
var air_accel_control = Global.player_action_pressed("run", player.player_id) and player.can_run if player.physics_params("CONTROL_RUN_AIR_ACCEL") else true
|
|
if lock_air_speed and air_accel_control:
|
|
target_speed = player.physics_params("RUN_SPEED")
|
|
target_accel = player.physics_params("AIR_SKID") * backwards_accel
|
|
if not player.physics_params("CAN_BACKWARDS_ACCEL_RUN") and sign(player.velocity.x * player.direction) < 0.0:
|
|
target_accel = player.physics_params("AIR_SKID") * backwards_accel
|
|
player.velocity.x = move_toward(player.velocity.x, target_speed * player.input_direction, (target_accel / delta) * delta)
|
|
|
|
func handle_swimming(delta: float) -> void:
|
|
bubble_meter += delta
|
|
if bubble_meter >= 1 and player.flight_meter <= 0:
|
|
player.summon_bubble()
|
|
bubble_meter = 0
|
|
swim_up_meter -= delta
|
|
player.skidding = (player.input_direction != player.velocity_direction) and player.input_direction != 0 and abs(player.velocity.x) > 100 and not player.crouching
|
|
if player.skidding:
|
|
ground_skid(delta)
|
|
elif player.input_direction != 0 and not player.crouching:
|
|
swim_acceleration(delta)
|
|
else:
|
|
deceleration(delta)
|
|
|
|
func swim_acceleration(delta: float) -> void:
|
|
player.velocity.x = move_toward(player.velocity.x, player.physics_params("SWIM_SPEED") * player.input_direction, (player.physics_params("GROUND_WALK_ACCEL") / delta) * delta)
|
|
|
|
func swim_up() -> void:
|
|
if player.swim_stroke:
|
|
player.play_animation("SwimIdle")
|
|
player.velocity.y = -player.physics_params("SWIM_HEIGHT") * player.gravity_vector.y
|
|
AudioManager.play_sfx("swim", player.global_position)
|
|
swim_up_meter = 0.5
|
|
player.crouching = false
|
|
|
|
func handle_animations() -> void:
|
|
if (player.is_actually_on_floor() or player.in_water or player.flight_meter > 0 or player.physics_params("CAN_AIR_TURN")) and player.input_direction != 0 and not player.crouching:
|
|
player.direction = player.input_direction
|
|
var animation = get_animation_name()
|
|
player.sprite.speed_scale = 1
|
|
if ["Walk", "Move", "Run"].has(animation):
|
|
player.sprite.speed_scale = abs(player.velocity.x) / player.physics_params("MOVE_ANIM_SPEED_DIV", player.COSMETIC_PARAMETERS)
|
|
player.play_animation(animation)
|
|
if player.sprite.animation == "Move":
|
|
walk_frame = player.sprite.frame
|
|
player.sprite.scale.x = player.direction * player.gravity_vector.y
|
|
|
|
func get_animation_name() -> String:
|
|
# SkyanUltra: Simplified animation table and optimized nesting.
|
|
var vel_x: float = abs(player.velocity.x)
|
|
var vel_y : float = player.actual_velocity_y()
|
|
var on_floor := player.is_actually_on_floor()
|
|
var on_wall := player.is_actually_on_wall()
|
|
var airborne := not on_floor
|
|
var has_flight := player.has_wings
|
|
var moving := vel_x >= 5 and not on_wall
|
|
var pushing := player.input_direction != 0 and on_wall
|
|
var running: float = vel_x >= player.physics_params("RUN_SPEED") - 10
|
|
var run_jump: bool = abs(player.velocity_x_jump_stored) >= player.physics_params("RUN_SPEED") - 10
|
|
|
|
var state_context := ""
|
|
if player.in_water: state_context = "Water"
|
|
elif has_flight: state_context = "Wing"
|
|
|
|
var state = func(anim_name: String) -> String:
|
|
return state_context + anim_name
|
|
|
|
var jump_context := ""
|
|
if player.has_spring_jumped: jump_context = "Spring"
|
|
elif player.has_star: jump_context = "Star"
|
|
elif run_jump: jump_context = "Run"
|
|
|
|
var jump = func(anim_name: String) -> String:
|
|
return jump_context + anim_name
|
|
|
|
# --- Attack Animations ---
|
|
if player.attacking:
|
|
if player.crouching:
|
|
return "CrouchAttack"
|
|
if on_floor:
|
|
if player.skidding:
|
|
return "SkidAttack"
|
|
if moving:
|
|
if player.in_water:
|
|
return "SwimAttack"
|
|
if has_flight:
|
|
return "FlyAttack"
|
|
return "RunAttack" if running else "WalkAttack"
|
|
return "IdleAttack"
|
|
else:
|
|
if player.in_water:
|
|
return "SwimAttack"
|
|
if has_flight:
|
|
return "FlyAttack"
|
|
return "AirAttack"
|
|
|
|
# --- Kick Animation ---
|
|
if player.kicking and player.can_kick_anim:
|
|
return state.call("Kick")
|
|
|
|
# --- Crouch Animations ---
|
|
if player.crouching and not wall_pushing:
|
|
if player.bumping and player.can_bump_crouch_anim:
|
|
return "CrouchBump"
|
|
if airborne:
|
|
return "CrouchFall" if vel_y >= 0 else "CrouchJump"
|
|
if moving:
|
|
return state.call("CrouchMove")
|
|
return state.call("Crouch")
|
|
|
|
# --- Grounded Animations ---
|
|
if on_floor:
|
|
if player.spring_bouncing and player.can_spring_land_anim:
|
|
return "SpringLand"
|
|
if player.skidding:
|
|
return "Skid"
|
|
if pushing and player.can_push_anim:
|
|
return state.call("Push")
|
|
if moving:
|
|
if state_context != "":
|
|
return state.call("Move")
|
|
return "Run" if running else "Walk"
|
|
# Idle States
|
|
if player.looking_up:
|
|
return state.call("LookUp")
|
|
return state.call("Idle")
|
|
|
|
# --- Airborne Animations ---
|
|
if player.in_water:
|
|
if swim_up_meter > 0:
|
|
if player.bumping and player.can_bump_swim_anim:
|
|
return "SwimBump"
|
|
return "SwimUp"
|
|
return "SwimIdle"
|
|
|
|
if has_flight:
|
|
if swim_up_meter > 0:
|
|
if player.bumping and player.can_bump_fly_anim:
|
|
return "FlyBump"
|
|
return "FlyUp"
|
|
return "FlyIdle"
|
|
|
|
if player.has_jumped:
|
|
if player.bumping and player.can_bump_jump_anim:
|
|
return jump.call("JumpBump")
|
|
if vel_y < 0:
|
|
return jump.call("Jump")
|
|
else:
|
|
return jump.call("JumpFall")
|
|
else:
|
|
# guzlad: Fixes characters with fall anims not playing them, but also prevents old characters without that anim not being accurate
|
|
if not player.sprite.sprite_frames.has_animation("Fall"):
|
|
player.sprite.frame = walk_frame
|
|
return "Fall"
|
|
|
|
func exit() -> void:
|
|
if owner.has_hammer:
|
|
owner.on_hammer_timeout()
|
|
owner.skidding = false
|