fix: better vaccum caterpillar sprites, consistent caterpillar behaviour

This commit is contained in:
Jakob Feldmann 2023-10-03 21:16:46 +02:00
parent 522e472c4d
commit 12a7a3d76a
20 changed files with 549 additions and 442 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/Caterpilllar.png-f7385704d20b491d5205bc11eb188006.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/enemy/Caterpilllar.png"
dest_files=[ "res://.import/Caterpilllar.png-f7385704d20b491d5205bc11eb188006.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=false
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 703 B

View File

@ -9,6 +9,11 @@
config_version=4
_global_script_classes=[ {
"base": "AudioStreamPlayer",
"class": "ACVoiceBox",
"language": "GDScript",
"path": "res://addons/ACVoicebox/ACVoicebox.gd"
}, {
"base": "KinematicBody2D",
"class": "Actor",
"language": "GDScript",
@ -90,6 +95,7 @@ _global_script_classes=[ {
"path": "res://src/StateMachines/StateMachine.gd"
} ]
_global_script_class_icons={
"ACVoiceBox": "",
"Actor": "",
"AudibleButton": "",
"AudibleCheckbox": "",

View File

@ -28,489 +28,489 @@ 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()) || stomping:
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()) || stomping:
snap_possible = false
#velocity += get_floor_velocity() * 0.5
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
#velocity += get_floor_velocity() * 0.5
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
func is_crushed() -> bool:
var touching_left = false
for left_raycast in left_wall_raycasts.get_children():
if left_raycast.is_colliding():
touching_left = true
var touching_right = false
for right_raycast in right_wall_raycasts.get_children():
if right_raycast.is_colliding():
touching_right = true
return touching_left && touching_right
var touching_left = false
for left_raycast in left_wall_raycasts.get_children():
if left_raycast.is_colliding():
touching_left = true
var touching_right = false
for right_raycast in right_wall_raycasts.get_children():
if right_raycast.is_colliding():
touching_right = true
return touching_left && touching_right
# Attached to wall state is in the PlayerStateMachine
func is_correct_walljump_input(direction: Vector2) -> bool:
if is_touching_wall_completely():
return (
Input.is_action_pressed("jump")
&& abs(direction.x + wall_touch_direction) < 1
&& abs(direction.x + wall_touch_direction) >= 0
)
return false
if is_touching_wall_completely():
return (
Input.is_action_pressed("jump")
&& abs(direction.x + wall_touch_direction) < 1
&& abs(direction.x + wall_touch_direction) >= 0
)
return false
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
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:
additive_jump_force += calculate_stomp_velocity(delta)
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)
var y_acceleration_force = acceleration_force[state].y
var x_acceleration_force = acceleration_force[state].x
var y_acceleration_force = acceleration_force[state].y
var x_acceleration_force = acceleration_force[state].x
if duck_jumping:
y_acceleration_force *= duck_boost.y
linear_velocity.x += duck_boost.x * direction.x
if duck_jumping:
y_acceleration_force *= duck_boost.y
linear_velocity.x += duck_boost.x * direction.x
if state != "jump":
linear_velocity.y = PhysicsFunc.two_step_euler(
linear_velocity.y,
(y_acceleration_force / delta + additive_jump_force) * -1,
mass,
delta
)
if state != "jump":
linear_velocity.y = PhysicsFunc.two_step_euler(
linear_velocity.y,
(y_acceleration_force / delta + additive_jump_force) * -1,
mass,
delta
)
# print(acceleration_force[state].y)
# print(linear_velocity.y)
var y_velocity = 0
if !Input.is_action_pressed("jump") && !stomping:
# Smooth transition from jumping to falling
if velocity.y > _gravity * delta * 10:
y_velocity += _gravity * delta * 10
else:
y_velocity += (max(abs(linear_velocity.y), _gravity * delta) / 2)
var y_velocity = 0
if !Input.is_action_pressed("jump") && !stomping:
# Smooth transition from jumping to falling
if velocity.y > _gravity * delta * 10:
y_velocity += _gravity * delta * 10
else:
y_velocity += (max(abs(linear_velocity.y), _gravity * delta) / 2)
else:
y_velocity += _gravity * delta
#if linear_velocity.y < max_velocity["jump"].y:
linear_velocity.y += y_velocity
else:
y_velocity += _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, x_acceleration_force * movement_factor * direction.x, mass, delta
)
#if linear_velocity.y < max_velocity["jump"].y:
linear_velocity.y += y_velocity
if is_correct_airstrafe_input():
linear_velocity = execute_airstrafe(linear_velocity, delta, direction)
# 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, x_acceleration_force * movement_factor * direction.x, mass, delta
)
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)
elif (
abs(direction.x + wall_touch_direction) < 1
&& abs(direction.x + wall_touch_direction) >= 0
):
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["fall"].x * movementFactor * direction.x,
mass,
delta
)
else:
# TODO dont put constants in here
linear_velocity.y = PhysicsFunc.two_step_euler(
linear_velocity.y * 0.94, _gravity * mass, mass, delta
)
# TODO single out to function
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)
elif (
abs(direction.x + wall_touch_direction) < 1
&& abs(direction.x + wall_touch_direction) >= 0
):
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["fall"].x * movementFactor * direction.x,
mass,
delta
)
else:
# TODO dont put constants in here
linear_velocity.y = PhysicsFunc.two_step_euler(
linear_velocity.y * 0.94, _gravity * mass, mass, delta
)
# TODO single out to function
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")
#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
#print("stomping")
#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 == 0:
$"%BlobbymationPlayer".play("expandingDisolve")
if animation_number == -1:
respawn()
return
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 == 0:
$"%BlobbymationPlayer".play("expandingDisolve")
if animation_number == -1:
respawn()
return
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"):
#scene_audio.play_parallel_sound(death_sound_1, -15)
scene_audio.play_parallel_sound(death_sound_2, -16)
$PitfallTimer.start()
if area.is_in_group("harmful"):
die()
if area.is_in_group("pit"):
#scene_audio.play_parallel_sound(death_sound_1, -15)
scene_audio.play_parallel_sound(death_sound_2, -16)
$PitfallTimer.start()
# This problem stems from trying to decelerate a walk
@ -518,54 +518,54 @@ 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 _on_CrushTimer_timeout() -> void:
if is_crushed():
die_for_real()
if is_crushed():
die_for_real()
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)

View File

@ -4385,7 +4385,7 @@ texture = SubResource( 62 )
offset = Vector2( 1, 0 )
hframes = 6
vframes = 6
frame = 9
frame = 5
__meta__ = {
"_editor_description_": "YXNlcHJpdGVfd2l6YXJkX2NvbmZpZwpwbGF5ZXJ8PUJsb2JieVNwcml0ZS9CbG9iYnltYXRpb25QbGF5ZXIKc291cmNlfD1yZXM6Ly9hc3NldHMvYmxvYmJ5L2Jsb2JieS1zcHJpdGVzaGVldHQuYXNlcHJpdGUKbGF5ZXJ8PUJsb2JieQpvcF9leHB8PUZhbHNlCm9fZm9sZGVyfD0Kb19uYW1lfD0Kb25seV92aXNpYmxlfD1GYWxzZQpvX2V4X3B8PQo="
}

View File

@ -32,6 +32,7 @@ func execute_movement(delta: float) -> void:
# velocity
var v = Vector2(velocity.x * movement, 0)
time += delta
$AnimationPlayer.play("moving")
move_and_slide_with_snap(
v.rotated(rotation), snap.rotated(rotation), FLOOR_NORMAL, false, 4, PI, false
)

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=7 format=2]
[gd_scene load_steps=8 format=2]
[ext_resource path="res://assets/enemy/enemy.png" type="Texture" id=1]
[ext_resource path="res://assets/enemy/Caterpilllar.png" type="Texture" id=1]
[ext_resource path="res://src/Actors/Enemies/Caterpillar.gd" type="Script" id=2]
[ext_resource path="res://src/StateMachines/CaterpillarStateMachine.gd" type="Script" id=3]
@ -13,6 +13,23 @@ extents = Vector2( 15, 8.61814 )
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 14.7108, 7.85442 )
[sub_resource type="Animation" id=4]
resource_name = "moving"
loop = true
step = 0.05
tracks/0/type = "value"
tracks/0/path = NodePath("enemy:scale")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 0.25, 0.5, 0.75 ),
"transitions": PoolRealArray( 1, 1, 1, 1 ),
"update": 0,
"values": [ Vector2( 1, 1 ), Vector2( 1.05, 1 ), Vector2( 1.1, 1.05 ), Vector2( 1.05, 1.1 ) ]
}
[node name="Caterpillar" type="KinematicBody2D" groups=["harmful"]]
scale = Vector2( 0.747749, 0.572926 )
collision_layer = 2
@ -21,11 +38,12 @@ collision/safe_margin = 0.001
script = ExtResource( 2 )
[node name="enemy" type="Sprite" parent="."]
position = Vector2( 0, -1.90735e-06 )
scale = Vector2( 0.286789, 0.276348 )
position = Vector2( 0, -3.49085 )
scale = Vector2( 1.01, 1.02 )
texture = ExtResource( 1 )
[node name="VisibilityEnabler2D" type="VisibilityEnabler2D" parent="."]
visible = false
position = Vector2( 1362.81, -0.138177 )
scale = Vector2( 15.4865, 1.28502 )
rect = Rect2( -89, -10, 2, 20 )
@ -33,30 +51,35 @@ process_parent = true
physics_process_parent = true
[node name="SlopeRaycastLeft" type="RayCast2D" parent="."]
visible = false
position = Vector2( -7.5, 12 )
enabled = true
cast_to = Vector2( 0, 2 )
collision_mask = 8
[node name="SlopeRaycastRight" type="RayCast2D" parent="."]
visible = false
position = Vector2( 7.5, 12 )
enabled = true
cast_to = Vector2( 0, 2 )
collision_mask = 8
[node name="WallRaycastLeft" type="RayCast2D" parent="."]
visible = false
position = Vector2( -14.711, 11.5 )
enabled = true
cast_to = Vector2( -3, 0 )
collision_mask = 8
[node name="WallRaycastRight" type="RayCast2D" parent="."]
visible = false
position = Vector2( 14.711, 11.5 )
enabled = true
cast_to = Vector2( 3, 0 )
collision_mask = 8
[node name="StompDetector" type="Area2D" parent="." groups=["weakpoint"]]
visible = false
modulate = Color( 0, 0.0392157, 1, 1 )
light_mask = 0
position = Vector2( 0, -6.44095 )
@ -66,26 +89,34 @@ monitorable = false
priority = 1.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="StompDetector"]
visible = false
position = Vector2( 0, -2.28618 )
shape = SubResource( 2 )
[node name="EnemySkin" type="Area2D" parent="."]
process_priority = -1
visible = false
collision_layer = 2
collision_mask = 127
input_pickable = false
[node name="CollisionPolygon2D" type="CollisionShape2D" parent="EnemySkin"]
visible = false
position = Vector2( 0, 3.49085 )
shape = SubResource( 3 )
[node name="EnemyBody" type="CollisionShape2D" parent="."]
visible = false
position = Vector2( -6.37697e-07, 4.36357 )
shape = SubResource( 1 )
[node name="StateMachine" type="Node2D" parent="."]
visible = false
script = ExtResource( 3 )
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
anims/moving = SubResource( 4 )
[connection signal="body_entered" from="StompDetector" to="." method="_on_StompDetector_body_entered"]
[connection signal="area_entered" from="EnemySkin" to="." method="_on_EnemySkin_area_entered"]
[connection signal="body_entered" from="EnemySkin" to="." method="_on_EnemySkin_body_entered"]

View File

@ -4,6 +4,7 @@ const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd")
export var invincible := false
export var speed := 80
export var acceleration := 80
export var is_harmful := true
func _ready() -> void:
$StompDetector.monitoring = !invincible
@ -22,8 +23,6 @@ func _physics_process(delta: float) -> void:
mass, delta)
velocity.y = move_and_slide(velocity, FLOOR_NORMAL).y
if player_entered_stomp:
$Sprite.frame = 1
# TODO Detects player over gaps
func player_on_floor_direction() -> float:
@ -33,3 +32,43 @@ func player_on_floor_direction() -> float:
if collider.is_in_group("player"):
return sign(collider.position.x - self.position.x)
return 0.0
func _on_StompDetector_body_entered(body: Node) -> void:
if !body.is_in_group("player"):
return
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) \
&& is_harmful:
print("too shallow entry")
body.die()
return
signal_manager.emit_signal("got_stomped")
#get_node("EnemyBody").disabled = true
if(killable):
remove_from_group("harmful")
die()
else:
switch_spikes()
func switch_spikes() -> void:
is_harmful = !is_harmful
if $Sprite.frame == 0:
$Sprite.frame = 1
else:
$Sprite.frame = 0
func die() -> void:
queue_free()
func _on_EnemySkin_area_entered(area: Area2D) -> void:
pass
func _on_EnemySkin_body_entered(body: Node) -> void:
if body.is_in_group("player") && is_harmful:
body.die()

View File

@ -2,7 +2,6 @@ extends Actor
class_name Enemy
export(bool) var killable := true
var player_entered_stomp = false
func _on_StompDetector_body_entered(body: Node) -> void:
@ -10,14 +9,11 @@ func _on_StompDetector_body_entered(body: Node) -> void:
return
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) \
&& !player_entered_stomp:
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")
player_entered_stomp = true
#get_node("EnemyBody").disabled = true
if(killable):
remove_from_group("harmful")
@ -35,5 +31,5 @@ func _on_EnemySkin_area_entered(area: Area2D) -> void:
func _on_EnemySkin_body_entered(body: Node) -> void:
if body.is_in_group("player") && !player_entered_stomp:
if body.is_in_group("player"):
body.die()

View File

@ -125,9 +125,6 @@ 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( 6 )
@ -223,9 +220,8 @@ speed = 16
[node name="DartingEnemy" parent="." instance=ExtResource( 6 )]
position = Vector2( 609, 67 )
mass = 1.0
killable = false
speed = 300
acceleration = 800
[connection signal="body_exited" from="Blobby/BlobbySkin" to="Blobby" method="_on_BlobbySkin_body_exited"]

View File

@ -128,7 +128,7 @@ death_sound_1 = null
death_sound_2 = null
[node name="BlobbySprite" parent="Blobby" index="5"]
frame = 7
frame = 6
[node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"]
parameters/playback = SubResource( 7 )

View File

@ -132,9 +132,6 @@ jump_buffer_filled = null
death_sound_1 = null
death_sound_2 = null
[node name="BlobbySprite" parent="Blobby" index="5"]
frame = 5
[node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"]
parameters/playback = SubResource( 53 )

View File

@ -135,7 +135,7 @@ death_sound_1 = null
death_sound_2 = null
[node name="BlobbySprite" parent="Blobby" index="5"]
frame = 10
frame = 9
[node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"]
parameters/playback = SubResource( 6 )
@ -194,8 +194,8 @@ max_speed = 100
[node name="DartingEnemy" parent="." instance=ExtResource( 20 )]
position = Vector2( -446, 259 )
speed = 200
acceleration = 320
mass = 1.0
killable = false
[node name="TileMap" type="TileMap" parent="."]
unique_name_in_owner = true

View File

@ -131,9 +131,6 @@ unique_name_in_owner = true
position = Vector2( -64, -1.90735e-06 )
scale = Vector2( 0.878906, 0.936025 )
[node name="BlobbySprite" parent="Blobby" index="5"]
frame = 10
[node name="BlobbymationTree" parent="Blobby/BlobbySprite" index="0"]
parameters/playback = SubResource( 6 )

File diff suppressed because one or more lines are too long

View File

@ -15,13 +15,16 @@ var halted = false
var returning = false
var initial_distance : float = 1.0
export(float) var velocity = 1
export(float) var return_velocity = 10
export(float) var initial_velocity = 20
export(float) var max_velocity = 200
export(float) var acceleration_force = 1200
export(float) var mass = 10
export(bool) var avoid_crushing = false
export(bool) var fast_retrigger = false
var velocity = initial_velocity
func _ready() -> void:
$FlyingLaserCutterBody/Sprite/AnimationPlayer.play("default")
@ -49,8 +52,8 @@ func _physics_process(delta: float) -> void:
if halted && avoid_crushing:
return
returning = true
velocity=1
body.position.x += (max_velocity/3)*-1*delta
velocity = initial_velocity
body.position.x += return_velocity * -1 * delta
else:
returning = false

View File

@ -72,6 +72,10 @@ shader_param/oscilation_speed = 0.2
[node name="FlyingLaserCutter" type="Node2D"]
script = ExtResource( 2 )
return_velocity = 80.0
initial_velocity = 30.0
max_velocity = 190.0
acceleration_force = 1000.0
[node name="FlyingLaserCutterBody" type="KinematicBody2D" parent="."]
collision_layer = 32