summaryrefslogtreecommitdiff
path: root/player.gd
diff options
context:
space:
mode:
Diffstat (limited to 'player.gd')
-rw-r--r--player.gd581
1 files changed, 436 insertions, 145 deletions
diff --git a/player.gd b/player.gd
index 8ac0da7..8f78605 100644
--- a/player.gd
+++ b/player.gd
@@ -2,12 +2,18 @@ class_name Player
extends CharacterBody2D
-const SPEED = 100.0
-const JUMP_VELOCITY = -225.0
+const SPEED = 80.0
+const JUMP_VELOCITY = -200.0
const AIR_SPEED = SPEED * 0.75
-const FLY_VELOCITY = -100
+const FLY_VELOCITY = -80
+const HURT_VELOCITY = SPEED * 5
+const MAX_GRAVITY = 300.0
+const MAX_GRAVITY_AIR = 100.0
var previous_velocity: Vector2 = Vector2.ZERO
+var jump_height_modifier: float
+var last_direction: float = 1.0
+var max_gravity: float = MAX_GRAVITY
var current_state: Dictionary = state_idle():
set(new_state):
@@ -16,21 +22,54 @@ var current_state: Dictionary = state_idle():
new_state.enter.call()
current_state = new_state
+var max_hp = 2
+var hp = max_hp :
+ set(value):
+ hp = value
+ get_tree().current_scene.get_node("CanvasLayer/PanelContainer/Label").text = "HP: " + str(hp)
+
+var sprite_small_star_base: Sprite2D
+var air_shot_base: Area2D
+var star_shot_base: Area2D
+
+var is_inflated = false
+var inhale_min_duration = 0.5
+var does_inhale_transition = false
+
+var entered_door: Node2D
+
func _ready():
current_state = state_idle()
+
+ sprite_small_star_base = $SpriteSmallStar.duplicate()
+ $SpriteSmallStar.queue_free()
+
+ air_shot_base = $AirShot.duplicate()
+ $AirShot.queue_free()
+
+ star_shot_base = $StarShot.duplicate()
+ $StarShot.queue_free()
+
+ hp = max_hp # to set UI labels
+
+ $CollisionArea.add_child($CollisionShape2D.duplicate())
+
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
+ velocity.y = min(velocity.y, max_gravity)
previous_velocity = velocity
current_state.process.call(delta)
+
func apply_directional_movement(speed = SPEED):
var direction = Input.get_axis("ui_left", "ui_right")
if direction:
+ last_direction = direction
if direction < 0:
$AnimatedSprite2D.flip_h = true
else:
@@ -40,10 +79,104 @@ func apply_directional_movement(speed = SPEED):
return direction
+func apply_jump_height_modification():
+ if Input.is_action_pressed("jump"):
+ jump_height_modifier += 10
+ if jump_height_modifier > 0:
+ jump_height_modifier = 0
+ if Input.is_action_just_released("jump"):
+ velocity.y -= jump_height_modifier
+
+
+func spawn_small_star():
+ var star := sprite_small_star_base.duplicate()
+ star.global_position = global_position
+ get_tree().current_scene.add_child(star)
+ var tween = get_tree().create_tween()
+ var target_x = randi_range(-1, 1) * 16
+ var target_y = (randi_range(-1, 1) if target_x != 0 else 1) * 16
+ tween.tween_property(
+ star,
+ "global_position",
+ star.global_position + Vector2(target_x, target_y),
+ 0.1
+ )
+ tween.tween_callback(func():
+ await get_tree().create_timer(0.2).timeout
+ star.queue_free()
+ )
+
+func air_shot(direction: float):
+ var shot = air_shot_base.duplicate() as Area2D
+ shot.global_position = global_position
+ get_tree().current_scene.add_child(shot)
+
+ %SoundAirShot.play()
+ shot.get_node("Sprite2D").flip_h = direction < 0
+
+ var tween = get_tree().create_tween()
+ tween.tween_property(
+ shot,
+ "global_position",
+ shot.global_position + Vector2(sign(direction) * 64, 0),
+ 0.3
+ ).set_ease(Tween.EASE_OUT)
+ tween.tween_callback(func():
+ await get_tree().create_timer(0.3).timeout
+ shot.queue_free()
+ )
+
+func star_shot(direction: float):
+ var shot = star_shot_base.duplicate() as Area2D
+ shot.global_position = global_position
+ get_tree().current_scene.add_child(shot)
+
+ %SoundStarShot.play()
+ shot.get_node("AnimatedSprite2D").play()
+
+ var tween = get_tree().create_tween()
+
+ shot.body_entered.connect(func(body):
+ %ShotObstacleHit.play()
+ tween.stop()
+ shot.queue_free()
+ body.queue_free()
+ )
+
+ tween.tween_property(
+ shot,
+ "global_position",
+ shot.global_position + Vector2(sign(direction) * get_viewport_rect().size.x, 0),
+ 0.5
+ )
+ tween.tween_callback(func():
+ await get_tree().create_timer(0.3).timeout
+ if is_instance_valid(shot):
+ shot.queue_free()
+ )
+
+
+func check_door_enter():
+ var areas = $CollisionArea.get_overlapping_areas()
+ if areas.size() > 0 and areas[0].is_in_group("door"):
+ if Input.is_action_just_pressed("up"):
+ entered_door = areas[0].get_parent()
+ return areas[0].get_parent()
+
+ return null
+
+
+func _on_hurt_area_body_entered(body: Node2D) -> void:
+ if body.is_in_group("enemy"):
+ current_state.id = "" # to force trigger state change into hurt
+ current_state = state_hurt({"collider": body})
+
+
func state_idle():
return {
"id": "idle",
"enter": func():
+ is_inflated = false
$AnimatedSprite2D.play("idle")
,
"process": func(_delta):
@@ -54,7 +187,9 @@ func state_idle():
if direction:
current_state = state_walk()
- if Input.is_action_just_pressed("jump"):
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
current_state = state_jump()
if not is_on_floor():
@@ -85,7 +220,9 @@ func state_walk():
else:
current_state = state_idle()
- if Input.is_action_just_pressed("jump"):
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
current_state = state_jump()
if not is_on_floor():
@@ -94,6 +231,9 @@ func state_walk():
if Input.is_action_pressed("duck"):
current_state = state_duck()
+
+ if Input.is_action_just_pressed("inhale_exhale"):
+ current_state = state_inhale()
,
"exit": func():
pass
@@ -105,19 +245,25 @@ func state_jump():
return {
"id": "jump",
"enter": func():
- $SoundJump.play()
+ %SoundJump.play()
$AnimatedSprite2D.play("jump")
velocity.y = JUMP_VELOCITY
+ jump_height_modifier = JUMP_VELOCITY
,
"process": func(_delta):
- apply_directional_movement(AIR_SPEED)
+ apply_jump_height_modification()
+ apply_directional_movement()
move_and_slide()
if Input.is_action_just_pressed("jump"):
velocity.y = FLY_VELOCITY
+ %SoundFly.play()
current_state = state_fly_idle()
- if velocity.y >= 0:
+ elif Input.is_action_just_pressed("inhale_exhale"):
+ current_state = state_inhale()
+
+ elif velocity.y >= 0:
current_state = state_fall()
,
"exit": func():
@@ -138,20 +284,24 @@ func state_fall():
elif Input.is_action_just_pressed("jump"):
velocity.y = FLY_VELOCITY
+ %SoundFly.play()
current_state = state_fly_idle()
- if velocity.y > abs(JUMP_VELOCITY) * 2:
- get_node("AnimatedSprite2D").play("fall")
+ if Input.is_action_just_pressed("inhale_exhale"):
+ current_state = state_inhale()
+
+ if velocity.y >= MAX_GRAVITY:
+ $AnimatedSprite2D.play("fall")
apply_directional_movement(AIR_SPEED)
move_and_slide()
if is_on_floor():
- if previous_velocity.y > abs(JUMP_VELOCITY):
- #$SoundFall.volume_db = linear_to_db(
- #clamp(abs(previous_velocity.y) / abs(JUMP_VELOCITY*2), 0.5, 1.0)
- #)
- $SoundFall.play()
+ if $AnimatedSprite2D.animation == "fall":
+ %SoundFall2.play()
+ else:
+ %SoundFall.play()
+ spawn_small_star()
current_state = state_idle()
,
"exit": func():
@@ -180,14 +330,18 @@ func state_fly_idle():
return {
"id": "fly_idle",
"enter": func():
+ max_gravity = MAX_GRAVITY_AIR
$AnimatedSprite2D.play("fly")
,
"process": func(delta):
velocity -= (get_gravity() * delta) / 1.5
- if Input.is_action_just_pressed("jump"):
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
velocity.y = FLY_VELOCITY
$AnimatedSprite2D.play("fly")
+ %SoundFly.play()
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
@@ -197,15 +351,11 @@ func state_fly_idle():
current_state = state_fly_walk()
if Input.is_action_just_pressed("inhale_exhale"):
- $SoundExhale.play()
- current_state = state_idle()
-
- if is_on_floor():
+ air_shot(last_direction)
current_state = state_idle()
- # current_state = state_inflated_idle()
,
"exit": func():
- pass
+ max_gravity = MAX_GRAVITY
,
}
@@ -214,15 +364,20 @@ func state_fly_walk():
return {
"id": "fly_walk",
"enter": func():
+ max_gravity = MAX_GRAVITY_AIR
$AnimatedSprite2D.play("fly")
,
"process": func(delta):
velocity -= (get_gravity() * delta) / 1.5
+ velocity.y = min(velocity.y, 100)
- if Input.is_action_just_pressed("jump"):
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
velocity.y = FLY_VELOCITY
+ %SoundFly.play()
- var direction = apply_directional_movement()
+ var direction = apply_directional_movement(AIR_SPEED)
if direction:
$AnimatedSprite2D.play("fly")
move_and_slide()
@@ -230,15 +385,11 @@ func state_fly_walk():
current_state = state_fly_idle()
if Input.is_action_just_pressed("inhale_exhale"):
- $SoundExhale.play()
- current_state = state_walk()
-
- if is_on_floor():
+ air_shot(last_direction)
current_state = state_walk()
- # current_state = state_inflated_walk()
,
"exit": func():
- pass
+ max_gravity = MAX_GRAVITY
,
}
@@ -253,137 +404,277 @@ func state_inhale():
return {
"id": "inhale",
"enter": func():
+ $InhaleMinDurationTimer.wait_time = inhale_min_duration
+ $InhaleMinDurationTimer.start()
+
#$AnimationPlayer.play("inhale")
$AnimatedSprite2D.play("inhale")
- $SoundInhale.play()
- $SoundInhale.finished.connect(func():
+ %SoundInhale.play()
+ %SoundInhale.finished.connect(func():
#$SoundInhaleContinue.play()
- $SoundInhale.play()
+ %SoundInhale.play()
+ )
+
+ %InhaleArea.position.x = abs(%InhaleArea.position.x) * sign(last_direction)
+
+ %InhaleParticles.process_material.gravity.x = - (
+ abs(%InhaleParticles.process_material.gravity.x) * sign(last_direction)
)
+ %InhaleParticles.position.x = abs(%InhaleParticles.position.x) * sign(last_direction)
+ %InhaleParticles.restart()
+ %InhaleParticles.emitting = true
,
"process": func(_delta):
- if Input.is_action_just_released("inhale_exhale"):
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ move_and_slide()
+
+ var bodies = %InhaleArea.get_overlapping_bodies()
+ if bodies.size() > 0:
+ does_inhale_transition = true
+ for body in bodies:
+ body.queue_free()
+ # todo: stop process? -> remove collision -> inhale aka move towards center player -> queue_free
+ await get_tree().create_timer(inhale_min_duration).timeout
+ current_state = state_inflated_idle()
+ return
+
+ if (
+ $InhaleMinDurationTimer.is_stopped() and not does_inhale_transition and
+ (not Input.is_action_pressed("inhale_exhale") or Input.is_action_just_released("inhale_exhale"))
+ ):
current_state = state_idle()
,
"exit": func():
- $SoundInhale.stop()
+ %SoundInhale.stop()
+ %InhaleParticles.emitting = false
+ does_inhale_transition = false
,
}
func state_inflated_idle():
- return {}
+ return {
+ "id": "inflated_idle",
+ "enter": func():
+ is_inflated = true
+ $AnimatedSprite2D.play("inflated_idle")
+ ,
+ "process": func(_delta):
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ move_and_slide()
+
+ var direction = Input.get_axis("ui_left", "ui_right")
+ if direction:
+ current_state = state_inflated_walk()
+
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
+ current_state = state_inflated_jump()
+
+ if not is_on_floor():
+ #current_state = state_inflated_fall()
+ current_state = state_inflated_jump()
+
+ if Input.is_action_pressed("duck"):
+ current_state = state_digest()
+
+ if Input.is_action_just_pressed("inhale_exhale"):
+ star_shot(last_direction)
+ current_state = state_idle()
+ ,
+ "exit": func():
+ is_inflated = false
+ ,
+ }
func state_inflated_walk():
- return {}
+ return {
+ "id": "inflated_walk",
+ "enter": func():
+ is_inflated = true
+ $AnimatedSprite2D.play("inflated_walk")
+ ,
+ "process": func(_delta):
+ var direction = apply_directional_movement()
+ if direction:
+ move_and_slide()
+ else:
+ current_state = state_inflated_idle()
+
+ if check_door_enter():
+ current_state = state_enter_door()
+ elif Input.is_action_just_pressed("jump"):
+ current_state = state_inflated_jump()
+
+ if not is_on_floor():
+ $CoyoteTimer.start()
+ current_state = state_inflated_fall()
+
+ if Input.is_action_pressed("duck"):
+ current_state = state_duck()
+
+ if Input.is_action_just_pressed("inhale_exhale"):
+ star_shot(last_direction)
+ current_state = state_idle()
+ ,
+ "exit": func():
+ is_inflated = false
+ ,
+ }
+
+
+func state_inflated_jump():
+ return {
+ "id": "inflated_jump",
+ "enter": func():
+ is_inflated = true
+ %SoundJump.play()
+ $AnimatedSprite2D.play("inflated_jump")
+ velocity.y = JUMP_VELOCITY
+ jump_height_modifier = JUMP_VELOCITY
+ ,
+ "process": func(_delta):
+ apply_jump_height_modification()
+ apply_directional_movement()
+ move_and_slide()
+
+ if Input.is_action_just_pressed("inhale_exhale"):
+ star_shot(last_direction)
+ current_state = state_fall()
+
+ elif velocity.y >= 0:
+ current_state = state_inflated_fall()
+ ,
+ "exit": func():
+ is_inflated = false
+ ,
+ }
+
+
+func state_inflated_fall():
+ return {
+ "id": "fall",
+ "enter": func():
+ is_inflated = true
+ $AnimatedSprite2D.play("inflated_jump")
+ ,
+ "process": func(_delta):
+ if not $CoyoteTimer.is_stopped() and Input.is_action_just_pressed("jump"):
+ current_state = state_inflated_jump()
+
+ if Input.is_action_just_pressed("inhale_exhale"):
+ star_shot(last_direction)
+ current_state = state_fall()
+
+ apply_directional_movement(AIR_SPEED)
+ move_and_slide()
+
+ if is_on_floor():
+ %SoundFall.play()
+ spawn_small_star()
+ current_state = state_inflated_idle()
+ ,
+ "exit": func():
+ is_inflated = false
+ ,
+ }
+
+
+func state_digest():
+ return {
+ "id": "digest",
+ "enter": func():
+ %SoundDigest.play()
+ is_inflated = false
+ ,
+ "process": func(_delta):
+ current_state = state_duck()
+ ,
+ "exit": func():
+ pass
+ ,
+ }
-#class StateIdle:
- #var player: Player
- #
- #func _init(_player):
- #player = _player
- #func _get_class():
- #return "StateIdle"
- #
- #func enter():
- #player.get_node("AnimatedSprite2D").play("idle")
- #
- #func process():
- #player.velocity.x = move_toward(player.velocity.x, 0, SPEED)
- #player.move_and_slide()
- #
- #var direction = Input.get_axis("ui_left", "ui_right")
- #if direction:
- #player.current_state = StateWalk.new(player)
- #
- #if Input.is_action_just_pressed("ui_accept"):
- #player.current_state = StateJump.new(player)
- #
- #if not player.is_on_floor():
- #player.current_state = StateFall.new(player)
- #
- #func exit():
- #pass
-#
-#class StateWalk:
- #var player: Player
- #
- #func _init(_player):
- #player = _player
- #func _get_class():
- #return "StateWalk"
- #
- #func enter():
- #player.get_node("AnimatedSprite2D").play("walk")
- #
- #func process():
- #var direction = player.apply_directional_movement()
- #if direction:
- #player.move_and_slide()
- #else:
- #player.current_state = StateIdle.new(player)
- #
- #if Input.is_action_just_pressed("ui_accept"):
- #player.current_state = StateJump.new(player)
- #
- #if not player.is_on_floor():
- #player.get_node("CoyoteTimer").start()
- #player.current_state = StateFall.new(player)
- #
- #func exit():
- #pass
-#
-#class StateJump:
- #var player: Player
- #
- #func _init(_player):
- #player = _player
- #func _get_class():
- #return "StateJump"
- #
- #func enter():
- #player.get_node("SoundJump").play()
- #player.get_node("AnimatedSprite2D").play("jump")
- #player.velocity.y = JUMP_VELOCITY
- #
- #func process():
- #player.apply_directional_movement(AIR_SPEED)
- #player.move_and_slide()
- #
- #if player.velocity.y >= 0:
- #player.current_state = StateFall.new(player)
- #
- #func exit():
- #pass
-#
-#class StateFall:
- #var player: Player
- #var is_falling = false
- #
- #func _init(_player):
- #player = _player
- #func _get_class():
- #return "StateFall"
- #
- #func enter():
- #player.get_node("AnimatedSprite2D").play("jump")
- #
- #func process():
- #if not player.get_node("CoyoteTimer").is_stopped() and Input.is_action_just_pressed("ui_accept"):
- #player.current_state = StateJump.new(player)
- #
- #if player.velocity.y > abs(JUMP_VELOCITY) * 2:
- #is_falling = true
- #player.get_node("AnimatedSprite2D").play("fall")
- #
- #player.apply_directional_movement(AIR_SPEED)
- #player.move_and_slide()
- #
- #if player.is_on_floor():
- #player.get_node("SoundFall").play()
- #player.current_state = StateIdle.new(player)
- #
- #func exit():
- #pass
+func state_hurt(data):
+ return {
+ "id": "hurt",
+ "enter": func():
+ if data.collider.is_in_group("enemy"):
+ data.collider.queue_free()
+
+ hp -= 1
+ if hp == 0:
+ %SoundNoHp.play()
+ #current_state = state_game_over()
+ else:
+ %SoundHurt.play()
+
+ if is_inflated:
+ $AnimatedSprite2D.play("inflated_jump")
+ else:
+ $AnimatedSprite2D.play("jump")
+
+ var impulse = sign(global_position - data.collider.global_position) * HURT_VELOCITY
+ velocity.x = impulse.x
+ velocity.y = -100
+
+ move_and_slide()
+ velocity.x = 0
+
+ var tween = get_tree().create_tween()
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1, 1, 1, 0.2), 0.1)
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1, 1, 1, 0.8), 0.1)
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1, 1, 1, 0.2), 0.1)
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1, 1, 1, 0.8), 0.1)
+ tween.tween_callback(func():
+ $AnimatedSprite2D.self_modulate = Color(1, 1, 1, 1)
+ if is_inflated:
+ current_state = state_inflated_idle()
+ else:
+ current_state = state_idle()
+ )
+ ,
+ "process": func(_delta):
+ move_and_slide()
+ ,
+ "exit": func():
+ pass
+ ,
+ }
+
+func state_enter_door():
+ return {
+ "id": "enter_door",
+ "enter": func():
+ SoundManager.play("EnterDoor")
+ $AnimatedSprite2D.play("enter_door")
+
+ # TODO
+ var canvas_layer = CanvasLayer.new()
+ var color_rect = ColorRect.new()
+ color_rect.size = get_viewport_rect().size
+ color_rect.color = Color(1,1,1,0)
+ canvas_layer.add_child(color_rect)
+ get_tree().current_scene.add_child(canvas_layer)
+ var tween = get_tree().create_tween()
+ tween.tween_property(
+ color_rect,
+ "color",
+ Color(1,1,1,1),
+ 0.3
+ )
+ tween.tween_callback(func():
+ $AnimatedSprite2D.play("exit_door")
+ Game.transition_scene_with_door(entered_door)
+ )
+ ,
+ "process": func(_delta):
+ pass
+ ,
+ "exit": func():
+ pass
+ ,
+ }