Commit 57468de7 authored by Gavin An's avatar Gavin An

작업중

parent 36a467ae
......@@ -2,6 +2,7 @@ class_name BaseUnit
extends CharacterBody3D
const UnitHelper = preload("res://src/entities/units/unit_helper.gd")
const MELEE_HIT_CONFIRM_PADDING: float = 0.05
## 플레이어 유닛 기본 클래스 (RTS 식 이동, 몬스터 자동 감지 및 공격 수행)
......@@ -31,7 +32,10 @@ var _model_instance: Node3D = null
var _model_anim_player: AnimationPlayer = null
var _last_anim_state: String = ""
var _is_currently_attacking: bool = false
var _attack_lock_timer: float = 0.0 # 공격 모션 완주 및 물리 이동 차단을 위한 타이머
var _attack_lock_timer: float = 0.0 # 공격 모션 재생 시간을 추적하는 타이머입니다.
var _melee_move_lock_timer: float = 0.0 # 근접 공격의 타격 확정 전까지만 이동을 막는 별도 타이머입니다.
var _has_queued_move_after_attack: bool = false
var _queued_move_position: Vector3 = Vector3.ZERO
var attack_speed_mult: float = 1.0 # 소환사 주문(가속) 등으로 변경 가능한 공속 배율
func _ready() -> void:
......@@ -64,6 +68,10 @@ func _physics_process(delta: float) -> void:
_attack_timer -= delta * attack_speed_mult
if _attack_lock_timer > 0.0:
_attack_lock_timer -= delta * attack_speed_mult
if _melee_move_lock_timer > 0.0:
_melee_move_lock_timer -= delta * attack_speed_mult
if _melee_move_lock_timer <= 0.0 and _has_queued_move_after_attack:
_apply_move_command(_queued_move_position)
if _auto_target_cooldown > 0.0:
_auto_target_cooldown -= delta
......@@ -108,10 +116,12 @@ func _process_attack_logic(_delta: float) -> void:
if not _target_monster:
_is_currently_attacking = false
_attack_lock_timer = 0.0
_melee_move_lock_timer = 0.0
return
# 공격 모션 재생 중(공격 잠금 시간 동안)에는 무조건 이동하지 않고 멈춰서 공격 모션 유지
if _attack_lock_timer > 0.0:
# 근접 유닛은 타격이 확정되기 전까지만 제자리에 고정합니다.
# 타격 판정 이후의 후딜 구간은 이동 명령으로 빠져나갈 수 있게 두어 웨이브에 갇히는 상황을 줄입니다.
if _is_melee_attack_locked():
_is_currently_attacking = true
velocity.x = 0.0
velocity.z = 0.0
......@@ -262,6 +272,7 @@ func _try_attack() -> void:
var target_ref: Node3D = _target_monster
var damage_amount: float = unit_data.damage
var damage_delay: float = _attack_lock_timer * 0.5
_set_melee_move_lock_until_hit(damage_delay)
if damage_delay > 0.0:
get_tree().create_timer(damage_delay).timeout.connect(
......@@ -286,21 +297,55 @@ func _show_attack_visual() -> void:
func hold_position() -> void:
_is_holding = true
_target_monster = null
_has_queued_move_after_attack = false
_nav_agent.target_position = global_position
velocity = Vector3.ZERO
## 외부에서 호출하는 수동 이동 명령
func move_to(target_pos: Vector3) -> void:
# 근접 유닛은 타격 확정 전 이동 명령을 잠시 보관했다가, 판정 직후 바로 이동합니다.
# 원거리 유닛이나 근접 후딜 구간은 즉시 공격을 끊고 이동해 조작 반응성을 유지합니다.
if _is_melee_attack_locked():
_has_queued_move_after_attack = true
_queued_move_position = target_pos
velocity.x = 0.0
velocity.z = 0.0
if _target_monster and is_instance_valid(_target_monster):
_look_at_target(_target_monster.global_position)
return
_apply_move_command(target_pos)
## 실제 수동 이동 상태 전환을 한곳에서 처리합니다.
## - 근접 공격의 후딜 캔슬과 원거리 카이팅 모두 이 경로를 공유합니다.
func _apply_move_command(target_pos: Vector3) -> void:
_is_holding = false # 수동 조작 시 홀드 해제
_target_monster = null # 이동 명령 시 강제 공격 해제
_attack_lock_timer = 0.0 # 공격 애니메이션 진행 중이더라도 강제 이동 명령 시 즉시 캔슬하고 이동 (스타크래프트 식 무빙 캔슬)
_attack_lock_timer = 0.0 # 타격 확정 이후의 후딜 또는 원거리 공격 모션은 이동 명령으로 캔슬합니다.
_melee_move_lock_timer = 0.0
_is_currently_attacking = false
_has_queued_move_after_attack = false
_auto_target_cooldown = 0.5 # 수동 강제 이동 시 0.5초 동안 자동 공격 타겟 지정을 비활성화하여 피신을 허용
_nav_agent.target_position = target_pos
## 근접 공격의 타격 확정 전 구간인지 확인합니다.
## - 원거리 유닛은 공격 모션 타이머가 있어도 이동 가능해야 하므로 false를 반환합니다.
func _is_melee_attack_locked() -> bool:
return unit_data != null and not unit_data.is_ranged and _melee_move_lock_timer > 0.0
## 근접 공격 판정이 확정되기 전까지만 이동을 막습니다.
## - 아주 짧은 패딩을 더해 데미지 타이머 신호가 먼저 처리될 여유를 둡니다.
func _set_melee_move_lock_until_hit(damage_delay: float) -> void:
if unit_data == null or unit_data.is_ranged:
_melee_move_lock_timer = 0.0
return
_melee_move_lock_timer = maxf(0.0, damage_delay + MELEE_HIT_CONFIRM_PADDING)
## 외부에서 호출하는 특정 몬스터 강제 공격 지정
func attack_target(monster: Node3D) -> void:
_is_holding = false # 강제 공격 시 홀드 해제
_has_queued_move_after_attack = false
if is_instance_valid(monster) and not monster.get("is_dead"):
_target_monster = monster
_nav_agent.target_position = monster.global_position
......
......@@ -58,6 +58,7 @@ func _try_attack() -> void:
var target_ref: Node3D = _target_monster
var damage_amount: float = unit_data.damage
var damage_delay: float = _attack_lock_timer * DWARF_ATTACK_DAMAGE_RATIO
_set_melee_move_lock_until_hit(damage_delay)
# 도끼가 몸 앞쪽으로 떨어지는 구간에 데미지가 들어가도록 지연시켜 시각적 타격감과 판정을 맞춥니다.
if damage_delay > 0.0:
......
[gd_scene format=3 uid="uid://np5fiyv02pk"]
[ext_resource type="PackedScene" uid="uid://lswmiam1ftlw" path="res://src/entities/hero/dwarf/dwarf.tscn" id="1_b0qj8"]
[ext_resource type="Script" uid="uid://dsckp7uaawijh" path="res://src/entities/hero/dwarf/dwarf_hero.gd" id="1_cthrw"]
[ext_resource type="PackedScene" uid="uid://lswmiam1ftlw" path="res://src/entities/units/hero/dwarf/dwarf.tscn" id="1_b0qj8"]
[ext_resource type="Script" uid="uid://dsckp7uaawijh" path="res://src/entities/units/hero/dwarf/dwarf_hero.gd" id="1_cthrw"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_pe3j2"]
radius = 0.4
......
......@@ -332,7 +332,7 @@ func _on_summon_hero_pressed() -> void:
return
var chosen_template: UnitData = DataManager.hero_templates[0]
var hero_scene: PackedScene = load("res://src/entities/hero/dwarf/dwarf_hero.tscn") as PackedScene
var hero_scene: PackedScene = load("res://src/entities/units/hero/dwarf/dwarf_hero.tscn") as PackedScene
if not hero_scene:
print("HUD Error: Failed to load dwarf_hero.tscn!")
return
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment