forked from team-sg/hero-mark-2
597 lines
20 KiB
GDScript
597 lines
20 KiB
GDScript
extends KinematicBody2D
|
|
|
|
# SIGNALS #
|
|
signal died()
|
|
signal teleport_finished()
|
|
|
|
# CONSTANTS #
|
|
const ArrowProjectile = preload("res://objects/player/arrow_projectile.tscn")
|
|
const DeathSplatter = preload("res://objects/player/player_death_particles.tscn")
|
|
const SplashParticles = preload("res://objects/environment/splash/splash_particles.tscn")
|
|
const BloodSpray := preload("res://objects/environment/blood/blood_spray.tscn")
|
|
|
|
# EXPORTS #
|
|
## whether to be temporarily invulnerable after respawning
|
|
export var use_iframes: bool = false
|
|
## horizontal movement speed
|
|
export var walk_speed: float = 50.0
|
|
## frames until walk speed peak (at 60fps reference)
|
|
export var walk_acceleration_frames: float = 1.0
|
|
## speed to push pushable objects at
|
|
export var push_speed: float = 25.0
|
|
## climbing speed
|
|
export var climb_speed: float = 39.0
|
|
## gravity force
|
|
export var gravity: float = 720.0
|
|
## SG's terminal velocity
|
|
export var max_fall_speed: float = 255.0
|
|
## upward added by jump
|
|
export var jump_force: float = 150.0
|
|
## proportion of remaining force retained when jump is released
|
|
export var jump_release_force: float = 0.25
|
|
## impulse added when double jumping
|
|
export var double_jump_force: float = 122.0
|
|
## if on turn on oxygentimer to kill player
|
|
export var underwater = false
|
|
|
|
# velocity
|
|
var velocity: Vector2 = Vector2.ZERO
|
|
# current falling speed
|
|
var current_fall_speed: float = 0.0
|
|
# snap vector
|
|
var snap: Vector2 = Vector2.ZERO
|
|
# ladder currently attached to
|
|
var _attached_ladder: Node2D = null
|
|
# whether to skip blood splatter for this death
|
|
var skip_blood: bool = false
|
|
#whether sg has landed before
|
|
var first_land = true
|
|
|
|
var can_shield = true
|
|
|
|
|
|
# NODE REFERENCES #
|
|
onready var state_chart: StateChart = $StateChart
|
|
onready var animation_player: AnimationPlayer = $AnimationPlayer
|
|
onready var graphics: Node2D = $Graphics
|
|
onready var sprite: Sprite = $"%Sprite"
|
|
onready var arrow_position: Position2D = $"%ArrowPosition"
|
|
onready var dust_particles: CPUParticles2D = $"%DustParticles"
|
|
onready var grounded_shape: CollisionShape2D = $"%GroundedShape"
|
|
onready var airborne_shape: CollisionShape2D = $"%AirborneShape"
|
|
onready var ladder_detector: RayCast2D = $"%LadderDetector"
|
|
onready var death_splatter_position: Position2D = $"%DeathSplatterPosition"
|
|
onready var pushable_detector: RayCast2D = $"%PushableDetector"
|
|
onready var oxygen_timer = $OxygenTimer
|
|
onready var low_oxygen_label = $"%LowOxygenLabel"
|
|
onready var edge_detector = $Graphics/EdgeDetector
|
|
onready var body_shape: CollisionShape2D = $"%BodyShape"
|
|
onready var cfox: Sprite = $"%CFox"
|
|
onready var hitbox: Area2D = $"%Hitbox"
|
|
|
|
# OVERRIDES #
|
|
func _ready() -> void:
|
|
Game.can_restart = true
|
|
#set palette
|
|
var palette = load("res://graphics/player/palettes/%s.tex" % Game.current_palette)
|
|
sprite.material.set_shader_param("palette", palette)
|
|
$"%CFox".material.set_shader_param("palette", palette)
|
|
$"%DissolveParticles".material.set_shader_param("palette", palette)
|
|
if Game.current_palette == "super_player":
|
|
$"%Sparkles".visible = true
|
|
|
|
# death handling
|
|
Game.respawn_point = global_position
|
|
connect("died", Game, "_on_player_died")
|
|
# to detect floor on first frame
|
|
move_and_slide(Vector2(0.0, 1.0), Vector2.UP)
|
|
# make certain pushable detector will not detect player
|
|
pushable_detector.add_exception(self)
|
|
# set up state chart
|
|
state_chart.initialize()
|
|
state_chart.set_guard_property("can_respawn", true)
|
|
state_chart.set_guard_property("use_iframes", use_iframes)
|
|
state_chart.set_guard_property("red_feather", false)
|
|
# state chart debug
|
|
$StateDebugLayer/StateChartDebug.target = state_chart
|
|
# set lung size
|
|
if Game.difficulty == Game.Difficulty.SWEET:
|
|
oxygen_timer.set_wait_time(25)
|
|
if Game.difficulty == Game.Difficulty.PUNGENT:
|
|
oxygen_timer.set_wait_time(15)
|
|
oxygen_timer.start()
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
# snap sprite
|
|
sprite.global_position = graphics.global_position.round() + Vector2(0.0, -10.0)
|
|
# update transition guard properties
|
|
# whether player can currently shoot an arrow
|
|
var can_shoot = Game.arrows > 0 and get_tree().get_nodes_in_group("player_arrow").size() == 0
|
|
state_chart.set_guard_property("can_shoot", can_shoot)
|
|
|
|
# check for and propagate input events
|
|
if Input.is_action_just_pressed("shoot"): # shooting
|
|
state_chart.send_event("shoot")
|
|
elif Input.is_action_just_pressed("jump"): # jumping
|
|
state_chart.send_event("jump")
|
|
if Input.is_action_pressed("move_down"):
|
|
state_chart.send_event("duck_pressed")
|
|
if Input.is_action_just_released("move_down"):
|
|
state_chart.send_event("duck_released")
|
|
if Input.is_action_just_pressed("shield") && Game.can_use_shield == true:
|
|
if can_shield:
|
|
Audio.play_sound(Audio.a_shield,Audio.ac_die)
|
|
$ShieldTimer.start()
|
|
$ShieldCooldown.start()
|
|
$Shield.visible = true
|
|
$"%AirborneShape".disabled = true
|
|
$"%GroundedShape".disabled = true
|
|
can_shield = false
|
|
|
|
|
|
|
|
# send relevant events
|
|
if is_on_floor(): # check on floor status
|
|
state_chart.send_event("grounded")
|
|
else:
|
|
state_chart.send_event("airborne")
|
|
|
|
# check if in contact with ladder
|
|
if ladder_detector.is_colliding():
|
|
state_chart.send_event("ladder_touched")
|
|
|
|
# show oxygen count on low oxygen
|
|
if underwater:
|
|
if oxygen_timer.time_left < 5:
|
|
low_oxygen_label.text = str(floor(oxygen_timer.time_left) + 1)
|
|
set_underwater_audio(true)
|
|
else:
|
|
low_oxygen_label.text = ""
|
|
set_underwater_audio(false)
|
|
else:
|
|
#NOT UNDERWATER
|
|
low_oxygen_label.text = ""
|
|
|
|
|
|
# HELPER FUNCTIONS #
|
|
## spawns an arrow
|
|
func spawn_arrow() -> void:
|
|
var arrow = ArrowProjectile.instance()
|
|
arrow.global_position = arrow_position.global_position
|
|
arrow.direction = sign(arrow_position.global_position.x - global_position.x)
|
|
arrow.add_to_group("player_arrow")
|
|
get_parent().add_child(arrow)
|
|
Audio.play_sound(Audio.a_shoot, Audio.ac_jump)
|
|
|
|
func die() -> void:
|
|
state_chart.send_event("hurt")
|
|
|
|
func zap() -> void:
|
|
state_chart.send_event("zapped")
|
|
|
|
func set_underwater_audio(value):
|
|
var idx = AudioServer.get_bus_index("Master")
|
|
AudioServer.set_bus_effect_enabled(idx,0,value)
|
|
AudioServer.set_bus_effect_enabled(idx,1,value)
|
|
|
|
func get_stick_input(axis):
|
|
var inp = Input.get_joy_axis(0,axis)
|
|
if abs(inp) >= 0.5:
|
|
return sign(inp)
|
|
else:
|
|
return 0
|
|
|
|
func reset_fall_speed():
|
|
current_fall_speed = 0
|
|
|
|
# STATE ENTERS/EXITS #
|
|
func _on_Grounded_state_entered() -> void:
|
|
# still jump if pressed frame hit ground
|
|
if Input.is_action_just_pressed("jump"):
|
|
state_chart.send_event("jump")
|
|
# toggle hurtbox shapes
|
|
grounded_shape.disabled = false
|
|
airborne_shape.disabled = true
|
|
snap.y = 2.5 # snap when in grounded state
|
|
velocity.y = 1.0
|
|
if first_land:
|
|
first_land = false
|
|
else:
|
|
#Landing sound
|
|
Audio.play_sound(Audio.a_land,Audio.ac_land)
|
|
#Landing Rumble
|
|
var intensity = inverse_lerp(0.0, max_fall_speed, current_fall_speed)
|
|
intensity = min(intensity * 1.1,1.0)
|
|
Input.start_joy_vibration(0, 1.0, intensity, 0.05)
|
|
|
|
func _on_Still_state_entered() -> void:
|
|
animation_player.play("idle")
|
|
|
|
func _on_Walking_state_entered() -> void:
|
|
animation_player.play("walk")
|
|
|
|
func _on_Blinking_state_entered() -> void:
|
|
if $"%Blinking".active:
|
|
animation_player.play("blink")
|
|
var blink_timer = get_tree().create_timer(rand_range(1.0, 2.0), false)
|
|
blink_timer.connect("timeout", self,"_on_Blinking_state_entered")
|
|
|
|
func _on_Stimming_state_entered() -> void:
|
|
animation_player.play("stim")
|
|
|
|
func _on_Ducking_state_entered():
|
|
velocity.x = 0
|
|
animation_player.play("duck")
|
|
|
|
func _on_Pushing_state_entered() -> void:
|
|
animation_player.play("push")
|
|
|
|
func _on_Airborne_state_entered() -> void:
|
|
grounded_shape.disabled = true
|
|
airborne_shape.disabled = false
|
|
snap.y = 0.0 # do not snap when in air
|
|
velocity.y = 0.0
|
|
|
|
func _on_NormalJump_state_entered() -> void:
|
|
velocity.y = -jump_force
|
|
Audio.play_sound(Audio.a_jump, Audio.ac_jump)
|
|
animation_player.play("jump")
|
|
dust_particles.restart()
|
|
|
|
func _on_NormalJump_state_exited() -> void:
|
|
# add bit of force proportional to how much of the jump is left
|
|
if Input.is_action_just_released("jump"):
|
|
var factor = inverse_lerp(0.0, -jump_force, velocity.y)
|
|
velocity.y = -jump_force * factor * jump_release_force
|
|
|
|
func _on_LadderJump_state_entered() -> void:
|
|
velocity.y = -jump_force
|
|
Audio.play_sound(Audio.a_jump, Audio.ac_jump)
|
|
animation_player.play("ladder_jump")
|
|
|
|
func _on_DoubleJump_state_entered() -> void:
|
|
velocity.y = -double_jump_force
|
|
Audio.play_sound(Audio.a_doublejump, Audio.ac_jump)
|
|
animation_player.play("double_jump")
|
|
|
|
func _on_CoyoteFalling_state_entered() -> void:
|
|
global_position.y += 1.0
|
|
velocity.x = 0.0
|
|
animation_player.play("fall")
|
|
|
|
func _on_NormalFalling_state_entered() -> void:
|
|
animation_player.play("fall")
|
|
|
|
func _on_ScaredFalling_state_entered() -> void:
|
|
velocity.x = 0.0
|
|
animation_player.play("fall_scared")
|
|
|
|
func _on_Shooting_state_entered() -> void:
|
|
velocity.x = 0.0
|
|
animation_player.play("shoot_grounded")
|
|
|
|
func _on_AirShooting_state_entered() -> void:
|
|
spawn_arrow()
|
|
animation_player.play("shoot_airborne")
|
|
|
|
func _on_Climbing_state_entered() -> void:
|
|
if ladder_detector.get_collider().is_in_group("ladder"):
|
|
_attached_ladder = ladder_detector.get_collider()
|
|
# move a tiny bit up if on ground to detach from falling blocks
|
|
if is_on_floor():
|
|
global_position.y -= get("collision/safe_margin")
|
|
velocity = Vector2.ZERO
|
|
snap = Vector2.ZERO
|
|
var input_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
var ladder_dir = sign(_attached_ladder.middle - global_position.x)
|
|
var flip = global_position.y - 1.0 <= _attached_ladder.global_position.y and input_dir == ladder_dir and is_on_floor()
|
|
if (ladder_dir >= 0.0 != flip or not _attached_ladder.can_climb_right) and _attached_ladder.can_climb_left:
|
|
global_position.x = _attached_ladder.left_snap
|
|
graphics.scale.x = 1.0
|
|
animation_player.play("climb")
|
|
elif _attached_ladder.can_climb_right:
|
|
global_position.x = _attached_ladder.right_snap
|
|
graphics.scale.x = -1.0
|
|
animation_player.play("climb")
|
|
|
|
func _on_Climbing_state_exited() -> void:
|
|
_attached_ladder = null
|
|
animation_player.playback_speed = 1.0 # restore playback speed
|
|
Audio.ac_climb.stream = null # stop audio
|
|
|
|
# all the stuff that happens when they DIE
|
|
func _on_Dead_state_entered() -> void:
|
|
if Debug.fast_punishment > 0:
|
|
Engine.time_scale += .05 * Debug.fast_punishment
|
|
# send signals
|
|
emit_signal("died")
|
|
state_chart.send_event("died")
|
|
Input.start_joy_vibration(0,1,1,0.2)
|
|
# spawn death particles
|
|
if not skip_blood:
|
|
var particles = DeathSplatter.instance()
|
|
particles.global_position = death_splatter_position.global_position
|
|
particles.emitting = true
|
|
get_parent().add_child(particles)
|
|
for i in 16:
|
|
var spray = BloodSpray.instance()
|
|
spray.pause_mode = PAUSE_MODE_PROCESS
|
|
Physics2DServer.set_active(true)
|
|
spray.global_position = death_splatter_position.global_position
|
|
spray.velocity = Vector2(randf() * 80.0, 0.0).rotated(randf() * TAU)
|
|
spray.stains_player = false
|
|
get_parent().add_child(spray)
|
|
else:
|
|
skip_blood = false
|
|
# fade into the ether
|
|
graphics.visible = false
|
|
state_chart.send_event("respawn")
|
|
#refill oxygen
|
|
oxygen_timer.start()
|
|
|
|
func _on_Drowning_state_entered() -> void:
|
|
# state_chart.send_event("died")
|
|
velocity = Vector2.ZERO
|
|
animation_player.call_deferred("play", "drown")
|
|
|
|
func _on_Respawn_state_entered() -> void:
|
|
global_position = Game.respawn_point
|
|
graphics.visible = true
|
|
|
|
func _on_Appearing_state_entered() -> void:
|
|
global_position = Game.respawn_point
|
|
animation_player.play("respawn")
|
|
|
|
func _on_Edge_state_entered():
|
|
animation_player.play("edge")
|
|
|
|
func _on_Inactive_state_entered() -> void:
|
|
velocity = Vector2.ZERO
|
|
body_shape.disabled = true
|
|
hitbox.monitorable = false
|
|
hitbox.monitoring = false
|
|
|
|
func _on_Inactive_state_exited() -> void:
|
|
body_shape.disabled = false
|
|
hitbox.monitorable = true
|
|
hitbox.monitoring = true
|
|
|
|
func _on_Teleporting_state_entered() -> void:
|
|
hitbox.monitorable = false
|
|
hitbox.monitoring = false
|
|
velocity = Vector2.ZERO
|
|
Audio.play_sound(Audio.a_teleport, Audio.ac_jump)
|
|
animation_player.play("idle")
|
|
var tween = create_tween()
|
|
for i in 8:
|
|
tween.tween_property(sprite, "position:x", 1.0, 0.0333333)
|
|
tween.tween_property(sprite, "position:x", -1.0, 0.0333333)
|
|
tween.tween_property(sprite, "position:x", 0.0, 0.0666667)
|
|
yield(tween, "finished")
|
|
sprite.visible = false
|
|
$"%DissolveParticles".emitting = true
|
|
yield(get_tree().create_timer(1.0, false), "timeout")
|
|
emit_signal("teleport_finished")
|
|
|
|
|
|
# STATE PROCESSING #
|
|
## when on ground
|
|
func _process_grounded(delta: float) -> void:
|
|
# make sure is_on_floor detected still
|
|
velocity.y = 1.0
|
|
#play edge sprite if hanging of edge
|
|
if !edge_detector.is_colliding():
|
|
state_chart.send_event("edge")
|
|
else:
|
|
state_chart.send_event("off_edge")
|
|
|
|
## called when player can move left and rightpass # Repass # Rpass # Replace with function body.eplace with function body.place with function body.
|
|
func _process_horizontal_movement(delta: float) -> void:
|
|
var input_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
velocity.x = input_dir * walk_speed
|
|
if input_dir != 0.0:
|
|
graphics.scale.x = input_dir
|
|
|
|
## player movement with acceleration
|
|
func _process_horizontal_movement_grounded(delta: float) -> void:
|
|
var input_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
# if Input.is_action_pressed("stick_input"): input_dir = get_stick_input(JOY_AXIS_0)
|
|
if input_dir == 0.0 or input_dir != sign(velocity.x):
|
|
velocity.x = 0.0
|
|
var acceleration = lerp(0.0, walk_speed, 1.0 / walk_acceleration_frames) * 60.0
|
|
velocity.x += input_dir * acceleration * delta
|
|
velocity.x = clamp(velocity.x, -walk_speed, walk_speed)
|
|
if input_dir != 0.0:
|
|
graphics.scale.x = input_dir
|
|
|
|
## walk/idle state
|
|
func _process_can_walk(delta: float) -> void:
|
|
if sign(Input.get_axis("move_left", "move_right")) != 0.0 or get_stick_input(JOY_AXIS_0) != 0.0:
|
|
state_chart.send_event("walk_start")
|
|
else:
|
|
state_chart.send_event("walk_stop")
|
|
|
|
## rubbing up against a wall or pushing an object
|
|
func _process_pushing(delta: float) -> void:
|
|
if not is_on_wall():
|
|
state_chart.send_event("push_stop")
|
|
var input_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
if input_dir != 0.0:
|
|
pushable_detector.force_raycast_update()
|
|
if pushable_detector.is_colliding():
|
|
var col = pushable_detector.get_collider()
|
|
if col.is_in_group("pushable"):
|
|
col.push(input_dir * push_speed)
|
|
velocity.x = input_dir * push_speed * 2.0
|
|
else:
|
|
state_chart.send_event("push_stop")
|
|
|
|
## climbing on ladders
|
|
func _process_climbing(delta: float) -> void:
|
|
# climbing movement
|
|
var input_dir = sign(Input.get_axis("move_up", "move_down") + get_stick_input(JOY_AXIS_1)) # sign() to normalize
|
|
move_and_slide(Vector2(0.0, input_dir * climb_speed), Vector2.UP) # move
|
|
animation_player.playback_speed = abs(input_dir) # play/pause animation
|
|
|
|
# play sound
|
|
if input_dir < 0.0:
|
|
if Audio.ac_climb.stream != Audio.a_climb_up:
|
|
Audio.play_sound(Audio.a_climb_up, Audio.ac_climb)
|
|
if Audio.ac_climb.get_playback_position() >= Audio.a_climb_up.get_length():
|
|
Audio.ac_climb.play()
|
|
elif input_dir > 0.0:
|
|
if Audio.ac_climb.stream != Audio.a_climb_down:
|
|
Audio.play_sound(Audio.a_climb_down, Audio.ac_climb)
|
|
if Audio.ac_climb.get_playback_position() >= Audio.a_climb_down.get_length():
|
|
Audio.ac_climb.play()
|
|
else:
|
|
Audio.ac_climb.stream = null
|
|
|
|
# check if still on ladder
|
|
ladder_detector.force_raycast_update()
|
|
var collider = ladder_detector.get_collider()
|
|
if collider and collider.is_in_group("ladder"):
|
|
_attached_ladder = collider
|
|
if Input.is_action_just_pressed("jump"):
|
|
var horizontal_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
if sign(_attached_ladder.middle - global_position.x) != horizontal_dir:
|
|
global_position.x -= graphics.scale.x * 3.0
|
|
state_chart.send_event("ladder_jump")
|
|
return
|
|
elif Input.is_action_just_pressed("shoot"):
|
|
var horizontal_dir = sign(Input.get_axis("move_left", "move_right") + get_stick_input(JOY_AXIS_0)) # sign() to normalize
|
|
if sign(_attached_ladder.middle - global_position.x) != horizontal_dir:
|
|
global_position.x -= graphics.scale.x * 3.0
|
|
state_chart.send_event("ladder_detach")
|
|
return
|
|
# # auto-dismount on ground
|
|
# elif Input.is_action_pressed("move_down") and is_on_floor():
|
|
# var horizontal_dir = sign(Input.get_axis("move_left", "move_right"))
|
|
# if sign(_attached_ladder.middle - global_position.x) != horizontal_dir:
|
|
# global_position.x -= graphics.scale.x * 3.0
|
|
# state_chart.send_event("ladder_detach")#
|
|
elif Input.is_action_just_pressed("move_left") and _attached_ladder.can_climb_left:
|
|
global_position.x = _attached_ladder.left_snap
|
|
graphics.scale.x = 1.0
|
|
elif Input.is_action_just_pressed("move_right") and _attached_ladder.can_climb_right:
|
|
global_position.x = _attached_ladder.right_snap
|
|
graphics.scale.x = -1.0
|
|
else:
|
|
var ladder_dir = sign(_attached_ladder.middle - global_position.x)
|
|
if ladder_dir >= 0.0:
|
|
global_position.x = _attached_ladder.left_snap
|
|
graphics.scale.x = 1.0
|
|
else:
|
|
global_position.x = _attached_ladder.right_snap
|
|
graphics.scale.x = -1.0
|
|
else:
|
|
if input_dir == -1.0:
|
|
state_chart.send_event("ladder_peak")
|
|
return
|
|
else:
|
|
state_chart.send_event("ladder_detach")
|
|
return
|
|
|
|
func _process_jump(delta: float) -> void:
|
|
if velocity.y >= 0.0:
|
|
state_chart.send_event("jump_peak")
|
|
if not Input.is_action_pressed("jump"):
|
|
state_chart.send_event("jump_released")
|
|
|
|
## called by states SG will fall during
|
|
func _process_gravity(delta: float) -> void:
|
|
velocity.y = min(velocity.y + gravity * delta, max_fall_speed)
|
|
current_fall_speed = max(velocity.y,current_fall_speed)
|
|
|
|
## called after all other physics things
|
|
func _process_movement(delta: float) -> void:
|
|
# apply velocity and react to collisions
|
|
velocity.y += get_floor_velocity().y
|
|
velocity = move_and_slide_with_snap(velocity, snap, Vector2.UP)
|
|
|
|
# deal with that STUPID landing exactly on corner bug
|
|
var col = get_last_slide_collision()
|
|
if col != null:
|
|
if col.remainder.y >= 1.0 and col.normal.y == 0.0:
|
|
position.x += col.normal.x * 0.001
|
|
|
|
# check for wall
|
|
if is_on_wall() and (Input.get_axis("move_left", "move_right") != 0.0 or get_stick_input(JOY_AXIS_0) != 0.0):
|
|
state_chart.send_event("push_start")
|
|
|
|
func _process_floating_up(delta: float) -> void:
|
|
graphics.global_position.y -= 50.0 * delta
|
|
var sprite_sector = Game.get_sector(Vector2(global_position.x, graphics.global_position.y - 20))
|
|
if sprite_sector != Game.current_sector:
|
|
graphics.visible = false
|
|
graphics.position = Vector2.ZERO
|
|
emit_signal("died")
|
|
state_chart.send_event("respawn")
|
|
|
|
|
|
# COLLISION CALLBACKS #
|
|
func _on_Hitbox_body_entered(body: Node) -> void:
|
|
if body.is_in_group("death"):
|
|
if body.is_in_group("no_blood"):
|
|
skip_blood = true
|
|
if body.is_in_group("has_splash"):
|
|
Game.alternate_death = Audio.a_die_splash
|
|
var particles = SplashParticles.instance()
|
|
particles.global_position = death_splatter_position.global_position
|
|
particles.color = body.splash_color
|
|
particles.emitting = true
|
|
get_parent().add_child(particles)
|
|
if body.is_in_group("death_zap"):
|
|
Game.alternate_death = Audio.a_die_zap
|
|
die()
|
|
|
|
|
|
func _on_Ducking_event_received(event):
|
|
if event == "jump":
|
|
position.y -= 1
|
|
|
|
|
|
func _on_OxygenTimer_timeout():
|
|
if underwater:
|
|
state_chart.send_event("drown")
|
|
|
|
#Reset low oxygen effect when leaving level
|
|
func _on_Player_tree_exited():
|
|
set_underwater_audio(false)
|
|
|
|
|
|
func _on_Zapping_state_entered():
|
|
velocity = Vector2.ZERO
|
|
Audio.play_sound(Audio.a_die_zap, Audio.ac_die)
|
|
animation_player.call_deferred("play", "zap")
|
|
|
|
|
|
func make_blood():
|
|
var particles = DeathSplatter.instance()
|
|
particles.global_position = death_splatter_position.global_position
|
|
particles.emitting = true
|
|
get_parent().add_child(particles)
|
|
for i in 16:
|
|
var spray = BloodSpray.instance()
|
|
spray.pause_mode = PAUSE_MODE_PROCESS
|
|
Physics2DServer.set_active(true)
|
|
spray.global_position = death_splatter_position.global_position
|
|
spray.velocity = Vector2(randf() * 80.0, 0.0).rotated(randf() * TAU)
|
|
spray.stains_player = false
|
|
get_parent().add_child(spray)
|
|
|
|
|
|
func _on_Zapping_state_exited():
|
|
$Graphics/ZapSprite.visible = false
|
|
emit_signal("died")
|
|
|
|
|
|
func _on_ShieldTimer_timeout():
|
|
$Shield.visible = false
|
|
$"%AirborneShape".disabled = false
|
|
$"%GroundedShape".disabled = false
|
|
|
|
|
|
func _on_ShieldCooldown_timeout():
|
|
can_shield = true
|
|
Audio.play_sound(Audio.a_shield_cooldown,Audio.ac_boss)
|