player.tscn: scholar of the first bullet casings
This commit is contained in:
parent
79cbd62a69
commit
bc57ba4171
45 changed files with 1429 additions and 113 deletions
265
objects/player/player_scholar.gd
Normal file
265
objects/player/player_scholar.gd
Normal file
|
@ -0,0 +1,265 @@
|
|||
extends KinematicBody2D
|
||||
|
||||
# SIGNALS #
|
||||
signal died()
|
||||
|
||||
# CONSTANTS #
|
||||
const ArrowProjectile = preload("res://objects/player/arrow_projectile.tscn")
|
||||
const DeathSplatter = preload("res://objects/player/player_death_particles.tscn")
|
||||
|
||||
# EXPORTS #
|
||||
## horizontal movement speed
|
||||
export var walk_speed: float = 50.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
|
||||
|
||||
|
||||
# velocity
|
||||
var velocity: Vector2 = Vector2.ZERO
|
||||
# snap vector
|
||||
var snap: Vector2 = Vector2.ZERO
|
||||
# ladder currently attached to
|
||||
var _attached_ladder: Node2D = null
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
|
||||
# OVERRIDES #
|
||||
func _ready() -> void:
|
||||
Game.respawn_point = global_position
|
||||
connect("died", Game, "_on_player_died")
|
||||
move_and_slide(Vector2(0.0, 1.0), Vector2.UP)
|
||||
state_chart.initialize()
|
||||
state_chart.set_guard_property("can_respawn", true)
|
||||
$StateDebugLayer/StateChartDebug.target = state_chart
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
# 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("jump"): # jumping
|
||||
state_chart.send_event("jump")
|
||||
if Input.is_action_just_pressed("shoot"): # shooting
|
||||
state_chart.send_event("shoot")
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
# STATE ENTERS/EXITS #
|
||||
func _on_Grounded_state_entered() -> void:
|
||||
# still jump if pressed frame hit ground
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
print("BOING")
|
||||
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
|
||||
|
||||
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("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:
|
||||
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()
|
||||
velocity = Vector2.ZERO
|
||||
snap = Vector2.ZERO
|
||||
if global_position.x < _attached_ladder.middle:
|
||||
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
|
||||
animation_player.play("climb")
|
||||
|
||||
func _on_Climbing_state_exited() -> void:
|
||||
_attached_ladder = null
|
||||
animation_player.playback_speed = 1.0 # restore playback speed
|
||||
|
||||
# all the stuff that happens when they DIE
|
||||
func _on_Dead_state_entered() -> void:
|
||||
# send signals
|
||||
emit_signal("died")
|
||||
state_chart.send_event("died")
|
||||
# spawn death particles
|
||||
var particles = DeathSplatter.instance()
|
||||
particles.global_position = death_splatter_position.global_position
|
||||
particles.emitting = true
|
||||
get_parent().add_child(particles)
|
||||
# fade into the ether
|
||||
graphics.visible = false
|
||||
state_chart.send_event("respawn")
|
||||
|
||||
func _on_Respawn_state_entered() -> void:
|
||||
global_position = Game.respawn_point
|
||||
graphics.visible = true
|
||||
state_chart.call_deferred("send_event", "get_real")
|
||||
|
||||
|
||||
# STATE PROCESSING #
|
||||
## when on ground
|
||||
func _process_grounded(delta: float) -> void:
|
||||
# make sure is_on_floor detected still
|
||||
velocity.y = 1.0
|
||||
|
||||
## 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("ui_left", "ui_right")) # sign() to normalize
|
||||
velocity.x = input_dir * 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("ui_left", "ui_right")) != 0.0:
|
||||
animation_player.play("walk")
|
||||
else:
|
||||
animation_player.play("idle")
|
||||
|
||||
## climbing on ladders
|
||||
func _process_climbing(delta: float) -> void:
|
||||
# climbing movement
|
||||
var input_dir = sign(Input.get_axis("ui_up", "ui_down"))
|
||||
velocity.y = input_dir * climb_speed # move in input direction
|
||||
animation_player.playback_speed = abs(input_dir) # play/pause animation
|
||||
|
||||
# # switching sides of ladder
|
||||
# if global_position.x < _attached_ladder.middle and Input.is_action_just_pressed("ui_right"):
|
||||
# global_position.x = _attached_ladder.right_snap
|
||||
# graphics.scale.x = -1SimCity.0SimCitySimCity
|
||||
# elif Input.is_action_just_pressed("ui_left"):
|
||||
# global_position.x = _attached_ladder.left_snap
|
||||
# graphics.scale.x = 1.0
|
||||
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
global_position.x -= graphics.scale.x * 3.0
|
||||
state_chart.send_event("jump")
|
||||
if Input.is_action_just_pressed("shoot"):
|
||||
global_position.x -= graphics.scale.x * 3.0
|
||||
state_chart.send_event("ladder_detach")
|
||||
|
||||
# check if still on ladder
|
||||
if ladder_detector.get_collider() != _attached_ladder:
|
||||
if input_dir == -1.0:
|
||||
state_chart.send_event("jump")
|
||||
else:
|
||||
state_chart.send_event("ladder_detach")
|
||||
|
||||
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)
|
||||
|
||||
## called after all other physics things
|
||||
func _process_movement(delta: float) -> void:
|
||||
# apply velocity and react to collisions
|
||||
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
|
||||
|
||||
|
||||
# COLLISION CALLBACKS #
|
||||
func _on_Hitbox_body_entered(body: Node) -> void:
|
||||
if body.is_in_group("death"):
|
||||
die()
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue