diff --git a/assets/sounds/grass swish 1.ogg b/assets/sounds/grass swish 1.ogg new file mode 100644 index 0000000..456a6ca Binary files /dev/null and b/assets/sounds/grass swish 1.ogg differ diff --git a/assets/sounds/grass swish 1.ogg.import b/assets/sounds/grass swish 1.ogg.import new file mode 100644 index 0000000..ecb2456 --- /dev/null +++ b/assets/sounds/grass swish 1.ogg.import @@ -0,0 +1,15 @@ +[remap] + +importer="ogg_vorbis" +type="AudioStreamOGGVorbis" +path="res://.import/grass swish 1.ogg-bdbb4d7db9f101b427a7017365253335.oggstr" + +[deps] + +source_file="res://assets/sounds/grass swish 1.ogg" +dest_files=[ "res://.import/grass swish 1.ogg-bdbb4d7db9f101b427a7017365253335.oggstr" ] + +[params] + +loop=false +loop_offset=0 diff --git a/assets/sounds/grass swish 2.ogg b/assets/sounds/grass swish 2.ogg new file mode 100644 index 0000000..7a16fbc Binary files /dev/null and b/assets/sounds/grass swish 2.ogg differ diff --git a/assets/sounds/grass swish 2.ogg.import b/assets/sounds/grass swish 2.ogg.import new file mode 100644 index 0000000..c5925e8 --- /dev/null +++ b/assets/sounds/grass swish 2.ogg.import @@ -0,0 +1,15 @@ +[remap] + +importer="ogg_vorbis" +type="AudioStreamOGGVorbis" +path="res://.import/grass swish 2.ogg-beebb4d61ae20e7e1fa9a915a809817d.oggstr" + +[deps] + +source_file="res://assets/sounds/grass swish 2.ogg" +dest_files=[ "res://.import/grass swish 2.ogg-beebb4d61ae20e7e1fa9a915a809817d.oggstr" ] + +[params] + +loop=false +loop_offset=0 diff --git a/assets/sounds/grass swish 3.ogg b/assets/sounds/grass swish 3.ogg new file mode 100644 index 0000000..17d41e3 Binary files /dev/null and b/assets/sounds/grass swish 3.ogg differ diff --git a/assets/sounds/grass swish 3.ogg.import b/assets/sounds/grass swish 3.ogg.import new file mode 100644 index 0000000..43a7865 --- /dev/null +++ b/assets/sounds/grass swish 3.ogg.import @@ -0,0 +1,15 @@ +[remap] + +importer="ogg_vorbis" +type="AudioStreamOGGVorbis" +path="res://.import/grass swish 3.ogg-8d9986e80092be5e026c4d30b38c8a68.oggstr" + +[deps] + +source_file="res://assets/sounds/grass swish 3.ogg" +dest_files=[ "res://.import/grass swish 3.ogg-8d9986e80092be5e026c4d30b38c8a68.oggstr" ] + +[params] + +loop=false +loop_offset=0 diff --git a/assets/sounds/grass swish 4.ogg b/assets/sounds/grass swish 4.ogg new file mode 100644 index 0000000..48752fa Binary files /dev/null and b/assets/sounds/grass swish 4.ogg differ diff --git a/assets/sounds/grass swish 4.ogg.import b/assets/sounds/grass swish 4.ogg.import new file mode 100644 index 0000000..e4ec5e2 --- /dev/null +++ b/assets/sounds/grass swish 4.ogg.import @@ -0,0 +1,15 @@ +[remap] + +importer="ogg_vorbis" +type="AudioStreamOGGVorbis" +path="res://.import/grass swish 4.ogg-dde2025c601051c92eabce1a8be33538.oggstr" + +[deps] + +source_file="res://assets/sounds/grass swish 4.ogg" +dest_files=[ "res://.import/grass swish 4.ogg-dde2025c601051c92eabce1a8be33538.oggstr" ] + +[params] + +loop=false +loop_offset=0 diff --git a/src/Actors/Actor.gd b/src/Actors/Actor.gd index 3676b83..51e161e 100644 --- a/src/Actors/Actor.gd +++ b/src/Actors/Actor.gd @@ -35,13 +35,13 @@ var init_acceleration_force := {"": 0, "idle_walk": 4181, "idle_run": 5765, "wal # Oriented around deltas of 0.0166666...s # newtonmeters is the unit var acceleration_force := { - "walk": Vector2(1800, 1385), + "walk": Vector2(1800, 1300), "fall": Vector2(1800, 1050), "jump": Vector2(1800, 0), "idle": Vector2(1800, 1233), "duck": Vector2(500, 1300), "duck_walk": Vector2(500, 1300), - "run": Vector2(2500, 1490), + "run": Vector2(2500, 1400), "walljump": Vector2(600, 1050), "air_strafe": Vector2(333, 2000) } diff --git a/src/Actors/Blobby/Blobby.gd b/src/Actors/Blobby/Blobby.gd index 473a776..c03a663 100644 --- a/src/Actors/Blobby/Blobby.gd +++ b/src/Actors/Blobby/Blobby.gd @@ -28,435 +28,447 @@ var shielded = false func execute_movement() -> void: - if level_state.is_dead: - return - var snap = Vector2.DOWN * 128 - var center_floor_rot = 0 - var floor_rot = 0 - var onfloor = is_on_floor() + if level_state.is_dead: + return + var snap = Vector2.DOWN * 128 + var center_floor_rot = 0 + var floor_rot = 0 + var onfloor = is_on_floor() - # get rotation of floor, compare collided floor with floor under center - if onfloor: - # TODO: Problem when correctly rotating? - center_floor_rot = $SlopeRaycast.get_collision_normal().rotated(PI / 2).angle() - floor_rot = get_floor_normal().rotated(PI / 2).angle() - if abs(center_floor_rot) > PI / 4 + 0.1: - center_floor_rot = floor_rot - # snap when on slopes - if (abs(floor_rot) > 0.1 || abs(center_floor_rot) > 0.1) && snap_possible: - velocity = move_and_slide_with_snap(velocity.rotated(floor_rot), snap, FLOOR_NORMAL, true) - # normal slide on flat floor - else: - velocity = move_and_slide(velocity.rotated(floor_rot), FLOOR_NORMAL) - rotation = 0 - if ( - $SlopeRaycastLeft.is_colliding() - && $SlopeRaycastRight.is_colliding() - && $SlopeRaycast.is_colliding() - ): - rotation = calculate_slope_rotation(onfloor) - # rotate related to floor slope - # Convert velocity back to local space. - # TODO: Downward velocity should be increased by gravity - velocity = velocity.rotated(-floor_rot) if snap_possible else velocity + # get rotation of floor, compare collided floor with floor under center + if onfloor: + # TODO: Problem when correctly rotating? + center_floor_rot = $SlopeRaycast.get_collision_normal().rotated(PI / 2).angle() + floor_rot = get_floor_normal().rotated(PI / 2).angle() + if abs(center_floor_rot) > PI / 4 + 0.1: + center_floor_rot = floor_rot + # snap when on slopes + if (abs(floor_rot) > 0.1 || abs(center_floor_rot) > 0.1) && snap_possible: + velocity = move_and_slide_with_snap(velocity.rotated(floor_rot), snap, FLOOR_NORMAL, true) + # normal slide on flat floor + else: + velocity = move_and_slide(velocity.rotated(floor_rot), FLOOR_NORMAL) + rotation = 0 + if ( + $SlopeRaycastLeft.is_colliding() + && $SlopeRaycastRight.is_colliding() + && $SlopeRaycast.is_colliding() + ): + rotation = calculate_slope_rotation(onfloor) + # rotate related to floor slope + # Convert velocity back to local space. + # TODO: Downward velocity should be increased by gravity + velocity = velocity.rotated(-floor_rot) if snap_possible else velocity func calculate_duck_velocity(linear_velocity: Vector2, delta: float, direction: Vector2) -> Vector2: - var state = player_state_machine.state - var out_vel := linear_velocity - var velocity_direction = 1.0 - if velocity.x < 0: - velocity_direction = -1.0 + var state = player_state_machine.state + var out_vel := linear_velocity + var velocity_direction = 1.0 + if velocity.x < 0: + velocity_direction = -1.0 - # TODO Improve this to separate crawling(slow) and sliding - var deceleration_force = calculate_deceleration_force(_gravity, mass) * 0.333 + # TODO Improve this to separate crawling(slow) and sliding + var deceleration_force = calculate_deceleration_force(_gravity, mass) * 0.333 - # Slowing down movement when not controlling direction - if is_equal_approx(direction.x, 0): - # TODO Handle Deadzones - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, deceleration_force * -1 * velocity_direction, mass, delta - ) - if abs(out_vel.x) > abs(velocity.x): - out_vel.x = 0 - else: - # Reversing movement - # When turning the opposite direction, friction is added to the opposite acceleration movement - var reverse_move = is_reversing_horizontal_movement(direction) - if reverse_move: - # TODO dont put constants in here - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, deceleration_force * -3.42 * velocity_direction, mass, delta - ) - # Normal movement - if abs(velocity.x) < max_velocity[state]: - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, (acceleration_force[state].x) * direction.x, mass, delta - ) - elif !reverse_move: - out_vel.x = max_velocity[state] * direction.x - # TODO is_on_dropThrough does the action, is that ok? yEs, MaAsTeR-ChAn - # TODO Drop Through coyote time? - if Input.is_action_just_pressed("jump") && is_on_dropThrough(): - return Vector2(out_vel.x, _gravity * delta) - # Jumping when grounded or jump is buffered - if Input.is_action_just_pressed("jump") || (jump_buffer_filled && is_on_floor()): - snap_possible = false - return calculate_jump_velocity(velocity, delta, direction) + # Slowing down movement when not controlling direction + if is_equal_approx(direction.x, 0): + # TODO Handle Deadzones + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, deceleration_force * -1 * velocity_direction, mass, delta + ) + if abs(out_vel.x) > abs(velocity.x): + out_vel.x = 0 + else: + # Reversing movement + # When turning the opposite direction, friction is added to the opposite acceleration movement + var reverse_move = is_reversing_horizontal_movement(direction) + if reverse_move: + # TODO dont put constants in here + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, deceleration_force * -3.42 * velocity_direction, mass, delta + ) + # Normal movement + if abs(velocity.x) < max_velocity[state]: + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, (acceleration_force[state].x) * direction.x, mass, delta + ) + elif !reverse_move: + out_vel.x = max_velocity[state] * direction.x + # TODO is_on_dropThrough does the action, is that ok? yEs, MaAsTeR-ChAn + # TODO Drop Through coyote time? + if Input.is_action_just_pressed("jump") && is_on_dropThrough(): + return Vector2(out_vel.x, _gravity * delta) + # Jumping when grounded or jump is buffered + if Input.is_action_just_pressed("jump") || (jump_buffer_filled && is_on_floor()) || stomping: + snap_possible = false + return calculate_jump_velocity(velocity, delta, direction) - elif player_state_machine.coyote_hanging: - out_vel.y = 0 + elif player_state_machine.coyote_hanging: + out_vel.y = 0 - else: - out_vel.y = _gravity * delta + else: + out_vel.y = _gravity * delta - return out_vel + return out_vel func is_on_dropThrough(): - var bodies: Array = $BlobbySkin.get_overlapping_bodies() - for i in range(0, bodies.size()): - if bodies[i].get_collision_mask_bit(7): - set_collision_mask_bit(7, false) - return true - return false + var bodies: Array = $BlobbySkin.get_overlapping_bodies() + for i in range(0, bodies.size()): + if bodies[i].get_collision_mask_bit(7): + set_collision_mask_bit(7, false) + return true + return false func calculate_grounded_velocity( - linear_velocity: Vector2, delta: float, direction: Vector2 + linear_velocity: Vector2, delta: float, direction: Vector2 ) -> Vector2: - var state = player_state_machine.state - var out_vel := linear_velocity - var velocity_direction = 1.0 - if velocity.x < 0: - velocity_direction = -1.0 + var state = player_state_machine.state + var out_vel := linear_velocity + var velocity_direction = 1.0 + if velocity.x < 0: + velocity_direction = -1.0 - var deceleration_force = calculate_deceleration_force(_gravity, mass) + var deceleration_force = calculate_deceleration_force(_gravity, mass) - # Slowing down movement when not controlling direction - if is_equal_approx(direction.x, 0): - # TODO Handle Deadzones - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, deceleration_force * -1 * velocity_direction, mass, delta - ) - if abs(out_vel.x) > abs(velocity.x): - out_vel.x = 0 - else: - # Reversing movement - # When turning the opposite direction, friction is added to the opposite acceleration movement - var reverse_move = is_reversing_horizontal_movement(direction) - if reverse_move: - # TODO dont put constants in here - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, deceleration_force * -3.42 * velocity_direction, mass, delta - ) - # Normal movement - if abs(velocity.x) < max_velocity[state]: - out_vel.x = PhysicsFunc.two_step_euler( - out_vel.x, - ( - ( - acceleration_force[state].x - + (init_acceleration_force[init_boost_type] * int(init_boost)) - ) - * direction.x - ), - mass, - delta - ) - elif !reverse_move: - out_vel.x = max_velocity[state] * direction.x - # Jumping when grounded or jump is buffered - if Input.is_action_just_pressed("jump") || (jump_buffer_filled && is_on_floor()): - snap_possible = false - return calculate_jump_velocity(velocity, delta, direction) + # Slowing down movement when not controlling direction + if is_equal_approx(direction.x, 0): + # TODO Handle Deadzones + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, deceleration_force * -1 * velocity_direction, mass, delta + ) + if abs(out_vel.x) > abs(velocity.x): + out_vel.x = 0 + else: + # Reversing movement + # When turning the opposite direction, friction is added to the opposite acceleration movement + var reverse_move = is_reversing_horizontal_movement(direction) + if reverse_move: + # TODO dont put constants in here + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, deceleration_force * -3.42 * velocity_direction, mass, delta + ) + # Normal movement + if abs(velocity.x) < max_velocity[state]: + out_vel.x = PhysicsFunc.two_step_euler( + out_vel.x, + ( + ( + acceleration_force[state].x + + (init_acceleration_force[init_boost_type] * int(init_boost)) + ) + * direction.x + ), + mass, + delta + ) + elif !reverse_move: + out_vel.x = max_velocity[state] * direction.x + # Jumping when grounded or jump is buffered + if Input.is_action_just_pressed("jump") || (jump_buffer_filled && is_on_floor()) || stomping: + snap_possible = false + return calculate_jump_velocity(velocity, delta, direction) - elif player_state_machine.coyote_hanging: - out_vel.y = 0 + elif player_state_machine.coyote_hanging: + out_vel.y = 0 - else: - out_vel.y = _gravity * delta + else: + out_vel.y = _gravity * delta - return out_vel + return out_vel # Determines if the player has reversed the steering direction # in reference to the current movement direction func is_reversing_horizontal_movement(direction: Vector2) -> bool: - return (direction.x > 0 && velocity.x < 0) || (direction.x < 0 && velocity.x > 0) + return (direction.x > 0 && velocity.x < 0) || (direction.x < 0 && velocity.x > 0) # Returns if the character is touching a wall with its whole body # Being able to touch a vertical surface over this length also makes it a qualified "wall" # Also sets wall_touch_direction func is_touching_wall_completely() -> bool: - var value = true - for left_raycast in left_wall_raycasts.get_children(): - wall_touch_direction = -1 - if !left_raycast.is_colliding(): - value = false - continue - if value == true: - return value + var value = true + for left_raycast in left_wall_raycasts.get_children(): + wall_touch_direction = -1 + if !left_raycast.is_colliding(): + value = false + continue + if value == true: + return value - value = true - for right_raycast in right_wall_raycasts.get_children(): - wall_touch_direction = 1 - if !right_raycast.is_colliding(): - value = false - continue - return value + value = true + for right_raycast in right_wall_raycasts.get_children(): + wall_touch_direction = 1 + if !right_raycast.is_colliding(): + value = false + continue + return value # Attached to wall state is in the PlayerStateMachine func is_correct_walljump_input(direction: Vector2) -> bool: - return ( - Input.is_action_just_pressed("jump") - && abs(direction.x + wall_touch_direction) < 1 - && abs(direction.x + wall_touch_direction) >= 0 - ) + return ( + Input.is_action_just_pressed("jump") + && abs(direction.x + wall_touch_direction) < 1 + && abs(direction.x + wall_touch_direction) >= 0 + ) func is_correct_airstrafe_input() -> bool: - return ( - air_strafe_charges > 0 - && (Input.is_action_just_pressed("move_right") || Input.is_action_just_pressed("move_left")) - ) + return ( + air_strafe_charges > 0 + && (Input.is_action_just_pressed("move_right") || Input.is_action_just_pressed("move_left")) + ) # Calculates the force of the ground friction func calculate_deceleration_force(_gravity: float, mass: float) -> float: - return floor_friction * _gravity * mass + return floor_friction * _gravity * mass + + +func calculate_stomp_velocity(delta: float) -> float: + var v = 0 + if Input.is_action_pressed("jump"): + v += stomp_feedback + # print(stomp_time) + stomp_time -= delta + # print(stomp_time) + if stomp_time <= 0: +# print("stomping over") + stomping = false + stomp_time = init_stomp_time + return v func calculate_jump_velocity(linear_velocity: Vector2, delta: float, direction: Vector2) -> Vector2: - var state = player_state_machine.state - var additive_jump_force = velocity_jump_boost_ratio * abs(velocity.x) * mass - #TODO Single out stomping and make betta - #TODO too much force intially and too high with frog jump - if stomping: - if Input.is_action_pressed("jump"): - additive_jump_force += stomp_feedback - stomp_time -= delta - # print(stomp_time) - if stomp_time <= 0: -# print("stomping over") - stomping = false - stomp_time = init_stomp_time + var state = player_state_machine.state + var additive_jump_force = velocity_jump_boost_ratio * abs(velocity.x) * mass + #TODO Single out stomping and make betta + #TODO too much force intially and too high with frog jump + if stomping: + additive_jump_force += calculate_stomp_velocity(delta) - if state != "jump": - linear_velocity.y = PhysicsFunc.two_step_euler( - linear_velocity.y, - (acceleration_force[state].y / delta + additive_jump_force) * -1, - mass, - delta - ) + if state != "jump": + linear_velocity.y = PhysicsFunc.two_step_euler( + linear_velocity.y, + (acceleration_force[state].y / delta + additive_jump_force) * -1, + mass, + delta + ) # print(acceleration_force[state].y) # print(linear_velocity.y) - if !Input.is_action_pressed("jump") && !stomping: - # Smooth transition from jumping to falling - if velocity.y > _gravity * delta * 10: - linear_velocity.y += _gravity * delta * 10 - else: - linear_velocity.y += (max(abs(linear_velocity.y), _gravity * delta) / 2) + if !Input.is_action_pressed("jump") && !stomping: + # Smooth transition from jumping to falling + if velocity.y > _gravity * delta * 10: + linear_velocity.y += _gravity * delta * 10 + else: + linear_velocity.y += (max(abs(linear_velocity.y), _gravity * delta) / 2) - else: - linear_velocity.y += _gravity * delta + else: + linear_velocity.y += _gravity * delta - # TODO This is poop too - if ( - -max_velocity["jump"].x < velocity.x and direction.x < 0 - || max_velocity["jump"].x > velocity.x and direction.x > 0 - ): - var absolut = 1 - initial_velocity_dependence - var divisor = 1 / max(0.1, initial_velocity_dependence) - var movement_factor = absolut + abs(velocity.x) / (max_velocity["fall"].x * divisor) - linear_velocity.x = PhysicsFunc.two_step_euler( - linear_velocity.x, - acceleration_force[state].x * movement_factor * direction.x, - mass, - delta - ) + # TODO This is poop too + if ( + -max_velocity["jump"].x < velocity.x and direction.x < 0 + || max_velocity["jump"].x > velocity.x and direction.x > 0 + ): + var absolut = 1 - initial_velocity_dependence + var divisor = 1 / max(0.1, initial_velocity_dependence) + var movement_factor = absolut + abs(velocity.x) / (max_velocity["fall"].x * divisor) + linear_velocity.x = PhysicsFunc.two_step_euler( + linear_velocity.x, + acceleration_force[state].x * movement_factor * direction.x, + mass, + delta + ) - if is_correct_airstrafe_input(): - linear_velocity = execute_airstrafe(linear_velocity, delta, direction) + if is_correct_airstrafe_input(): + linear_velocity = execute_airstrafe(linear_velocity, delta, direction) # print(linear_velocity.y) - return linear_velocity + return linear_velocity # Only applicable to downwards gravity # Can set the jump buffer func calculate_fall_velocity(linear_velocity: Vector2, delta: float, direction: Vector2) -> Vector2: - var state = player_state_machine.state - if velocity.y < max_velocity["fall"].y: - linear_velocity.y = PhysicsFunc.two_step_euler( - linear_velocity.y, _gravity * mass, mass, delta - ) - else: - linear_velocity.y = max_velocity["fall"].y - if ( - -max_velocity["fall"].x < velocity.x and direction.x < 0 - || max_velocity["fall"].x > velocity.x and direction.x > 0 - ): - # TODO This is poop - var absolut = 1 - initial_velocity_dependence - var divisor = 1 / max(0.1, initial_velocity_dependence) - var movementFactor = absolut + abs(velocity.x) / (max_velocity["fall"].x * divisor) - linear_velocity.x = PhysicsFunc.two_step_euler( - linear_velocity.x, - acceleration_force[state].x * movementFactor * direction.x, - mass, - delta - ) - if Input.is_action_just_pressed("jump"): - jump_buffer_filled = true - if is_correct_airstrafe_input(): - linear_velocity = execute_airstrafe(linear_velocity, delta, direction) - if stomping: - linear_velocity = calculate_jump_velocity(Vector2(linear_velocity.x, 0), delta, direction) - return linear_velocity + var state = player_state_machine.state + if velocity.y < max_velocity["fall"].y: + linear_velocity.y = PhysicsFunc.two_step_euler( + linear_velocity.y, _gravity * mass, mass, delta + ) + else: + linear_velocity.y = max_velocity["fall"].y + if ( + -max_velocity["fall"].x < velocity.x and direction.x < 0 + || max_velocity["fall"].x > velocity.x and direction.x > 0 + ): + # TODO This is poop + var absolut = 1 - initial_velocity_dependence + var divisor = 1 / max(0.1, initial_velocity_dependence) + var movementFactor = absolut + abs(velocity.x) / (max_velocity["fall"].x * divisor) + linear_velocity.x = PhysicsFunc.two_step_euler( + linear_velocity.x, + acceleration_force[state].x * movementFactor * direction.x, + mass, + delta + ) + if Input.is_action_just_pressed("jump"): + jump_buffer_filled = true + if is_correct_airstrafe_input(): + linear_velocity = execute_airstrafe(linear_velocity, delta, direction) + if stomping: + linear_velocity = calculate_jump_velocity(Vector2(linear_velocity.x, 0), delta, direction) + return linear_velocity func calculate_wallslide_velocity( - linear_velocity: Vector2, delta: float, direction: Vector2 + linear_velocity: Vector2, delta: float, direction: Vector2 ) -> Vector2: - # Walljump mechanics - if is_correct_walljump_input(direction): - linear_velocity.x = PhysicsFunc.two_step_euler( - 0, acceleration_force["walljump"].x / delta * direction.x, mass, delta - ) - linear_velocity.y = PhysicsFunc.two_step_euler( - 0, acceleration_force["walljump"].y / delta * -1, mass, delta - ) - elif is_correct_airstrafe_input(): - # var rev = 1 if !is_reversing_horizontal_movement(direction) else -1 - linear_velocity = execute_airstrafe(linear_velocity, delta, direction) - else: - # TODO dont put constants in here - linear_velocity.y = PhysicsFunc.two_step_euler( - linear_velocity.y * 0.94, _gravity * mass, mass, delta - ) - air_strafe_charges = ( - air_strafe_charges + 1 - if max_air_strafe_charges > air_strafe_charges - else 0 - ) - return linear_velocity.rotated(rotation) + # Walljump mechanics + if is_correct_walljump_input(direction): + linear_velocity.x = PhysicsFunc.two_step_euler( + 0, acceleration_force["walljump"].x / delta * direction.x, mass, delta + ) + linear_velocity.y = PhysicsFunc.two_step_euler( + 0, acceleration_force["walljump"].y / delta * -1, mass, delta + ) + elif is_correct_airstrafe_input(): + # var rev = 1 if !is_reversing_horizontal_movement(direction) else -1 + linear_velocity = execute_airstrafe(linear_velocity, delta, direction) + else: + # TODO dont put constants in here + linear_velocity.y = PhysicsFunc.two_step_euler( + linear_velocity.y * 0.94, _gravity * mass, mass, delta + ) + air_strafe_charges = ( + air_strafe_charges + 1 + if max_air_strafe_charges > air_strafe_charges + else 0 + ) + return linear_velocity.rotated(rotation) func execute_airstrafe(linear_velocity: Vector2, delta: float, direction: Vector2) -> Vector2: - # var rev = 1 if !is_reversing_horizontal_movement(direction) else -1 - # TODO Consider adding a extra state for airstrafing - # TODO Make airstrafing less instantaneous and moderate the impulse - if direction.x > 0: - effect_player.play("airstrafing") - else: - effect_player.play("airstrafingLeft") - if is_reversing_horizontal_movement(direction): - linear_velocity.x = 0 - linear_velocity.x = PhysicsFunc.two_step_euler( - linear_velocity.x, acceleration_force["air_strafe"].x / delta * direction.x, mass, delta - ) - if linear_velocity.y > 0: - # TODO Put constant elsewhere - linear_velocity.y = linear_velocity.y * 0.33 - air_strafe_charges -= 1 - return linear_velocity + # var rev = 1 if !is_reversing_horizontal_movement(direction) else -1 + # TODO Consider adding a extra state for airstrafing + # TODO Make airstrafing less instantaneous and moderate the impulse + if direction.x > 0: + effect_player.play("airstrafing") + else: + effect_player.play("airstrafingLeft") + if is_reversing_horizontal_movement(direction): + linear_velocity.x = 0 + linear_velocity.x = PhysicsFunc.two_step_euler( + linear_velocity.x, acceleration_force["air_strafe"].x / delta * direction.x, mass, delta + ) + if linear_velocity.y > 0: + # TODO Put constant elsewhere + linear_velocity.y = linear_velocity.y * 0.33 + air_strafe_charges -= 1 + return linear_velocity func calculate_slope_rotation(_onfloor: bool) -> float: - var angle = 0 - var slope_angle_left = $SlopeRaycastLeft.get_collision_normal().rotated(PI / 2).angle() - var slope_angle_right = $SlopeRaycastRight.get_collision_normal().rotated(PI / 2).angle() - # avoid invalid angles and stay in rotation when touching ground completely - if ( - !(-PI / 2 <= slope_angle_left && slope_angle_left <= PI / 2) - || !(-PI / 2 <= slope_angle_right && slope_angle_right <= PI / 2) - || (is_equal_approx(abs(slope_angle_left), abs(slope_angle_right))) - ): - return ( - previous_rotation - if abs(rad2deg(previous_rotation)) > 1 && !is_equal_approx(slope_angle_left, 0) - else 0.0 - ) - # downturn - if ( - abs(slope_angle_left) > abs(slope_angle_right) && velocity.x < -10 - || abs(slope_angle_right) > abs(slope_angle_left) && velocity.x > 10 - ): - var length_vector: Vector2 = ( - $SlopeRaycastRight.get_collision_point() - - $SlopeRaycastLeft.get_collision_point() - ) - angle = length_vector.angle() - # upturn - else: - var length_vector: Vector2 = ( - $SlopeRaycastLeft.get_collision_point() - - $SlopeRaycastRight.get_collision_point() - ) - angle = length_vector.angle() - PI - previous_rotation = angle - if is_equal_approx(deg2rad(angle), 0): - pass - return angle + var angle = 0 + var slope_angle_left = $SlopeRaycastLeft.get_collision_normal().rotated(PI / 2).angle() + var slope_angle_right = $SlopeRaycastRight.get_collision_normal().rotated(PI / 2).angle() + # avoid invalid angles and stay in rotation when touching ground completely + if ( + !(-PI / 2 <= slope_angle_left && slope_angle_left <= PI / 2) + || !(-PI / 2 <= slope_angle_right && slope_angle_right <= PI / 2) + || (is_equal_approx(abs(slope_angle_left), abs(slope_angle_right))) + ): + return ( + previous_rotation + if abs(rad2deg(previous_rotation)) > 1 && !is_equal_approx(slope_angle_left, 0) + else 0.0 + ) + # downturn + if ( + abs(slope_angle_left) > abs(slope_angle_right) && velocity.x < -10 + || abs(slope_angle_right) > abs(slope_angle_left) && velocity.x > 10 + ): + var length_vector: Vector2 = ( + $SlopeRaycastRight.get_collision_point() + - $SlopeRaycastLeft.get_collision_point() + ) + angle = length_vector.angle() + # upturn + else: + var length_vector: Vector2 = ( + $SlopeRaycastLeft.get_collision_point() + - $SlopeRaycastRight.get_collision_point() + ) + angle = length_vector.angle() - PI + previous_rotation = angle + if is_equal_approx(deg2rad(angle), 0): + pass + return angle # TODO could be expanded with a parameter about what got stomped func stomp() -> void: # print("stomping") - stomping = true + print(player_state_machine.state) + scene_audio.play_parallel_sound( + "res://assets/sounds/FABRIC_Flap_03_mono.wav", -15, false, 1.5, 0.2 + ) + scene_audio.play_parallel_sound("res://assets/sounds/CLASP_Plastic_Open_stereo.wav", -12) + stomping = true # TOD lose_power_up function func receive_power_up(kind: String) -> void: - if kind == "shield": - $BubbleShieldViewport/IridescenceBall.visible = true - shielded = true + if kind == "shield": + $BubbleShieldViewport/IridescenceBall.visible = true + shielded = true # TODO Maybe this should be a state in itself? func die(animation_number: int = 0) -> void: - if level_state.is_dead: - return - if shielded: - shielded = false - $BubbleShieldViewport/IridescenceBall.visible = false - $InvincibilityTimer.start() - $BlobbySprite.material = invincible_shader - return - elif !$InvincibilityTimer.is_stopped(): - return - z_index = 1 - $BlobbySprite.material = death_shader - signal_manager.emit_signal("player_died", animation_number) - $"%BlobbymationTree".active = false - $"%BlobbymationPlayer".play("dying3") - if animation_number < 1: - $"%BlobbymationPlayer".play("expandingDisolve") - scene_audio.play_parallel_sound(death_sound_1, -15) - scene_audio.play_parallel_sound(death_sound_2, -16) + if level_state.is_dead: + return + if shielded: + shielded = false + $BubbleShieldViewport/IridescenceBall.visible = false + $InvincibilityTimer.start() + $BlobbySprite.material = invincible_shader + return + elif !$InvincibilityTimer.is_stopped(): + return + z_index = 1 + $BlobbySprite.material = death_shader + signal_manager.emit_signal("player_died", animation_number) + $"%BlobbymationTree".active = false + $"%BlobbymationPlayer".play("dying3") + if animation_number < 1: + $"%BlobbymationPlayer".play("expandingDisolve") + scene_audio.play_parallel_sound(death_sound_1, -15) + scene_audio.play_parallel_sound(death_sound_2, -16) func die_for_real(animation_number: int = 0) -> void: - shielded = false - $BubbleShieldViewport/IridescenceBall.visible = false - die(animation_number) + shielded = false + $BubbleShieldViewport/IridescenceBall.visible = false + die(animation_number) # TODO Checkpoint system func respawn() -> void: - # Is tied to the death animation - get_tree().reload_current_scene() + # Is tied to the death animation + get_tree().reload_current_scene() # When the Enemy stomp AREA enters the enemy collision area -> stomp func _on_BlobbySkin_area_entered(area: Area2D) -> void: - if area.is_in_group("harmful"): - die() - if area.is_in_group("pit"): - $PitfallTimer.start() + if area.is_in_group("harmful"): + die() + if area.is_in_group("pit"): + $PitfallTimer.start() # This problem stems from trying to decelerate a walk @@ -464,49 +476,49 @@ func _on_BlobbySkin_area_entered(area: Area2D) -> void: # It is particularly usefull for moving floor physics # TODO Setting y velocity this way stopped is_on_floor() from working correctly func _on_Blobby_got_grounded() -> void: - velocity.x -= get_floor_velocity().x - snap_possible = true - var floor_object = get_last_slide_collision().collider.get_parent() - #TODO There is already a friction property in engine - if "slide_friction" in floor_object: - floor_friction = floor_object.slide_friction - else: - floor_friction = base_floor_friction - air_strafe_charges = ( - air_strafe_charges + 1 - if max_air_strafe_charges > air_strafe_charges - else 0 - ) + velocity.x -= get_floor_velocity().x + snap_possible = true + var floor_object = get_last_slide_collision().collider.get_parent() + #TODO There is already a friction property in engine + if "slide_friction" in floor_object: + floor_friction = floor_object.slide_friction + else: + floor_friction = base_floor_friction + air_strafe_charges = ( + air_strafe_charges + 1 + if max_air_strafe_charges > air_strafe_charges + else 0 + ) func _on_BlobbySkin_body_exited(body: Node) -> void: - # This is for drop through platforms - if body.get_collision_mask_bit(7): - set_collision_mask_bit(7, true) + # This is for drop through platforms + if body.get_collision_mask_bit(7): + set_collision_mask_bit(7, true) func _on_InvincibilityTimer_timeout() -> void: - $BlobbySprite.material = null - for area in $BlobbySkin.get_overlapping_areas(): - if area.is_in_group("harmful"): - die() + $BlobbySprite.material = null + for area in $BlobbySkin.get_overlapping_areas(): + if area.is_in_group("harmful"): + die() func handle_grounded_movement(delta: float, direction: Vector2) -> Vector2: - return calculate_grounded_velocity(velocity, delta, direction) + return calculate_grounded_velocity(velocity, delta, direction) func handle_jump_movement(delta: float, direction: Vector2) -> Vector2: - return calculate_jump_velocity(velocity, delta, direction) + return calculate_jump_velocity(velocity, delta, direction) func handle_duck_movement(delta: float, direction: Vector2) -> Vector2: - return calculate_duck_velocity(velocity, delta, direction) + return calculate_duck_velocity(velocity, delta, direction) func handle_fall_movement(delta: float, direction: Vector2) -> Vector2: - return calculate_fall_velocity(velocity, delta, direction) + return calculate_fall_velocity(velocity, delta, direction) func handle_wallslide_movement(delta: float, direction: Vector2) -> Vector2: - return calculate_wallslide_velocity(velocity, delta, direction) + return calculate_wallslide_velocity(velocity, delta, direction) diff --git a/src/Actors/Blobby/Blobby.tscn b/src/Actors/Blobby/Blobby.tscn index a250edf..a6007b8 100644 --- a/src/Actors/Blobby/Blobby.tscn +++ b/src/Actors/Blobby/Blobby.tscn @@ -4385,7 +4385,7 @@ texture = SubResource( 62 ) offset = Vector2( 1, 0 ) hframes = 6 vframes = 6 -frame = 10 +frame = 7 __meta__ = { "_editor_description_": "YXNlcHJpdGVfd2l6YXJkX2NvbmZpZwpwbGF5ZXJ8PUJsb2JieVNwcml0ZS9CbG9iYnltYXRpb25QbGF5ZXIKc291cmNlfD1yZXM6Ly9hc3NldHMvYmxvYmJ5L2Jsb2JieS1zcHJpdGVzaGVldHQuYXNlcHJpdGUKbGF5ZXJ8PUJsb2JieQpvcF9leHB8PUZhbHNlCm9fZm9sZGVyfD0Kb19uYW1lfD0Kb25seV92aXNpYmxlfD1GYWxzZQpvX2V4X3B8PQo=" } diff --git a/src/Actors/BlobbyCam.gd b/src/Actors/BlobbyCam.gd index e3a2061..3ceaee1 100644 --- a/src/Actors/BlobbyCam.gd +++ b/src/Actors/BlobbyCam.gd @@ -5,7 +5,7 @@ export var offset_reset_seconds := 1 export var offset_adapt_seconds := 1 export var offset_input_seconds := 0.618 * 2 export var alarm_light_shader: Material -export var fixed_position : bool = false +export var fixed_position: bool = false onready var level_state := $"%LevelState" onready var signal_manager := $"%SignalManager" @@ -29,7 +29,7 @@ var original_limit_right: int var original_limit_bottom: int var original_limit_top: int var camera_is_panning: bool = false -var target_offset: Vector2 = Vector2(0,0) +var target_offset: Vector2 = Vector2(0, 0) var terminal_activated: bool = false var image = Image.new() @@ -38,232 +38,252 @@ var prev_pos: Vector2 var camera_state := "centered" var screen_rect = Vector2() -var old_screen_rect = Vector2(ProjectSettings.get_setting("display/window/size/width") * zoom.x, ProjectSettings.get_setting("display/window/size/height") * zoom.y ) +var old_screen_rect = Vector2( + ProjectSettings.get_setting("display/window/size/width") * zoom.x, + ProjectSettings.get_setting("display/window/size/height") * zoom.y +) var screen_center = Vector2() var screen_bottom = Vector2() var screen_top = Vector2() var screen_left = Vector2() var screen_right = Vector2() + # Gets the camera limits from the tilemap of the level # Requires "TileMap" to be a sibling of blobby func _ready(): - _set_boundaries() - get_tree().get_root().connect("size_changed", self, "_set_boundaries") - if !fixed_position: - self.position = blobby.global_position - image.create(128, 2, false, Image.FORMAT_RGBAH) - # TODO Test Performance - material.set_shader_param("light_data", null) - _update_lighting_shader() - # TODO Trigger when needed - signal_manager.connect("terminal_activated", self, "_on_SignalManager_terminal_activated") - signal_manager.connect("player_died", self, "_death_cam") + _set_boundaries() + get_tree().get_root().connect("size_changed", self, "_set_boundaries") + if !fixed_position: + self.position = blobby.global_position + image.create(128, 2, false, Image.FORMAT_RGBAH) + # TODO Test Performance + material.set_shader_param("light_data", null) + _update_lighting_shader() + # TODO Trigger when needed + signal_manager.connect("terminal_activated", self, "_on_SignalManager_terminal_activated") + signal_manager.connect("player_died", self, "_death_cam") + func _on_SignalManager_terminal_activated(animation_number: int = 0): - terminal_activated = true - get_node("LightAnimationPlayer").play("Pulsing") + terminal_activated = true + get_node("LightAnimationPlayer").play("Pulsing") + #func _draw(): # draw_line(Vector2((limit_left - position.x), screen_center.y), screen_left, Color(255, 0, 0), 1) + func _physics_process(delta: float) -> void: - if fixed_position: - return + if fixed_position: + return # update() - screen_center = (get_camera_screen_center() - position) - screen_bottom = screen_center + Vector2(0, screen_rect.y/2) - screen_top = screen_center - Vector2(0, screen_rect.y/2) - screen_left = screen_center - Vector2(screen_rect.x/2, 0) - screen_right = screen_center + Vector2(screen_rect.x/2, 0) - var was_adjusted := false - if(!level_state.is_dead): - was_adjusted = _adjust_offset(delta) + screen_center = (get_camera_screen_center() - position) + screen_bottom = screen_center + Vector2(0, screen_rect.y / 2) + screen_top = screen_center - Vector2(0, screen_rect.y / 2) + screen_left = screen_center - Vector2(screen_rect.x / 2, 0) + screen_right = screen_center + Vector2(screen_rect.x / 2, 0) + var was_adjusted := false + if !level_state.is_dead: + was_adjusted = _adjust_offset(delta) - if(anim_player.is_playing() || was_adjusted): - position = blobby.position - prev_pos = position - _update_lighting_shader() - return - var player_vel = (blobby.position - prev_pos)/delta - # TODO Take average of velocity here - if(abs(player_vel.x) >= blobby.max_velocity["walk"] * 0.97 - && (sign(player_vel.x) == sign(target_offset.x) || target_offset.x == 0)): - if(player_vel.x > 0): - right_move_time += delta - left_move_time = max(0, left_move_time - delta) - slow_time = max(0, slow_time - delta) - else: - left_move_time += delta - right_move_time = max(0, right_move_time - delta) - slow_time = max(0, slow_time - delta) - elif(abs(player_vel.x) <= blobby.max_velocity["walk"] * 0.9 - || sign(player_vel.x) != sign(target_offset.x) || target_offset.x == 0): - slow_time += delta - left_move_time = max(0, left_move_time - delta) - right_move_time = max(0, right_move_time - delta) + if anim_player.is_playing() || was_adjusted: + position = blobby.position + prev_pos = position + _update_lighting_shader() + return + var player_vel = (blobby.position - prev_pos) / delta + # TODO Take average of velocity here + if ( + abs(player_vel.x) >= blobby.max_velocity["walk"] * 0.97 + && (sign(player_vel.x) == sign(target_offset.x) || target_offset.x == 0) + ): + if player_vel.x > 0: + right_move_time += delta + left_move_time = max(0, left_move_time - delta) + slow_time = max(0, slow_time - delta) + else: + left_move_time += delta + right_move_time = max(0, right_move_time - delta) + slow_time = max(0, slow_time - delta) + elif ( + abs(player_vel.x) <= blobby.max_velocity["walk"] * 0.9 + || sign(player_vel.x) != sign(target_offset.x) + || target_offset.x == 0 + ): + slow_time += delta + left_move_time = max(0, left_move_time - delta) + right_move_time = max(0, right_move_time - delta) + + _adapt_to_movement(player_vel) + if abs(player_vel.x) <= blobby.max_velocity["walk"] * 0.9: + _adapt_to_input(player_vel, delta) + position = blobby.position + prev_pos = position + _update_lighting_shader() - _adapt_to_movement(player_vel) - if abs(player_vel.x) <= blobby.max_velocity["walk"] * 0.9: - _adapt_to_input(player_vel, delta) - position = blobby.position - prev_pos = position - _update_lighting_shader() # TODO This has to be redone when the screen is resized in any way # Otherwise the boundaries will not be correct anymore func _set_boundaries(): - screen_rect = get_viewport_rect().size - screen_rect.x *= zoom.x - screen_rect.y *= zoom.y - original_x_zoom = zoom.x - original_y_zoom = zoom.y - # This is ok, because it only happens on initialization - # But it is also quite fickle - var tilemap = get_node("./%TileMap") - # TODO: This goes wrong when overwriting old tiles with new sprites - # New pngs -> completely new tiles and rebuild map - var rect = tilemap.get_used_rect() - var cell_size = tilemap.cell_size - # TODO is fixed for camera issue in adjust horizontal - limit_right = rect.end.x * cell_size.x - 6 - limit_left = rect.position.x * cell_size.x + 6 - limit_top = rect.position.y * cell_size.y + 6 - limit_bottom = rect.end.y * cell_size.y - 6 - original_limit_left = limit_left - original_limit_right = limit_right - original_limit_top = limit_top - original_limit_bottom = limit_bottom - var screen_size = get_viewport_rect() - var h_pixels = limit_right - limit_left - var v_pixels = limit_bottom - limit_top - # TODO: Fix that it can zoom both? - if screen_size.end.x * original_x_zoom - h_pixels > 0: - zoom.x = h_pixels / screen_size.end.x - zoom.y = zoom.x - if screen_size.end.y * original_y_zoom - v_pixels > 0: - zoom.y = v_pixels / screen_size.end.y - zoom.x = zoom.y + screen_rect = get_viewport_rect().size + screen_rect.x *= zoom.x + screen_rect.y *= zoom.y + original_x_zoom = zoom.x + original_y_zoom = zoom.y + # This is ok, because it only happens on initialization + # But it is also quite fickle + var tilemap = get_node("./%TileMap") + # TODO: This goes wrong when overwriting old tiles with new sprites + # New pngs -> completely new tiles and rebuild map + var rect = tilemap.get_used_rect() + var cell_size = tilemap.cell_size + # TODO is fixed for camera issue in adjust horizontal + limit_right = rect.end.x * cell_size.x - 6 + limit_left = rect.position.x * cell_size.x + 6 + limit_top = rect.position.y * cell_size.y + 6 + limit_bottom = rect.end.y * cell_size.y - 6 + original_limit_left = limit_left + original_limit_right = limit_right + original_limit_top = limit_top + original_limit_bottom = limit_bottom + var screen_size = get_viewport_rect() + var h_pixels = limit_right - limit_left + var v_pixels = limit_bottom - limit_top + # TODO: Fix that it can zoom both? + if screen_size.end.x * original_x_zoom - h_pixels > 0: + zoom.x = h_pixels / screen_size.end.x + zoom.y = zoom.x + if screen_size.end.y * original_y_zoom - v_pixels > 0: + zoom.y = v_pixels / screen_size.end.y + zoom.x = zoom.y + # Smoothing the camera limits in godot ruins something func _adapt_to_movement(velocity: Vector2) -> void: - var offset_track - var center = get_camera_screen_center() - var left_edge_pos = center.x - screen_rect.x/2 + camera_horizontal_shift - var right_edge_pos = center.x + screen_rect.x/2 - camera_horizontal_shift - if(left_move_time >= offset_adapt_seconds && !anim_player.is_playing()): - left_move_time = 0 - target_offset.x = -camera_horizontal_shift - if(offset == target_offset): - return - offset_track = shiftLeft.find_track(".:offset") - shiftLeft.track_set_key_value(offset_track, 0, offset) - shiftLeft.track_set_key_value(offset_track, 1, target_offset) - camera_state = "shiftedLeft" - anim_player.play("shiftingLeft") - elif(right_move_time >= offset_adapt_seconds && !anim_player.is_playing()): - right_move_time = 0 - target_offset.x = camera_horizontal_shift - if(offset == target_offset): - return - offset_track = shiftRight.find_track(".:offset") - shiftRight.track_set_key_value(offset_track, 0, offset) - shiftRight.track_set_key_value(offset_track, 1, target_offset) - camera_state = "shiftedRight" - anim_player.play("shiftingRight") - elif(slow_time >= offset_reset_seconds && - !(Input.is_action_pressed("up") || Input.is_action_pressed("duck"))): - slow_time = 0 - target_offset.x = 0 - if(offset == target_offset): - return - if(left_edge_pos > limit_left && limit_right > right_edge_pos): - offset_track = shiftCenter.find_track(".:offset") - shiftCenter.track_set_key_value(offset_track, 0, offset) - shiftCenter.track_set_key_value(offset_track, 1, target_offset) - camera_state = "centered" - anim_player.play("shiftingCenter") - return + var offset_track + var center = get_camera_screen_center() + var left_edge_pos = center.x - screen_rect.x / 2 + camera_horizontal_shift + var right_edge_pos = center.x + screen_rect.x / 2 - camera_horizontal_shift + if left_move_time >= offset_adapt_seconds && !anim_player.is_playing(): + left_move_time = 0 + target_offset.x = -camera_horizontal_shift + if offset == target_offset: + return + offset_track = shiftLeft.find_track(".:offset") + shiftLeft.track_set_key_value(offset_track, 0, offset) + shiftLeft.track_set_key_value(offset_track, 1, target_offset) + camera_state = "shiftedLeft" + anim_player.play("shiftingLeft") + elif right_move_time >= offset_adapt_seconds && !anim_player.is_playing(): + right_move_time = 0 + target_offset.x = camera_horizontal_shift + if offset == target_offset: + return + offset_track = shiftRight.find_track(".:offset") + shiftRight.track_set_key_value(offset_track, 0, offset) + shiftRight.track_set_key_value(offset_track, 1, target_offset) + camera_state = "shiftedRight" + anim_player.play("shiftingRight") + elif ( + slow_time >= offset_reset_seconds + && !(Input.is_action_pressed("up") || Input.is_action_pressed("duck")) + ): + slow_time = 0 + target_offset.x = 0 + if offset == target_offset: + return + if left_edge_pos > limit_left && limit_right > right_edge_pos: + offset_track = shiftCenter.find_track(".:offset") + shiftCenter.track_set_key_value(offset_track, 0, offset) + shiftCenter.track_set_key_value(offset_track, 1, target_offset) + camera_state = "centered" + anim_player.play("shiftingCenter") + return + func _adapt_to_input(velocity: Vector2, delta: float) -> void: - # TODO Den bug dass man damit durch die map gucken kann wenn man sich weiter bewegt - # lasse ich erstmal drin - if(velocity.length() > 20.0): - input_time = 0 - return - if(input_time < offset_input_seconds): - input_time += delta - return - if Input.is_action_pressed("duck"): - if(original_limit_bottom - position.y - 2 > screen_bottom.y && offset.y < 48): - offset.y += 0.5 - elif Input.is_action_pressed("up"): - if(original_limit_top - position.y + 2 < screen_top.y && offset.y > -48): - offset.y -= 0.5 + # TODO Den bug dass man damit durch die map gucken kann wenn man sich weiter bewegt + # lasse ich erstmal drin + if velocity.length() > 20.0: + input_time = 0 + return + if input_time < offset_input_seconds: + input_time += delta + return + if Input.is_action_pressed("duck"): + if original_limit_bottom - position.y - 2 > screen_bottom.y && offset.y < 48: + offset.y += 0.5 + elif Input.is_action_pressed("up"): + if original_limit_top - position.y + 2 < screen_top.y && offset.y > -48: + offset.y -= 0.5 + # TODO This is a regulatory problem, it doesn't adapt fast enough # TODO Maybe just make background black and dont bother -func _adjust_offset(delta: float) -> bool: - var new_offset = offset - if (limit_left - position.x - screen_left.x > 0.1): - if (anim_player.is_playing()): - anim_player.stop(true) - new_offset.x += (limit_left - position.x - screen_left.x)/1.5 - if (limit_right - position.x - screen_right.x < 0.1): - if (anim_player.is_playing()): - anim_player.stop(true) - new_offset.x += (limit_right - position.x - screen_right.x)/1.5 - if (limit_top - position.y - screen_top.y > 0.001): - new_offset.y += (limit_top - position.y - screen_top.y)/1.5 - if (limit_bottom - position.y - screen_bottom.y < 0.001): - new_offset.y += (limit_bottom - position.y - screen_bottom.y)/1.5 - #print(abs(offset.x) - abs(new_offset.x)) - if(abs(offset.x) > abs(new_offset.x) || abs(offset.y) > abs(new_offset.y)): - offset = new_offset - return true - else: - return false - - +func _adjust_offset(delta: float) -> bool: + var new_offset = offset + if limit_left - position.x - screen_left.x > 0.1: + if anim_player.is_playing(): + anim_player.stop(true) + new_offset.x += (limit_left - position.x - screen_left.x) / 1.5 + if limit_right - position.x - screen_right.x < 0.1: + if anim_player.is_playing(): + anim_player.stop(true) + new_offset.x += (limit_right - position.x - screen_right.x) / 1.5 + if limit_top - position.y - screen_top.y > 0.001: + new_offset.y += (limit_top - position.y - screen_top.y) / 1.5 + if limit_bottom - position.y - screen_bottom.y < 0.001: + new_offset.y += (limit_bottom - position.y - screen_bottom.y) / 1.5 + #print(abs(offset.x) - abs(new_offset.x)) + if abs(offset.x) > abs(new_offset.x) || abs(offset.y) > abs(new_offset.y): + offset = new_offset + return true + else: + return false + + func reset_limits() -> void: - limit_left = original_limit_left - limit_right = original_limit_right - limit_bottom = original_limit_bottom - limit_top = original_limit_top + limit_left = original_limit_left + limit_right = original_limit_right + limit_bottom = original_limit_bottom + limit_top = original_limit_top + func _death_cam(animation_number: int = 0) -> void: - if(animation_number < 1): - $CameraAnimationPlayer.play("deathCamJustZoom") - if(animation_number == 1): - $CameraAnimationPlayer.play("deathCamLateRotation") + if animation_number < 1: + $CameraAnimationPlayer.play("deathCamJustZoom") + if animation_number == 1: + $CameraAnimationPlayer.play("deathCamLateRotation") + # TODO Rename to alarm lights specially func _update_lighting_shader() -> void: - if !terminal_activated: return - # Props to gameendaevour - # TODO get this into a central world update management system - var lights = get_tree().get_nodes_in_group("light") - image.lock() - for i in lights.size(): - var light = lights[i] - # TODO To make the lighting affect all layers properly - # I would have the access the global positions of nodes in different Z layers - # without the projection to the global center layer. + if !terminal_activated: + return + # Props to gameendaevour + # TODO get this into a central world update management system + var lights = get_tree().get_nodes_in_group("light") + image.lock() + for i in lights.size(): + var light = lights[i] + # TODO To make the lighting affect all layers properly + # I would have the access the global positions of nodes in different Z layers + # without the projection to the global center layer. - # var vtrans = get_canvas_transform() - # var top_left = -vtrans.origin / vtrans.get_scale() - # var vsize = get_viewport_rect().size - # var t = Transform2D(0, (top_left + 0.5*vsize/vtrans.get_scale()).rotated(rotation)) - image.set_pixel(i, 0, Color( - light.position.x, light.position.y, - light.strength, light.radius - )) - image.set_pixel(i, 1, light.color) - image.unlock() + # var vtrans = get_canvas_transform() + # var top_left = -vtrans.origin / vtrans.get_scale() + # var vsize = get_viewport_rect().size + # var t = Transform2D(0, (top_left + 0.5*vsize/vtrans.get_scale()).rotated(rotation)) + image.set_pixel( + i, 0, Color(light.position.x, light.position.y, light.strength, light.radius) + ) + image.set_pixel(i, 1, light.color) + image.unlock() - texture.create_from_image(image) + texture.create_from_image(image) - material.set_shader_param("n_lights", lights.size()) - material.set_shader_param("light_data", texture) - material.set_shader_param("global_transform", get_global_transform()) - material.set_shader_param("viewport_transform", get_viewport_transform()) + material.set_shader_param("n_lights", lights.size()) + material.set_shader_param("light_data", texture) + material.set_shader_param("global_transform", get_global_transform()) + material.set_shader_param("viewport_transform", get_viewport_transform()) diff --git a/src/Actors/Enemies/Caterpillar.gd b/src/Actors/Enemies/Caterpillar.gd index 9526d24..1252839 100644 --- a/src/Actors/Enemies/Caterpillar.gd +++ b/src/Actors/Enemies/Caterpillar.gd @@ -9,20 +9,29 @@ export var block_size := 16 var time = 0 var snap = Vector2.DOWN * block_size + func _ready() -> void: - velocity.x = -120 + velocity.x = -120 + func execute_movement(delta: float) -> void: - # rotation - var movement = max(0,sign(sin(time*15))) - if(left_src.is_colliding() && right_src.is_colliding() && !left_wrc.is_colliding() && !right_wrc.is_colliding()): - pass - elif(left_wrc.is_colliding() || (!right_src.is_colliding() && left_src.is_colliding())): - rotation += delta * 7 * movement - else: - rotation += sign(velocity.x) * delta * 7 * movement - - # velocity - var v = Vector2(velocity.x * movement, 0) - time += delta - move_and_slide_with_snap(v.rotated(rotation), snap.rotated(rotation), FLOOR_NORMAL, false, 4, PI, false) + # rotation + var movement = max(0, sign(sin(time * 15))) + if ( + left_src.is_colliding() + && right_src.is_colliding() + && !left_wrc.is_colliding() + && !right_wrc.is_colliding() + ): + pass + elif left_wrc.is_colliding() || (!right_src.is_colliding() && left_src.is_colliding()): + rotation += delta * 7 * movement + else: + rotation += sign(velocity.x) * delta * 7 * movement + + # velocity + var v = Vector2(velocity.x * movement, 0) + time += delta + move_and_slide_with_snap( + v.rotated(rotation), snap.rotated(rotation), FLOOR_NORMAL, false, 4, PI, false + ) diff --git a/src/Actors/Enemies/Enemy.gd b/src/Actors/Enemies/Enemy.gd index 88d7188..4b72eba 100644 --- a/src/Actors/Enemies/Enemy.gd +++ b/src/Actors/Enemies/Enemy.gd @@ -3,31 +3,35 @@ class_name Enemy var player_entered_stomp = false + func _on_StompDetector_body_entered(body: Node) -> void: - if !body.is_in_group("player"): - return - player_entered_stomp = true - var incoming_vel_vector: Vector2 = body.velocity.normalized() - print(rad2deg(abs(incoming_vel_vector.angle_to(Vector2.DOWN.rotated(rotation))))) - if abs(incoming_vel_vector.angle_to(Vector2.DOWN.rotated(rotation))) > deg2rad(95): - print("too shallow entry") - body.die() - player_entered_stomp = false - return - signal_manager.emit_signal("got_stomped") - remove_from_group("harmful") - $StompDetector.remove_from_group("weakpoint") - get_node("EnemyBody").disabled = true - die() + if !body.is_in_group("player"): + return + player_entered_stomp = true + var incoming_vel_vector: Vector2 = body.velocity.normalized() + print(rad2deg(abs(incoming_vel_vector.angle_to(Vector2.DOWN.rotated(rotation))))) + if abs(incoming_vel_vector.angle_to(Vector2.DOWN.rotated(rotation))) > deg2rad(95): + print("too shallow entry") + body.die() + player_entered_stomp = false + return + signal_manager.emit_signal("got_stomped") + remove_from_group("harmful") + $StompDetector.remove_from_group("weakpoint") + get_node("EnemyBody").disabled = true + die() + func die() -> void: - queue_free() + queue_free() + + +func _on_EnemySkin_area_entered(area: Area2D) -> void: + if area.is_in_group("harmful"): + get_node("EnemyBody").disabled = true + die() + -func _on_EnemySkin_area_entered(area:Area2D) -> void: - if area.is_in_group("harmful"): - get_node("EnemyBody").disabled = true - die() - func _on_EnemySkin_body_entered(body: Node) -> void: - if body.is_in_group("player") && !player_entered_stomp: - body.die() + if body.is_in_group("player") && !player_entered_stomp: + body.die() diff --git a/src/Actors/Friendlies/WhatAreFrog.gd b/src/Actors/Friendlies/WhatAreFrog.gd index ecc2b76..0a7614d 100644 --- a/src/Actors/Friendlies/WhatAreFrog.gd +++ b/src/Actors/Friendlies/WhatAreFrog.gd @@ -3,9 +3,8 @@ const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd") onready var players = get_tree().get_nodes_in_group("player") - onready var vision_raycast: RayCast2D = $VisionRayCast -onready var orientation: RayCast2D = $Orientation +onready var orientation: RayCast2D = $Orientation onready var feeler_raycast: RayCast2D = $FeelerRayCast onready var tilemap: TileMap = $"../%TileMap" onready var state_machine = $Statemachine @@ -28,8 +27,6 @@ export var jump_time_standard_deviation := 0.1 # TODO Make constant for project export var block_size := 16 - - # Also in blocks var movement_radius: float var anchor: Node2D @@ -56,288 +53,319 @@ var attached_player = null func _ready(): - default_jump_distance = default_jump_distance * tilemap.cell_size.x - jump_timer = Timer.new() - jump_timer.set_one_shot(true) - jump_timer.connect("timeout", self, "jump") - target_lost_timer = Timer.new() - target_lost_timer.set_one_shot(true) - target_lost_timer.connect("timeout", self, "loose_target") - add_child(jump_timer) - add_child(target_lost_timer) - # TODO this is so bad ;_; - if(get_parent().name.begins_with("Bound")): - is_bound = true - else: - level_state.free_a_frog(frog_number) - level_state.register_frog(frog_number, !is_bound) - # TODO Stays harmless for now - #if(is_bound): add_to_group("harmful") + default_jump_distance = default_jump_distance * tilemap.cell_size.x + jump_timer = Timer.new() + jump_timer.set_one_shot(true) + jump_timer.connect("timeout", self, "jump") + target_lost_timer = Timer.new() + target_lost_timer.set_one_shot(true) + target_lost_timer.connect("timeout", self, "loose_target") + add_child(jump_timer) + add_child(target_lost_timer) + # TODO this is so bad ;_; + if get_parent().name.begins_with("Bound"): + is_bound = true + else: + level_state.free_a_frog(frog_number) + level_state.register_frog(frog_number, !is_bound) + # TODO Stays harmless for now + #if(is_bound): add_to_group("harmful") -func bind_to_anchor(anchor_node: Node2D, radius: float ) -> void: - anchor = anchor_node - movement_radius = radius * block_size - is_bound = true - # TODO multiple free frogs - $Digit.visible = true - $Digit.frame = frog_number - $LeashAnchor.visible = is_bound +func bind_to_anchor(anchor_node: Node2D, radius: float) -> void: + anchor = anchor_node + movement_radius = radius * block_size + is_bound = true + # TODO multiple free frogs + $Digit.visible = true + $Digit.frame = frog_number + $LeashAnchor.visible = is_bound func execute_movement(delta: float) -> void: - # Navigation2DServer.map_get_path() - current_delta = delta - # TODO what when the game runs really long and the float runs out of space? - # Achievment maybe lul - detect_timer += delta - velocity.y += _gravity * delta - if(is_bound): - var next_position = global_position + velocity * current_delta - var current_distance = global_position.distance_to(anchor.global_position) - var new_distance = next_position.distance_to(anchor.global_position) - # TODO Fix this in respects to x and y distances and movement dampening - # Maybe use mathemathematics or something idfc - if(current_distance >= movement_radius && new_distance > current_distance): - velocity.x = velocity.x * 0.8 - velocity.y = velocity.y * 0.8 - was_restricted = true - velocity = move_and_slide(velocity, FLOOR_NORMAL, false, 4, 0.785398, false) + # Navigation2DServer.map_get_path() + current_delta = delta + # TODO what when the game runs really long and the float runs out of space? + # Achievment maybe lul + detect_timer += delta + velocity.y += _gravity * delta + if is_bound: + var next_position = global_position + velocity * current_delta + var current_distance = global_position.distance_to(anchor.global_position) + var new_distance = next_position.distance_to(anchor.global_position) + # TODO Fix this in respects to x and y distances and movement dampening + # Maybe use mathemathematics or something idfc + if current_distance >= movement_radius && new_distance > current_distance: + velocity.x = velocity.x * 0.8 + velocity.y = velocity.y * 0.8 + was_restricted = true + velocity = move_and_slide(velocity, FLOOR_NORMAL, false, 4, 0.785398, false) - if($"%GroundDetector".get_overlapping_bodies().size() > 0): - velocity.y -= 10 * (delta/0.0083) - var min_x_slide_velocity = 50 * (delta/0.0083) - velocity.x = sign(velocity.x) * max(min_x_slide_velocity, velocity.x * 0.99) - return - elif(is_on_floor()): - velocity = Vector2(0,0) - - # Reverse direction when hitting limit + if $"%GroundDetector".get_overlapping_bodies().size() > 0: + velocity.y -= 10 * (delta / 0.0083) + var min_x_slide_velocity = 50 * (delta / 0.0083) + velocity.x = sign(velocity.x) * max(min_x_slide_velocity, velocity.x * 0.99) + return + elif is_on_floor(): + velocity = Vector2(0, 0) + + # Reverse direction when hitting limit func die() -> void: - queue_free() + queue_free() -func _on_EnemySkin_area_entered(area:Area2D) -> void: - if area.is_in_group("harmful") && !area.is_in_group("frogfood"): - get_node("EnemyBody").disabled = true - die() +func _on_EnemySkin_area_entered(area: Area2D) -> void: + if area.is_in_group("harmful") && !area.is_in_group("frogfood"): + get_node("EnemyBody").disabled = true + die() func _on_EnemySkin_body_entered(body: Node) -> void: - if body.is_in_group("frogfood"): - loose_target() - body.die() - + if body.is_in_group("frogfood"): + loose_target() + body.die() + func _on_StompDetector_body_entered(body: Node) -> void: - if body.is_in_group("player"): - attached_player = body - $FeelerRayCast.collision_mask -= 1 - if !body.is_in_group("player") || is_hurt: - return - var incoming_vel_vector: Vector2 = body.velocity.normalized() - # TODO This is not the right angle somehow + if body.is_in_group("player"): + attached_player = body + $FeelerRayCast.collision_mask -= 1 + if !body.is_in_group("player") || is_hurt: + return + var incoming_vel_vector: Vector2 = body.velocity.normalized() + # TODO This is not the right angle somehow # print(rad2deg(abs(incoming_vel_vector.angle_to(Vector2.DOWN.rotated(rotation))))) # if abs(incoming_vel_vector.angle_to(\Vector2.DOWN.rotated(rotation))) > deg2rad(60): # print("too shallow entry") # return - signal_manager.emit_signal("got_stomped") - remove_from_group("harmful") - # TODO Weakpoint group is not needed per se - $StompDetector.remove_from_group("weakpoint") - get_node("EnemyBody").disabled = true - is_hurt = true - $FrogSprite.material = invincible_shader - $HurtTimer.start() + signal_manager.emit_signal("got_stomped") + remove_from_group("harmful") + # TODO Weakpoint group is not needed per se + $StompDetector.remove_from_group("weakpoint") + get_node("EnemyBody").disabled = true + is_hurt = true + $FrogSprite.material = invincible_shader + $HurtTimer.start() + func _on_StompDetector_body_exited(body: Node) -> void: - if attached_player == body: - $FeelerRayCast.collision_mask += 1 - attached_player = null + if attached_player == body: + $FeelerRayCast.collision_mask += 1 + attached_player = null func searching() -> Vector2: - if(detect_timer > 0.333): - search_next_target() - detect_timer = 0.0 - if(is_on_floor()): - if(jump_timer.is_stopped()): - jump_timer.start(rng.randfn(jump_time_search, jump_time_standard_deviation)) - if(in_air): - in_air = false - else: - if(!in_air): - start_x = global_position.x - reversing_possible_searching = true - jump_timer.stop() - in_air = true - return velocity + if detect_timer > 0.333: + search_next_target() + detect_timer = 0.0 + if is_on_floor(): + if jump_timer.is_stopped(): + jump_timer.start(rng.randfn(jump_time_search, jump_time_standard_deviation)) + if in_air: + in_air = false + else: + if !in_air: + start_x = global_position.x + reversing_possible_searching = true + jump_timer.stop() + in_air = true + return velocity func search_next_target(): - if(target != null && !weakref(target).get_ref()): - return - detect_food() - if(food_target == null && is_bound): - detect_player() + if target != null && !weakref(target).get_ref(): + return + detect_food() + if food_target == null && is_bound: + detect_player() func hunting() -> Vector2: - var was_target_freed = !weakref(target).get_ref() - if(detect_timer > 0.333): - search_next_target() - detect_timer = 0.0 - #TODO Dependent on block size - elif(is_on_floor() && food_target != null && !was_target_freed && - global_position.distance_to(food_target.global_position) <= attack_jump_range * block_size): - - var collider = check_feeler(food_target.global_position - global_position) - if(!was_restricted && collider != null && collider.is_in_group("frogfood")): - jump_timer.stop() - return attack_jump(food_target.global_position) - - if(is_on_floor()): - if(jump_timer.is_stopped()): - jump_timer.start(rng.randfn(jump_time_hunt, jump_time_standard_deviation)) - if(in_air): - in_air = false - - else: - if(!in_air): - start_x = global_position.x - reversing_possible_searching = true - jump_timer.stop() - in_air = true + var was_target_freed = !weakref(target).get_ref() + if detect_timer > 0.333: + search_next_target() + detect_timer = 0.0 + #TODO Dependent on block size + elif ( + is_on_floor() + && food_target != null + && !was_target_freed + && ( + global_position.distance_to(food_target.global_position) + <= attack_jump_range * block_size + ) + ): + var collider = check_feeler(food_target.global_position - global_position) + if !was_restricted && collider != null && collider.is_in_group("frogfood"): + jump_timer.stop() + return attack_jump(food_target.global_position) - if(barely_held_back_counter > 1): - barely_held_back_counter = 0 - loose_target() + if is_on_floor(): + if jump_timer.is_stopped(): + jump_timer.start(rng.randfn(jump_time_hunt, jump_time_standard_deviation)) + if in_air: + in_air = false - if(target != null && !was_target_freed && - sign((target.global_position - global_position).x) != get_facing_direction()): - # TODO Waits in front of too small tunnels if it sees the target on the other side - # It's ok behavior for now - reverse_facing_direction() + else: + if !in_air: + start_x = global_position.x + reversing_possible_searching = true + jump_timer.stop() + in_air = true - return velocity + if barely_held_back_counter > 1: + barely_held_back_counter = 0 + loose_target() + + if ( + target != null + && !was_target_freed + && sign((target.global_position - global_position).x) != get_facing_direction() + ): + # TODO Waits in front of too small tunnels if it sees the target on the other side + # It's ok behavior for now + reverse_facing_direction() + + return velocity func detect_food() -> void: - # TODO What if food spawns in - food_sources = get_tree().get_nodes_in_group("frogfood") - if(food_sources.empty()): - return - var i = 0 - var min_dist_f_index = 0 - var min_dist = (food_sources[0].global_position - global_position).length() - var food_node = null - for f in food_sources: - var new_dist = (food_sources[i].global_position - global_position).length() - min_dist = new_dist if new_dist < min_dist else min_dist - min_dist_f_index = i if new_dist < min_dist else min_dist_f_index - i += 1 - food_node = food_sources[min_dist_f_index] - #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 - vision_raycast.cast_to = (food_node.global_position - global_position).normalized() * block_size * vision_distance - var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to) - vision_raycast.force_raycast_update() - var collider = vision_raycast.get_collider() - if(abs(ray_angle_to_facing) < PI/3 && collider != null && collider.is_in_group("frogfood")): - target_lost_timer.stop() - target = collider - food_target = collider - elif(target != null && target_lost_timer.is_stopped()): - target_lost_timer.start(loose_target_seconds) + # TODO What if food spawns in + food_sources = get_tree().get_nodes_in_group("frogfood") + if food_sources.empty(): + return + + #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 + var i = 0 + var min_dist_f_index = 0 + var min_dist = (food_sources[0].global_position - global_position).length() + var food_node = null + for f in food_sources: + var new_dist = (food_sources[i].global_position - global_position).length() + min_dist = new_dist if new_dist < min_dist else min_dist + min_dist_f_index = i if new_dist < min_dist else min_dist_f_index + i += 1 + + #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 + food_node = food_sources[min_dist_f_index] + #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 + vision_raycast.cast_to = ( + (food_node.global_position - global_position).normalized() + * block_size + * vision_distance + ) + var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to) + vision_raycast.force_raycast_update() + var collider = vision_raycast.get_collider() + if abs(ray_angle_to_facing) < PI / 3 && collider != null && collider.is_in_group("frogfood"): + target_lost_timer.stop() + target = collider + food_target = collider + elif target != null && target_lost_timer.is_stopped(): + target_lost_timer.start(loose_target_seconds) func detect_player() -> void: - var player - if(players.empty()): - # print("no player found") - return - player = players[0] - #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 - vision_raycast.cast_to = (player.global_position - global_position - Vector2(0, 9)).normalized() * block_size * vision_distance - var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to) - vision_raycast.force_raycast_update() - var collider = vision_raycast.get_collider() - if(abs(ray_angle_to_facing) < PI/4 && collider != null && collider.is_in_group("player")): - target_lost_timer.stop() - target = collider - elif(target != null && target_lost_timer.is_stopped()): - target_lost_timer.start(loose_target_seconds) + var player + if players.empty(): + # print("no player found") + return + + #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 + player = players[0] + #TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0 + vision_raycast.cast_to = ( + (player.global_position - global_position - Vector2(0, 9)).normalized() + * block_size + * vision_distance + ) + var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to) + vision_raycast.force_raycast_update() + var collider = vision_raycast.get_collider() + if abs(ray_angle_to_facing) < PI / 4 && collider != null && collider.is_in_group("player"): + target_lost_timer.stop() + target = collider + elif target != null && target_lost_timer.is_stopped(): + target_lost_timer.start(loose_target_seconds) func sleeping() -> Vector2: - jump_timer.stop() - # detect_player() - return velocity + jump_timer.stop() + # detect_player() + return velocity func loose_target() -> void: - # print("frog target lost") - target = null - food_target = null + # print("frog target lost") + target = null + food_target = null func jump(): - # print("jump calculation initiated") - # Can only reverse once per jump calculation - has_reversed = false - var zero_vector = Vector2(0,0) - var v: Vector2 = velocity_for_jump_distance(default_jump_distance, deg2rad(default_jump_angle)) - v = correct_jump_direction(v) + # print("jump calculation initiated") + # Can only reverse once per jump calculation + has_reversed = false + var zero_vector = Vector2(0, 0) + var v: Vector2 = velocity_for_jump_distance(default_jump_distance, deg2rad(default_jump_angle)) + v = correct_jump_direction(v) + + if is_bound: + var next_position = global_position + v * current_delta + var current_distance = global_position.distance_to(anchor.global_position) + var new_distance = next_position.distance_to(anchor.global_position) + # print(current_distance) + # print(new_distance) + # Would go out of distance + if ( + (new_distance >= movement_radius && new_distance > current_distance) + || (new_distance > current_distance && was_restricted) + ): + if state_machine.state == "hunting": + barely_held_back_counter += 1 + if ( + can_reverse_facing_direction() + && (barely_held_back_counter == 0 || barely_held_back_counter > 1) + ): + reverse_facing_direction() + was_restricted = false + + if $Right_Wallcast.is_colliding() && $Left_Wallcast.is_colliding(): + # TODO No idea what it might do in these situations + print("help this is a really tight space :(") + elif get_facing_direction() < 0 && $Left_Wallcast.is_colliding(): + v = zero_vector + elif get_facing_direction() > 0 && $Right_Wallcast.is_colliding(): + v = zero_vector + + v = correct_jump_direction(v) + if v != zero_vector: + v = consider_jump_headspace(v) + if v != zero_vector: + v = consider_jump_landing_space(v) + if v == zero_vector: + # TODO fix that you could call jump from jumping on top + # and let it fail if the top is dangerous for jump height or not safe + v = consider_jumping_on_top() + if v == zero_vector && can_reverse_facing_direction(): + reverse_facing_direction() - if(is_bound): - var next_position = global_position + v * current_delta - var current_distance = global_position.distance_to(anchor.global_position) - var new_distance = next_position.distance_to(anchor.global_position) - # print(current_distance) - # print(new_distance) - # Would go out of distance - if((new_distance >= movement_radius && new_distance > current_distance) || (new_distance > current_distance && was_restricted)): - if(state_machine.state == "hunting"): - barely_held_back_counter += 1 - if can_reverse_facing_direction() && (barely_held_back_counter == 0 || barely_held_back_counter > 1): - reverse_facing_direction() - was_restricted = false - - if ($Right_Wallcast.is_colliding() && $Left_Wallcast.is_colliding()): - # TODO No idea what it might do in these situations - print("help this is a really tight space :(") - elif (get_facing_direction() < 0 && $Left_Wallcast.is_colliding()): - v = zero_vector - elif (get_facing_direction() > 0 && $Right_Wallcast.is_colliding()): - v = zero_vector - - - v = correct_jump_direction(v) - if(v != zero_vector): - v = consider_jump_headspace(v) - if(v != zero_vector): - v = consider_jump_landing_space(v) - if(v == zero_vector): - # TODO fix that you could call jump from jumping on top - # and let it fail if the top is dangerous for jump height or not safe - v = consider_jumping_on_top() - if(v == zero_vector && can_reverse_facing_direction()): - reverse_facing_direction() - # if attached_player != null && v != zero_vector: # move_with_player(v) - - velocity = v + + velocity = v + #func move_with_player(v: Vector2): # print(v) # attached_player.move_and_slide(v * 10) + func correct_jump_direction(v: Vector2) -> Vector2: - if sign(v.x) != get_facing_direction(): - v.x *= -1 - return v + if sign(v.x) != get_facing_direction(): + v.x *= -1 + return v # Cast a ray to the highest point of the jump @@ -345,215 +373,245 @@ func correct_jump_direction(v: Vector2) -> Vector2: # Calculate safe jump height and then a safe jump velocity # Returns 0,0 if theres no headspace func consider_jump_headspace(v: Vector2, recursive_check_count = 0, max_checks = 2) -> Vector2: - if recursive_check_count >= max_checks: - print("Frog has no safe headspace") - return Vector2(0,0) - var height = calculate_jump_height(v) - var distance = calculate_jump_distance(v) - var angle = (v * get_facing_direction()).angle() - # Half distance is an estimate of the jumps apex() - #TODO Consider sprite size for height - var height_collider = check_feeler(Vector2(get_facing_direction()*(distance/2), -(height+23))) - if(height_collider != null): - var collision_point = feeler_raycast.get_collision_point() - var target_height = collision_point.y - (feeler_raycast.global_position.y - 23) - # print(feeler_raycast.global_position) - var new_angle = angle * (0.75 if target_height > -26 else 0.95) - var new_distance = abs(distance) * (0.66 if target_height < -26 else 0.75) - v = velocity_for_jump_distance(new_distance, abs(new_angle)) - v = correct_jump_direction(v) - height = calculate_jump_height(v) * -1 - distance = calculate_jump_distance(v) * get_facing_direction() - if(height < target_height && can_reverse_facing_direction()): - v = consider_jump_headspace(v, recursive_check_count + 1) - return v + if recursive_check_count >= max_checks: + print("Frog has no safe headspace") + return Vector2(0, 0) + var height = calculate_jump_height(v) + var distance = calculate_jump_distance(v) + var angle = (v * get_facing_direction()).angle() + # Half distance is an estimate of the jumps apex() + #TODO Consider sprite size for height + var height_collider = check_feeler( + Vector2(get_facing_direction() * (distance / 2), -(height + 23)) + ) + if height_collider != null: + var collision_point = feeler_raycast.get_collision_point() + var target_height = collision_point.y - (feeler_raycast.global_position.y - 23) + # print(feeler_raycast.global_position) + var new_angle = angle * (0.75 if target_height > -26 else 0.95) + var new_distance = abs(distance) * (0.66 if target_height < -26 else 0.75) + v = velocity_for_jump_distance(new_distance, abs(new_angle)) + v = correct_jump_direction(v) + height = calculate_jump_height(v) * -1 + distance = calculate_jump_distance(v) * get_facing_direction() + if height < target_height && can_reverse_facing_direction(): + v = consider_jump_headspace(v, recursive_check_count + 1) + return v # Check the block in jump distance for danger or height # If danger check neighboring blocks: if still danger, then jump closer (or jump over) # If height move to distance which allows 1 block high jump func consider_jump_landing_space(v: Vector2) -> Vector2: - var jump_distance = calculate_jump_distance(v) - var jump_height = calculate_jump_height(v) - var collider = check_feeler(Vector2(jump_distance * get_facing_direction(), - jump_height/2)) - # TODO Unpacked loop, make function or something? - # Shortens the jump in steps to make it more safe - if(!is_jump_path_safe(v, global_position) || collider != null): - jump_distance = calculate_jump_distance(v) - block_size/1.5 - v = change_jump_distance(jump_distance, v) - jump_height = calculate_jump_height(v) - v = correct_jump_direction(v) - collider = check_feeler(Vector2(jump_distance * get_facing_direction(), - jump_height/2)) - if(!is_jump_path_safe(v, global_position) || collider != null): - jump_distance = calculate_jump_distance(v) - block_size/2.0 - v = change_jump_distance(jump_distance, v) - jump_height = calculate_jump_height(v) - v = correct_jump_direction(v) - collider = check_feeler(Vector2(jump_distance * get_facing_direction(), - jump_height/2)) - if((!is_jump_path_safe(v, global_position) || collider != null) && can_reverse_facing_direction()): - # Can be printed when frog would jump into a wall too - print("at wall or no safe landing spot") - return Vector2(0,0) - return v + var jump_distance = calculate_jump_distance(v) + var jump_height = calculate_jump_height(v) + var collider = check_feeler(Vector2(jump_distance * get_facing_direction(), -jump_height / 2)) + # TODO Unpacked loop, make function or something? + # Shortens the jump in steps to make it more safe + if !is_jump_path_safe(v, global_position) || collider != null: + jump_distance = calculate_jump_distance(v) - block_size / 1.5 + v = change_jump_distance(jump_distance, v) + jump_height = calculate_jump_height(v) + v = correct_jump_direction(v) + collider = check_feeler(Vector2(jump_distance * get_facing_direction(), -jump_height / 2)) + if !is_jump_path_safe(v, global_position) || collider != null: + jump_distance = calculate_jump_distance(v) - block_size / 2.0 + v = change_jump_distance(jump_distance, v) + jump_height = calculate_jump_height(v) + v = correct_jump_direction(v) + collider = check_feeler(Vector2(jump_distance * get_facing_direction(), -jump_height / 2)) + if ( + (!is_jump_path_safe(v, global_position) || collider != null) + && can_reverse_facing_direction() + ): + # Can be printed when frog would jump into a wall too + print("at wall or no safe landing spot") + return Vector2(0, 0) + return v func consider_jumping_on_top() -> Vector2: - var collider = check_feeler(Vector2(42 * get_facing_direction(),0)) - # 0 just for tile coordinate calculation - var facing = 0 if get_facing_direction() >= 0 else - 1 - if (collider == null): - return Vector2(0,0) - var local_position = tilemap.to_local(feeler_raycast.get_collision_point()) - var map_position = tilemap.world_to_map(local_position) - var tile_position = Vector2(map_position.x + facing, map_position.y - 1) - # TODO Here the climb height of frog is limited to one constantly - var cell_id = tilemap.get_cell(tile_position.x, tile_position.y - 1) - if (cell_id != -1 && - #TODO 0 is the navigation tile, but thats subject to change! - cell_id != 7): - return Vector2(0,0) - var tile_upper_left_corner = tilemap.to_global(tilemap.map_to_world(tile_position)) - var tile_upper_right_corner = Vector2(tile_upper_left_corner.x + tilemap.cell_size.x, tile_upper_left_corner.y) - - var jump_angle = 0 - if(facing < 0): - var frog_bottom_left_corner = Vector2($EnemyBody.global_position.x - $EnemyBody.shape.extents.x, - $EnemyBody.global_position.y + $EnemyBody.shape.extents.y) - jump_angle = frog_bottom_left_corner.angle_to_point(tile_upper_right_corner) - else: - var frog_bottom_right_corner = Vector2($EnemyBody.global_position.x + $EnemyBody.shape.extents.x, - $EnemyBody.global_position.y + $EnemyBody.shape.extents.y) - jump_angle = frog_bottom_right_corner.angle_to_point(tile_upper_left_corner) - PI - - if(abs(rad2deg(jump_angle)) < 78): - return correct_jump_direction(velocity_for_jump_distance(default_jump_distance/2, abs(deg2rad(80)))) - else: - var v = velocity_for_jump_distance(block_size/1.5, abs(deg2rad(45))) - return Vector2(v.x * -1 * get_facing_direction(), v.y) + var collider = check_feeler(Vector2(42 * get_facing_direction(), 0)) + # 0 just for tile coordinate calculation + var facing = 0 if get_facing_direction() >= 0 else -1 + if collider == null: + return Vector2(0, 0) + var local_position = tilemap.to_local(feeler_raycast.get_collision_point()) + var map_position = tilemap.world_to_map(local_position) + var tile_position = Vector2(map_position.x + facing, map_position.y - 1) + # TODO Here the climb height of frog is limited to one constantly + var cell_id = tilemap.get_cell(tile_position.x, tile_position.y - 1) + if ( + cell_id != -1 + #TODO 0 is the navigation tile, but thats subject to change! + && cell_id != 7 + ): + return Vector2(0, 0) + var tile_upper_left_corner = tilemap.to_global(tilemap.map_to_world(tile_position)) + var tile_upper_right_corner = Vector2( + tile_upper_left_corner.x + tilemap.cell_size.x, tile_upper_left_corner.y + ) + + var jump_angle = 0 + if facing < 0: + var frog_bottom_left_corner = Vector2( + $EnemyBody.global_position.x - $EnemyBody.shape.extents.x, + $EnemyBody.global_position.y + $EnemyBody.shape.extents.y + ) + jump_angle = frog_bottom_left_corner.angle_to_point(tile_upper_right_corner) + else: + var frog_bottom_right_corner = Vector2( + $EnemyBody.global_position.x + $EnemyBody.shape.extents.x, + $EnemyBody.global_position.y + $EnemyBody.shape.extents.y + ) + jump_angle = frog_bottom_right_corner.angle_to_point(tile_upper_left_corner) - PI + + if abs(rad2deg(jump_angle)) < 78: + return correct_jump_direction( + velocity_for_jump_distance(default_jump_distance / 2, abs(deg2rad(80))) + ) + else: + var v = velocity_for_jump_distance(block_size / 1.5, abs(deg2rad(45))) + return Vector2(v.x * -1 * get_facing_direction(), v.y) # Tries to shorten the jump, so that it lands in a tiles center func jump_to_tile_center(v: Vector2) -> Vector2: - var distance = stepify(calculate_jump_distance(v), 0.01) - if !is_equal_approx(fmod(abs(global_position.x + distance * get_facing_direction()), block_size), (block_size/2.0)): - # print(distance) - # print(global_position.x + distance) - # print(fmod((global_position.x + distance), block_size)) - var new_distance = distance - if(get_facing_direction() < 0): - new_distance = fmod((global_position.x + distance), block_size) - (block_size/2.0) + distance - else: - new_distance = distance + block_size/2.0 - fmod((global_position.x + distance), block_size) - # print("centering distance") - # print(new_distance) - v = change_jump_distance(abs(new_distance), v) - v = correct_jump_direction(v) - return v + var distance = stepify(calculate_jump_distance(v), 0.01) + if !is_equal_approx( + fmod(abs(global_position.x + distance * get_facing_direction()), block_size), + block_size / 2.0 + ): + # print(distance) + # print(global_position.x + distance) + # print(fmod((global_position.x + distance), block_size)) + var new_distance = distance + if get_facing_direction() < 0: + new_distance = ( + fmod(global_position.x + distance, block_size) + - (block_size / 2.0) + + distance + ) + else: + new_distance = ( + distance + + block_size / 2.0 + - fmod(global_position.x + distance, block_size) + ) + # print("centering distance") + # print(new_distance) + v = change_jump_distance(abs(new_distance), v) + v = correct_jump_direction(v) + return v # TODO Depends on Frog Shape and Tile Shape func is_jump_path_safe(v: Vector2, pos: Vector2) -> bool: - var v0 = v.length() - var angle = v.angle() - var jump_distance = calculate_jump_distance(v) - var harmful_nodes = get_tree().get_nodes_in_group("harmful") - harmful_nodes.append_array(get_tree().get_nodes_in_group("pit")) - for node in harmful_nodes: - var node_pos = node.global_position - # TODO Ignores spikes more than 4 blocks below and 3 jumps away - # Also when its too near to one - if (abs(node_pos.x - pos.x) > abs(jump_distance) * 3 - ||abs(node_pos.y - pos.y) > block_size * 4 - || abs(node_pos.x - pos.x) < 1): - continue - var node_y = node_pos.y - block_size/2.0 - var initial_throw_height = node_y - (global_position.y + 9) - var term1 = (pow(v0, 2) * sin(2 * angle)) / (2 * _gravity) - var term2 = ((v0 * cos(angle))/_gravity) * sqrt(pow(v0, 2) * pow(sin(angle), 2) + 2 * _gravity * initial_throw_height) - var distance = abs(term1) + abs(term2) - # print("distance to next spike") - # print(pos.x + sign(v.x) * distance - node_pos.x) - var safe_distance = block_size/2.0 - if (sign(initial_throw_height) < 0): - safe_distance = block_size - if(abs(pos.x + sign(v.x) * distance - node_pos.x) < safe_distance): - return false - return true + var v0 = v.length() + var angle = v.angle() + var jump_distance = calculate_jump_distance(v) + var harmful_nodes = get_tree().get_nodes_in_group("harmful") + harmful_nodes.append_array(get_tree().get_nodes_in_group("pit")) + for node in harmful_nodes: + var node_pos = node.global_position + # TODO Ignores spikes more than 4 blocks below and 3 jumps away + # Also when its too near to one + if ( + abs(node_pos.x - pos.x) > abs(jump_distance) * 3 + || abs(node_pos.y - pos.y) > block_size * 4 + || abs(node_pos.x - pos.x) < 1 + ): + continue + var node_y = node_pos.y - block_size / 2.0 + var initial_throw_height = node_y - (global_position.y + 9) + var term1 = (pow(v0, 2) * sin(2 * angle)) / (2 * _gravity) + var term2 = ( + ((v0 * cos(angle)) / _gravity) + * sqrt(pow(v0, 2) * pow(sin(angle), 2) + 2 * _gravity * initial_throw_height) + ) + var distance = abs(term1) + abs(term2) + # print("distance to next spike") + # print(pos.x + sign(v.x) * distance - node_pos.x) + var safe_distance = block_size / 2.0 + if sign(initial_throw_height) < 0: + safe_distance = block_size + if abs(pos.x + sign(v.x) * distance - node_pos.x) < safe_distance: + return false + return true func calculate_jump_height(v: Vector2) -> float: - return abs((pow(v.length(), 2) * pow(sin(v.angle()), 2))/(2*_gravity)) + return abs((pow(v.length(), 2) * pow(sin(v.angle()), 2)) / (2 * _gravity)) # Only works for jumps on straight ground func calculate_jump_distance(v: Vector2) -> float: - return abs((pow(v.length(), 2) * sin(-1 * 2 * v.angle()))/(_gravity)) + return abs((pow(v.length(), 2) * sin(-1 * 2 * v.angle())) / (_gravity)) func jump_height_to_velocity(target_height: float, v: Vector2) -> Vector2: - var initial_height = calculate_jump_height(v) - return v.normalized() * sqrt(pow(v.length(),2)/(initial_height/target_height)) + var initial_height = calculate_jump_height(v) + return v.normalized() * sqrt(pow(v.length(), 2) / (initial_height / target_height)) # Changes a Vector for a jump to the targeted distance, keeping the angle func change_jump_distance(target_distance: float, v: Vector2) -> Vector2: - var initial_distance = calculate_jump_distance(v) - return v.normalized() * sqrt(pow(v.length(),2)/(initial_distance/target_distance)) + var initial_distance = calculate_jump_distance(v) + return v.normalized() * sqrt(pow(v.length(), 2) / (initial_distance / target_distance)) # Takes an angle and a distance to calculate a jump launching at that angle and covering the distance -func velocity_for_jump_distance(distance: float = default_jump_distance*block_size, angle: float = deg2rad(default_jump_angle)) -> Vector2: - var abs_velocity = sqrt((distance * _gravity)/sin(2*angle)) - return Vector2(abs_velocity,0).rotated(-1*angle) +func velocity_for_jump_distance( + distance: float = default_jump_distance * block_size, angle: float = deg2rad(default_jump_angle) +) -> Vector2: + var abs_velocity = sqrt((distance * _gravity) / sin(2 * angle)) + return Vector2(abs_velocity, 0).rotated(-1 * angle) func can_reverse_facing_direction() -> bool: - if(is_on_floor() && !has_reversed): - return true - return false + if is_on_floor() && !has_reversed: + return true + return false # Returns a jump velocity that has the target_position in it's path func attack_jump(target_position: Vector2) -> Vector2: - var target_vector = target_position - global_position - target_vector = Vector2(abs(target_vector.x), target_vector.y) - var jump_angle = target_vector.angle() - var v = Vector2() - # TODO Tunable parameters - if jump_angle < deg2rad(-30): - v = velocity_for_jump_distance(target_vector.x, deg2rad(default_jump_angle)) - v = jump_height_to_velocity(abs(target_vector.y), v) - else: - v = velocity_for_jump_distance(target_vector.x * 1.5,deg2rad(45)) - v = correct_jump_direction(v) - return v + var target_vector = target_position - global_position + target_vector = Vector2(abs(target_vector.x), target_vector.y) + var jump_angle = target_vector.angle() + var v = Vector2() + # TODO Tunable parameters + if jump_angle < deg2rad(-30): + v = velocity_for_jump_distance(target_vector.x, deg2rad(default_jump_angle)) + v = jump_height_to_velocity(abs(target_vector.y), v) + else: + v = velocity_for_jump_distance(target_vector.x * 1.5, deg2rad(45)) + v = correct_jump_direction(v) + return v # Checks the feeler ray for collisions and returns collider or null -func check_feeler(v: Vector2, _offset = Vector2(0,0)) -> Object: - var prev_position = feeler_raycast.position - feeler_raycast.position += _offset - feeler_raycast.cast_to = v - feeler_raycast.force_raycast_update() - var collider = feeler_raycast.get_collider() - feeler_raycast.position = prev_position - return collider +func check_feeler(v: Vector2, _offset = Vector2(0, 0)) -> Object: + var prev_position = feeler_raycast.position + feeler_raycast.position += _offset + feeler_raycast.cast_to = v + feeler_raycast.force_raycast_update() + var collider = feeler_raycast.get_collider() + feeler_raycast.position = prev_position + return collider func reverse_facing_direction() -> void: - has_reversed = true - # print("reversing direction") - orientation.cast_to.x *= -1 + has_reversed = true + # print("reversing direction") + orientation.cast_to.x *= -1 func get_facing_direction() -> float: - return orientation.cast_to.x + return orientation.cast_to.x func _on_HurtTimer_timeout() -> void: - is_hurt = false - #if(is_bound): add_to_group("harmful") - $FrogSprite.material = null - - - + is_hurt = false + #if(is_bound): add_to_group("harmful") + $FrogSprite.material = null diff --git a/src/Levels/1 Tutorial Level.tscn b/src/Levels/1 Tutorial Level.tscn index e908194..8900dbc 100644 --- a/src/Levels/1 Tutorial Level.tscn +++ b/src/Levels/1 Tutorial Level.tscn @@ -212,6 +212,9 @@ unique_name_in_owner = true position = Vector2( -70, 1 ) scale = Vector2( 0.878906, 0.936025 ) +[node name="BlobbySprite" parent="Blobby" index="5"] +frame = 8 + [node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"] parameters/playback = SubResource( 14 ) parameters/jumpStretching/blend_position = 1 diff --git a/src/Levels/2 Tutorial Level.tscn b/src/Levels/2 Tutorial Level.tscn index e04cfe8..79f169e 100644 --- a/src/Levels/2 Tutorial Level.tscn +++ b/src/Levels/2 Tutorial Level.tscn @@ -1040,7 +1040,7 @@ position = Vector2( -156, -51 ) scale = Vector2( 0.878906, 0.936025 ) [node name="BlobbySprite" parent="Blobby" index="5"] -frame = 6 +frame = 5 [node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"] parameters/playback = SubResource( 6 ) diff --git a/src/Levels/Actual Level 1.tscn b/src/Levels/Actual Level 1.tscn index 5b6311a..ca68379 100644 --- a/src/Levels/Actual Level 1.tscn +++ b/src/Levels/Actual Level 1.tscn @@ -44,17 +44,14 @@ wait_time = 20.0 [node name="BlobbyCam" parent="." instance=ExtResource( 9 )] unique_name_in_owner = true -[node name="AnimatedSprite" parent="BlobbyCam/ParallaxBackground/ParallaxLayer5" index="4"] -frame = 13 - -[node name="AnimatedSprite2" parent="BlobbyCam/ParallaxBackground/ParallaxLayer5" index="5"] -frame = 3 - [node name="Blobby" parent="." instance=ExtResource( 15 )] unique_name_in_owner = true position = Vector2( 251, -24 ) scale = Vector2( 0.878906, 0.936025 ) +[node name="BlobbySprite" parent="Blobby" index="5"] +frame = 6 + [node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"] parameters/playback = SubResource( 1 ) diff --git a/src/Levels/Templates/LevelTemplate.gd b/src/Levels/Templates/LevelTemplate.gd index 31c7513..e88746f 100644 --- a/src/Levels/Templates/LevelTemplate.gd +++ b/src/Levels/Templates/LevelTemplate.gd @@ -5,8 +5,8 @@ onready var signal_manager := $"%SignalManager" onready var level_state := $"%LevelState" func _ready() -> void: - # should spawn the tutorial thingies which are still remembered in the progress dictionary - signal_manager.emit_signal("level_loaded") - get_tree().paused = false - - + # should spawn the tutorial thingies which are still remembered in the progress dictionary + signal_manager.emit_signal("level_loaded") + get_tree().paused = false + + diff --git a/src/Sounds/default_bus_layout.tres b/src/Sounds/default_bus_layout.tres index 647ba66..1028d26 100644 --- a/src/Sounds/default_bus_layout.tres +++ b/src/Sounds/default_bus_layout.tres @@ -41,12 +41,12 @@ resource_name = "LowPassFilter" cutoff_hz = 3000.0 [resource] -bus/0/volume_db = -6.0206 +bus/0/volume_db = -10.4576 bus/1/name = "Music" bus/1/solo = false bus/1/mute = false bus/1/bypass_fx = false -bus/1/volume_db = -20.0 +bus/1/volume_db = -6.0206 bus/1/send = "Master" bus/1/effect/0/effect = SubResource( 1 ) bus/1/effect/0/enabled = false @@ -68,7 +68,7 @@ bus/3/name = "UI" bus/3/solo = false bus/3/mute = false bus/3/bypass_fx = false -bus/3/volume_db = -4.43698 +bus/3/volume_db = -6.0206 bus/3/send = "Master" bus/3/effect/0/effect = SubResource( 6 ) bus/3/effect/0/enabled = true diff --git a/src/StateMachines/BlobbyStateMachine.gd b/src/StateMachines/BlobbyStateMachine.gd index b5c46b9..958979c 100644 --- a/src/StateMachines/BlobbyStateMachine.gd +++ b/src/StateMachines/BlobbyStateMachine.gd @@ -165,6 +165,9 @@ func _get_transition(_delta): ) anim_tree.set("parameters/wallsliding/blend_position", parent.wall_touch_direction) new_state = states.wallslide + # TODO Wallslide has to stick because the animation disconnects the wall raycasts + if self.state == states.wallslide && state_time < 0.2: + new_state = states.wallslide # Begins coyote time only if walking from ledge elif [states.walk, states.run].has(self.state) && !was_coyote_hanging: $CoyoteTimer.start() @@ -180,6 +183,7 @@ func _get_transition(_delta): if coyote_hanging: new_state = self.state + elif abs(parent.velocity.x) > 5: was_coyote_hanging = false if Input.is_action_pressed("boost_move"): @@ -263,7 +267,7 @@ func _exit_state(old_state, new_state): running_particles.emitting = false if old_state == "fall" && new_state != "wallslide": scene_audio.play_parallel_sound(landing_sound_1, 0.0, true, 1.0, 0.1) - elif old_state == "fall" && new_state == "wallslide": + elif new_state == "wallslide": scene_audio.play_parallel_sound(landing_sound_2, -15.0, true, 1.0, 0.1)