fix: sticky wallslide, bounce consistency
This commit is contained in:
parent
53e8620c8c
commit
15c98361c0
BIN
assets/sounds/grass swish 1.ogg
Normal file
BIN
assets/sounds/grass swish 1.ogg
Normal file
Binary file not shown.
15
assets/sounds/grass swish 1.ogg.import
Normal file
15
assets/sounds/grass swish 1.ogg.import
Normal file
@ -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
|
||||
BIN
assets/sounds/grass swish 2.ogg
Normal file
BIN
assets/sounds/grass swish 2.ogg
Normal file
Binary file not shown.
15
assets/sounds/grass swish 2.ogg.import
Normal file
15
assets/sounds/grass swish 2.ogg.import
Normal file
@ -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
|
||||
BIN
assets/sounds/grass swish 3.ogg
Normal file
BIN
assets/sounds/grass swish 3.ogg
Normal file
Binary file not shown.
15
assets/sounds/grass swish 3.ogg.import
Normal file
15
assets/sounds/grass swish 3.ogg.import
Normal file
@ -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
|
||||
BIN
assets/sounds/grass swish 4.ogg
Normal file
BIN
assets/sounds/grass swish 4.ogg
Normal file
Binary file not shown.
15
assets/sounds/grass swish 4.ogg.import
Normal file
15
assets/sounds/grass swish 4.ogg.import
Normal file
@ -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
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -4385,7 +4385,7 @@ texture = SubResource( 62 )
|
||||
offset = Vector2( 1, 0 )
|
||||
hframes = 6
|
||||
vframes = 6
|
||||
frame = 10
|
||||
frame = 7
|
||||
__meta__ = {
|
||||
"_editor_description_": "YXNlcHJpdGVfd2l6YXJkX2NvbmZpZwpwbGF5ZXJ8PUJsb2JieVNwcml0ZS9CbG9iYnltYXRpb25QbGF5ZXIKc291cmNlfD1yZXM6Ly9hc3NldHMvYmxvYmJ5L2Jsb2JieS1zcHJpdGVzaGVldHQuYXNlcHJpdGUKbGF5ZXJ8PUJsb2JieQpvcF9leHB8PUZhbHNlCm9fZm9sZGVyfD0Kb19uYW1lfD0Kb25seV92aXNpYmxlfD1GYWxzZQpvX2V4X3B8PQo="
|
||||
}
|
||||
|
||||
@ -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
|
||||
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())
|
||||
|
||||
@ -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
|
||||
# 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)
|
||||
# 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
|
||||
)
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -3,7 +3,6 @@ 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 feeler_raycast: RayCast2D = $FeelerRayCast
|
||||
@ -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)
|
||||
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
|
||||
# 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 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)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
else:
|
||||
if(!in_air):
|
||||
start_x = global_position.x
|
||||
reversing_possible_searching = true
|
||||
jump_timer.stop()
|
||||
in_air = true
|
||||
if barely_held_back_counter > 1:
|
||||
barely_held_back_counter = 0
|
||||
loose_target()
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
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 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
|
||||
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()
|
||||
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 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
|
||||
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)
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 )
|
||||
|
||||
@ -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 )
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user