146 lines
4.1 KiB
GDScript
146 lines
4.1 KiB
GDScript
extends CharacterBody2D
|
|
@onready var bullet = preload("res://scene/entities/bullet.tscn")
|
|
@onready var animated_sprite = $AnimatedSprite2D
|
|
@onready var muzzle = $FIRE
|
|
@onready var TimerFIRE = $TimerFIRE
|
|
@onready var hurt_timer = $Timerinvincibility
|
|
const SPEED = 140.0
|
|
const JUMP_VELOCITY = -230.0
|
|
const JUMP_MAX = 2
|
|
var JUMP_COUNT = 0
|
|
var HP = 3
|
|
var invincibility = false
|
|
var is_jump : bool = false
|
|
var respawn_position
|
|
|
|
@onready var hp_icons = [
|
|
$HP_Block, # 对应第1滴血
|
|
$HP_Block2, # 对应第2滴血
|
|
$HP_Block3 # 对应第3滴血
|
|
]
|
|
const MAX_HP = 3 # 最大血量
|
|
|
|
# 刷新 UI 的核心函数
|
|
func _update_hp_ui():
|
|
# 遍历所有的生命图标
|
|
for i in range(hp_icons.size()):
|
|
# 如果索引小于当前HP,就显示,否则隐藏
|
|
# 比如 HP=2,那么 i=0(显示)、i=1(显示)、i=2(隐藏)
|
|
hp_icons[i].visible = i < HP
|
|
|
|
func _ready() -> void:
|
|
animated_sprite.play("IDLE")
|
|
add_to_group("Player")
|
|
hurt_timer.timeout.connect(_on_hurt_timer_timeout)
|
|
|
|
# 1. 从全局单例读取血量(注意大小写要和 Global.gd 里一致!)
|
|
if Global:
|
|
HP = Global.player_HP
|
|
else:
|
|
HP = 3 # 如果没有全局单例,默认给3滴血(防止报错)
|
|
|
|
# 2. 寻找第二关场景里的出生点 (需要你给出生点节点加上 "SpawnPoint" 组)
|
|
var spawn_point = get_tree().get_first_node_in_group("SpawnPoint")
|
|
if spawn_point:
|
|
global_position = spawn_point.global_position # 把玩家移动到出生点
|
|
|
|
# 3. 更新玩家死亡后的复活点(非常重要!否则在第二关死了会复活回第一关的位置)
|
|
respawn_position = global_position
|
|
|
|
# 4. 刷新血量UI,确保血条显示正确
|
|
_update_hp_ui()
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
# Add the gravity.
|
|
if not is_on_floor():
|
|
velocity += get_gravity() * delta
|
|
else:
|
|
JUMP_COUNT = 0
|
|
# Handle jump.
|
|
if Input.is_action_just_pressed("move_up") and JUMP_COUNT < JUMP_MAX:
|
|
velocity.y = JUMP_VELOCITY
|
|
animated_sprite.play("JUMP")
|
|
JUMP_COUNT += 1
|
|
if JUMP_COUNT == 1:
|
|
is_jump = true
|
|
animated_sprite.play("JUMP")
|
|
is_jump = false
|
|
elif JUMP_COUNT == 2:
|
|
animated_sprite.play("DOUBLE_JUMP")
|
|
await get_tree().create_timer(0.26).timeout
|
|
animated_sprite.play("JUMP")
|
|
|
|
|
|
|
|
# Get the input direction and handle the movement/deceleration.
|
|
# As good practice, you should replace UI actions with custom gameplay actions.
|
|
var direction := Input.get_axis("move_left", "move_right")
|
|
|
|
if invincibility:#无敌帧
|
|
if direction < 0: #无敌阵期间
|
|
animated_sprite.flip_h = true
|
|
elif direction > 0:
|
|
animated_sprite.flip_h = false
|
|
velocity.x = SPEED * direction
|
|
move_and_slide()
|
|
else:
|
|
if direction < 0: #动画运行
|
|
animated_sprite.flip_h = true
|
|
elif direction > 0:
|
|
animated_sprite.flip_h = false
|
|
if direction != 0 :
|
|
velocity.x = SPEED * direction #RUN动画
|
|
if animated_sprite.animation != "RUN" and is_on_floor() and not is_jump:
|
|
animated_sprite.play("RUN")
|
|
else: #IDLE动画
|
|
if is_on_floor() and not is_jump:
|
|
velocity.x = move_toward(velocity.x, 0, SPEED)
|
|
animated_sprite.play("IDLE")
|
|
|
|
move_and_slide()
|
|
|
|
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and TimerFIRE.is_stopped():
|
|
shoot()
|
|
TimerFIRE.start()
|
|
|
|
|
|
func shoot(): #射击
|
|
var bullet_scene = bullet.instantiate()
|
|
var mouse_pos = get_global_mouse_position()
|
|
bullet_scene.target_pos = mouse_pos
|
|
bullet_scene.global_position = muzzle.global_position
|
|
get_parent().add_child(bullet_scene)
|
|
|
|
func die(): #死亡
|
|
HP = 3
|
|
velocity = Vector2.ZERO
|
|
global_position = respawn_position
|
|
_update_hp_ui()
|
|
animated_sprite.play("IDLE")
|
|
invincibility = true
|
|
hurt_timer.start()
|
|
|
|
|
|
func take_damage(amount:int): #伤害
|
|
if invincibility:
|
|
return
|
|
HP -= amount
|
|
if HP <0:
|
|
HP = 0
|
|
_update_hp_ui()
|
|
animated_sprite.play("HIT")
|
|
#print("当前的HP是:", HP)
|
|
if HP <= 0:
|
|
die()
|
|
else:
|
|
invincibility = true # 开启无敌
|
|
hurt_timer.start() # 启动无敌计时器
|
|
func _on_hurt_timer_timeout() -> void:
|
|
invincibility = false
|
|
|
|
func heal(amount:int):
|
|
if HP >= MAX_HP:
|
|
return
|
|
HP += amount
|
|
_update_hp_ui()
|