Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
L
ldefense
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Packages
Packages
Container Registry
Analytics
CI / CD Analytics
Repository Analytics
Value Stream Analytics
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Gavin An
ldefense
Commits
45c18ca1
Commit
45c18ca1
authored
Jul 20, 2026
by
Gavin An
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
유닛 생성 시 미리보기 추가
parent
46fd46de
Changes
19
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1558 additions
and
692 deletions
+1558
-692
src/core/main.gd
src/core/main.gd
+90
-0
src/core/projectile_pool.gd
src/core/projectile_pool.gd
+157
-0
src/core/projectile_pool.gd.uid
src/core/projectile_pool.gd.uid
+1
-0
src/entities/summoner/summoner.gd
src/entities/summoner/summoner.gd
+28
-16
src/entities/units/base/base_unit.gd
src/entities/units/base/base_unit.gd
+10
-6
src/entities/units/base/projectile.gd
src/entities/units/base/projectile.gd
+93
-5
src/entities/units/mage/mage_unit.gd
src/entities/units/mage/mage_unit.gd
+16
-0
src/entities/units/ranger/ranger_unit.gd
src/entities/units/ranger/ranger_unit.gd
+16
-0
src/map/background/desert.tscn
src/map/background/desert.tscn
+1
-1
src/ui/hero_panel/hud_hero_panel.gd
src/ui/hero_panel/hud_hero_panel.gd
+328
-0
src/ui/hero_panel/hud_hero_panel.gd.uid
src/ui/hero_panel/hud_hero_panel.gd.uid
+1
-0
src/ui/hud.gd
src/ui/hud.gd
+115
-664
src/ui/summoner_panel/hud_summoner_panel.gd
src/ui/summoner_panel/hud_summoner_panel.gd
+161
-0
src/ui/summoner_panel/hud_summoner_panel.gd.uid
src/ui/summoner_panel/hud_summoner_panel.gd.uid
+1
-0
src/ui/unit_placement/hud_unit_placement.gd
src/ui/unit_placement/hud_unit_placement.gd
+490
-0
src/ui/unit_placement/hud_unit_placement.gd.uid
src/ui/unit_placement/hud_unit_placement.gd.uid
+1
-0
src/ui/unit_placement/placement_tile_overlay.gd
src/ui/unit_placement/placement_tile_overlay.gd
+36
-0
src/ui/unit_placement/placement_tile_overlay.gd.uid
src/ui/unit_placement/placement_tile_overlay.gd.uid
+1
-0
src/ui/unit_placement/placement_tile_overlay.tscn
src/ui/unit_placement/placement_tile_overlay.tscn
+12
-0
No files found.
src/core/main.gd
View file @
45c18ca1
extends
Node3D
extends
Node3D
const
ProjectilePoolScript
:
GDScript
=
preload
(
"res://src/core/projectile_pool.gd"
)
## 메인 전장 월드 씬 루트 스크립트 (Main)
## 메인 전장 월드 씬 루트 스크립트 (Main)
## 스테이지 선택에 따른 맵 데이터를 동적으로 읽어 전장에 탑재합니다.
## 스테이지 선택에 따른 맵 데이터를 동적으로 읽어 전장에 탑재합니다.
## 1스테이지에서 사용할 기본 태양광 밝기입니다.
## 값이 클수록 DirectionalLight3D가 전장을 더 강하게 비춥니다.
@
export
var
stage_1_light_energy
:
float
=
1.2
## 마지막 스테이지에서 사용할 태양광 밝기입니다.
## 스테이지가 진행될수록 이 값에 가까워져 후반부 분위기가 어두워집니다.
@
export
var
final_stage_light_energy
:
float
=
0.35
## 스테이지 변경 시 조명 밝기가 목표값까지 전환되는 시간입니다.
## 0 이하로 설정하면 보간 없이 즉시 밝기가 바뀝니다.
@
export
var
stage_light_transition_time
:
float
=
0.6
## main.tscn 루트에 배치된 주 광원입니다.
## 스테이지별 분위기 연출을 위해 light_energy만 런타임에 조정합니다.
@
onready
var
_directional_light
:
DirectionalLight3D
=
$
DirectionalLight3D
## 스테이지가 빠르게 바뀌는 경우 이전 밝기 전환을 중단하기 위한 Tween 참조입니다.
var
_light_tween
:
Tween
## 런타임에 생성되는 발사체 풀입니다.
## main.tscn 원본을 직접 수정하지 않고 코드에서 노드를 붙여 프로젝트 지침을 지킵니다.
var
_projectile_pool
:
Node
=
null
func
_enter_tree
()
->
void
:
func
_enter_tree
()
->
void
:
var
map_path
:
String
=
"res://src/map/stages/stage_1_map.tscn"
# 기본 맵
var
map_path
:
String
=
"res://src/map/stages/stage_1_map.tscn"
# 기본 맵
if
GameManager
.
selected_stage_map_path
!=
""
:
if
GameManager
.
selected_stage_map_path
!=
""
:
...
@@ -11,6 +36,21 @@ func _enter_tree() -> void:
...
@@ -11,6 +36,21 @@ func _enter_tree() -> void:
_load_stage_background
(
map_path
)
_load_stage_background
(
map_path
)
_load_stage_map
(
map_path
)
_load_stage_map
(
map_path
)
func
_ready
()
->
void
:
_setup_projectile_pool
()
# GameManager의 current_stage setter가 stage_changed를 발행하므로,
# Main은 이 신호만 구독해 스테이지 진행과 조명 연출을 느슨하게 연결합니다.
GameManager
.
stage_changed
.
connect
(
_on_stage_changed
)
# 이미 선택된 현재 스테이지 밝기를 씬 시작 시 즉시 반영합니다.
# 초기 밝기는 전환 애니메이션 없이 맞춰야 첫 프레임부터 의도한 분위기가 나옵니다.
_apply_stage_light_energy
(
GameManager
.
current_stage
,
true
)
# 전장 첫 진입 직후 투사체 이펙트를 미리 준비합니다.
# 실제 전투가 시작되기 전에 GLB, 셰이더, 파티클 리소스가 한 번 구성되도록 유도합니다.
_warmup_projectile_effects_deferred
()
func
_load_stage_map
(
map_path
:
String
)
->
void
:
func
_load_stage_map
(
map_path
:
String
)
->
void
:
var
map_scene
:
PackedScene
=
load
(
map_path
)
as
PackedScene
var
map_scene
:
PackedScene
=
load
(
map_path
)
as
PackedScene
if
map_scene
:
if
map_scene
:
...
@@ -47,3 +87,53 @@ func _get_background_path_for_map(map_path: String) -> String:
...
@@ -47,3 +87,53 @@ func _get_background_path_for_map(map_path: String) -> String:
return
"res://src/map/background/swamp.tscn"
return
"res://src/map/background/swamp.tscn"
_
:
_
:
return
""
return
""
## 발사체 풀 노드를 런타임에 생성해 Main의 자식으로 배치합니다.
## 원거리 유닛은 projectile_pool 그룹을 통해 이 노드를 찾아 공통으로 재사용합니다.
func
_setup_projectile_pool
()
->
void
:
_projectile_pool
=
ProjectilePoolScript
.
new
()
as
Node
_projectile_pool
.
name
=
"ProjectilePool"
add_child
(
_projectile_pool
)
if
_projectile_pool
.
has_method
(
"initialize_pool"
):
_projectile_pool
.
call
(
"initialize_pool"
)
## 첫 전투 중 끊김을 줄이기 위해 투사체 이펙트를 지연 워밍업합니다.
## 한 프레임 뒤에 실행하면 Main과 카메라/월드 노드가 준비된 뒤 리소스 초기화가 진행됩니다.
func
_warmup_projectile_effects_deferred
()
->
void
:
await
get_tree
()
.
process_frame
if
_projectile_pool
and
_projectile_pool
.
has_method
(
"warmup_projectile_effects"
):
_projectile_pool
.
call
(
"warmup_projectile_effects"
)
func
_on_stage_changed
(
stage
:
int
)
->
void
:
# 스테이지 숫자가 바뀔 때마다 해당 진행도에 맞는 광량으로 전환합니다.
_apply_stage_light_energy
(
stage
)
## 스테이지 진행도에 따라 DirectionalLight3D의 밝기를 계산하고 적용합니다.
## - 1스테이지는 stage_1_light_energy를 사용합니다.
## - 마지막 스테이지는 final_stage_light_energy를 사용합니다.
## - 중간 스테이지는 두 값 사이를 선형 보간합니다.
func
_apply_stage_light_energy
(
stage
:
int
,
instant
:
bool
=
false
)
->
void
:
if
not
_directional_light
:
return
# stage_progress는 0.0(첫 스테이지)부터 1.0(마지막 스테이지)까지의 정규화된 진행도입니다.
# clampf로 범위를 고정해 디버그 중 비정상 스테이지 값이 들어와도 광량이 과하게 튀지 않게 합니다.
var
stage_progress
:
float
=
0.0
if
GameManager
.
MAX_STAGE
>
1
:
stage_progress
=
clampf
(
float
(
stage
-
1
)
/
float
(
GameManager
.
MAX_STAGE
-
1
),
0.0
,
1.0
)
# 진행도에 따라 밝은 초반 광량에서 어두운 후반 광량으로 자연스럽게 이동합니다.
var
target_energy
:
float
=
lerpf
(
stage_1_light_energy
,
final_stage_light_energy
,
stage_progress
)
# 이전 스테이지 전환 애니메이션이 남아 있다면 중복 적용을 막기 위해 중단합니다.
if
_light_tween
:
_light_tween
.
kill
()
# 초기 적용 또는 전환 시간이 없는 설정에서는 Tween 없이 즉시 목표 밝기를 반영합니다.
if
instant
or
stage_light_transition_time
<=
0.0
:
_directional_light
.
light_energy
=
target_energy
return
# 실제 플레이 중 스테이지가 넘어갈 때는 짧은 보간으로 밝기를 부드럽게 바꿉니다.
_light_tween
=
create_tween
()
_light_tween
.
tween_property
(
_directional_light
,
"light_energy"
,
target_energy
,
stage_light_transition_time
)
src/core/projectile_pool.gd
0 → 100644
View file @
45c18ca1
class_name
ProjectilePool
extends
Node3D
## 원거리 발사체와 투사체 비주얼 이펙트를 미리 만들어 재사용하는 런타임 풀입니다.
## - 첫 공격 순간에 PackedScene 인스턴싱, GLB 업로드, 셰이더/파티클 준비 비용이 몰리는 현상을 줄입니다.
## - 전투 중에는 queue_free() 대신 비활성화 후 재사용하여 잦은 생성/삭제로 인한 프레임 끊김을 줄입니다.
const
ProjectileScript
:
GDScript
=
preload
(
"res://src/entities/units/base/projectile.gd"
)
const
FIREBALL_EFFECT_SCENE
:
PackedScene
=
preload
(
"res://src/entities/projectiles/fireball/fireball_effect.tscn"
)
const
ARROW_EFFECT_SCENE
:
PackedScene
=
preload
(
"res://src/entities/projectiles/arrow/arrow_effect.tscn"
)
const
PROJECTILE_KEY_FIREBALL
:
String
=
"fireball"
const
PROJECTILE_KEY_ARROW
:
String
=
"arrow"
const
PROJECTILE_KEY_SPHERE
:
String
=
"sphere"
## 전투 시작 전 미리 준비할 화염구 발사체 수입니다.
## 마법사 수가 늘어 동시에 여러 발이 나가도 런타임 인스턴싱이 적게 발생하도록 여유분을 둡니다.
@
export
var
fireball_pool_size
:
int
=
16
## 전투 시작 전 미리 준비할 화살 발사체 수입니다.
## 레인저는 공격 속도가 빠른 편이므로 화염구보다 조금 더 넉넉히 준비합니다.
@
export
var
arrow_pool_size
:
int
=
24
## 커스텀 비주얼을 쓰지 않는 기본 구체 발사체 예비 수입니다.
## 현재는 fallback 용도지만, 다른 원거리 유닛이 추가될 때 재사용할 수 있습니다.
@
export
var
sphere_pool_size
:
int
=
8
## 워밍업 인스턴스가 잠시 배치될 위치입니다.
## 카메라 밖/전장 밖에 두어 플레이어에게 보이지 않게 하면서 리소스 초기화를 유도합니다.
@
export
var
warmup_position
:
Vector3
=
Vector3
(
0.0
,
-
100.0
,
0.0
)
var
_available_projectiles
:
Dictionary
=
{}
var
_visual_scenes
:
Dictionary
=
{}
var
_is_initialized
:
bool
=
false
func
_ready
()
->
void
:
initialize_pool
()
## 풀을 한 번만 초기화합니다.
## Main에서 명시적으로 호출해도 되고, 노드가 씬 트리에 들어올 때 _ready()를 통해 자동 실행되어도 안전합니다.
func
initialize_pool
()
->
void
:
if
_is_initialized
:
return
_is_initialized
=
true
add_to_group
(
"projectile_pool"
)
_visual_scenes
=
{
PROJECTILE_KEY_FIREBALL
:
FIREBALL_EFFECT_SCENE
,
PROJECTILE_KEY_ARROW
:
ARROW_EFFECT_SCENE
,
PROJECTILE_KEY_SPHERE
:
null
}
_available_projectiles
.
clear
()
_available_projectiles
[
PROJECTILE_KEY_FIREBALL
]
=
[]
_available_projectiles
[
PROJECTILE_KEY_ARROW
]
=
[]
_available_projectiles
[
PROJECTILE_KEY_SPHERE
]
=
[]
_create_projectiles
(
PROJECTILE_KEY_FIREBALL
,
fireball_pool_size
)
_create_projectiles
(
PROJECTILE_KEY_ARROW
,
arrow_pool_size
)
_create_projectiles
(
PROJECTILE_KEY_SPHERE
,
sphere_pool_size
)
## 지정된 종류의 발사체를 풀에 미리 생성합니다.
## 생성 직후에는 비활성화 상태로 보관하며, 실제 공격 시 activate_from_pool()로 켭니다.
func
_create_projectiles
(
projectile_key
:
String
,
count
:
int
)
->
void
:
var
safe_count
:
int
=
maxi
(
0
,
count
)
for
index
:
int
in
range
(
safe_count
):
var
projectile
:
Projectile
=
_create_projectile
(
projectile_key
)
_store_projectile
(
projectile_key
,
projectile
)
## 발사체 노드 하나를 생성하고 해당 종류의 비주얼 씬을 장착합니다.
## 이 시점에 씬 트리에 붙기 때문에 _ready()에서 비주얼 인스턴스도 함께 구성됩니다.
func
_create_projectile
(
projectile_key
:
String
)
->
Projectile
:
var
projectile
:
Projectile
=
ProjectileScript
.
new
()
as
Projectile
projectile
.
name
=
"PooledProjectile_"
+
projectile_key
projectile
.
custom_visual_scene
=
_visual_scenes
.
get
(
projectile_key
)
as
PackedScene
projectile
.
projectile_pool
=
self
projectile
.
pool_key
=
projectile_key
add_child
(
projectile
)
projectile
.
global_position
=
warmup_position
projectile
.
deactivate_for_pool
()
return
projectile
## 외부 유닛이 공격할 때 호출하는 발사체 대여 함수입니다.
## 풀이 비어 있으면 같은 경로로 새 발사체를 확장 생성하여 공격 누락을 막습니다.
func
spawn_projectile
(
projectile_key
:
String
,
fire_position
:
Vector3
,
target
:
Node3D
,
damage
:
float
,
speed
:
float
,
color
:
Color
)
->
Projectile
:
initialize_pool
()
var
projectile
:
Projectile
=
_take_projectile
(
projectile_key
)
projectile
.
activate_from_pool
(
self
,
projectile_key
,
fire_position
,
target
,
damage
,
speed
,
color
)
return
projectile
## 발사체가 충돌/소멸 조건에 도달했을 때 다시 풀로 반환됩니다.
## Projectile 쪽에서 직접 호출하므로 이름과 시그니처를 안정적으로 유지합니다.
func
release_projectile
(
projectile
:
Projectile
)
->
void
:
if
not
is_instance_valid
(
projectile
):
return
var
projectile_key
:
String
=
projectile
.
pool_key
if
not
_available_projectiles
.
has
(
projectile_key
):
projectile
.
queue_free
()
return
projectile
.
deactivate_for_pool
()
_store_projectile
(
projectile_key
,
projectile
)
## 워밍업용으로 미리 만들어 둔 발사체를 잠깐 켰다가 다시 끕니다.
## 실제 첫 공격 전에 비주얼 노드, 머티리얼, 파티클 리소스가 한 번 씬 트리에 올라오도록 유도합니다.
func
warmup_projectile_effects
()
->
void
:
initialize_pool
()
var
warmup_keys
:
Array
[
String
]
=
[
PROJECTILE_KEY_FIREBALL
,
PROJECTILE_KEY_ARROW
,
PROJECTILE_KEY_SPHERE
]
var
warmup_projectiles
:
Array
[
Projectile
]
=
[]
for
projectile_key
:
String
in
warmup_keys
:
var
projectile
:
Projectile
=
_take_projectile
(
projectile_key
)
projectile
.
show_for_warmup
(
warmup_position
)
warmup_projectiles
.
append
(
projectile
)
# 한 렌더 프레임 이상 비주얼을 씬 트리에 켜 두어 첫 사용 리소스 준비가 진행될 시간을 줍니다.
await
get_tree
()
.
process_frame
await
get_tree
()
.
process_frame
for
projectile
:
Projectile
in
warmup_projectiles
:
projectile
.
deactivate_for_pool
()
_store_projectile
(
projectile
.
pool_key
,
projectile
)
## 풀에서 하나를 꺼내거나, 부족하면 새로 만들어 반환합니다.
func
_take_projectile
(
projectile_key
:
String
)
->
Projectile
:
if
not
_available_projectiles
.
has
(
projectile_key
):
projectile_key
=
PROJECTILE_KEY_SPHERE
var
available
:
Array
=
_available_projectiles
[
projectile_key
]
if
available
.
is_empty
():
return
_create_projectile
(
projectile_key
)
return
available
.
pop_back
()
as
Projectile
## 비활성 발사체를 해당 종류의 대기열에 넣습니다.
func
_store_projectile
(
projectile_key
:
String
,
projectile
:
Projectile
)
->
void
:
if
not
_available_projectiles
.
has
(
projectile_key
):
_available_projectiles
[
projectile_key
]
=
[]
var
available
:
Array
=
_available_projectiles
[
projectile_key
]
if
not
available
.
has
(
projectile
):
available
.
append
(
projectile
)
src/core/projectile_pool.gd.uid
0 → 100644
View file @
45c18ca1
uid://yb0vk5n52gji
src/entities/summoner/summoner.gd
View file @
45c18ca1
...
@@ -26,9 +26,18 @@ var spell_mana_costs: Dictionary = {
...
@@ -26,9 +26,18 @@ var spell_mana_costs: Dictionary = {
var
is_initialized
:
bool
=
false
var
is_initialized
:
bool
=
false
## 강타(Smite) 번개 기둥에 재사용할 메쉬 리소스입니다.
## 첫 시전 순간 CylinderMesh를 생성하지 않도록 소환사 노드 준비 시 미리 구성합니다.
var
_lightning_mesh
:
CylinderMesh
=
null
## 강타(Smite) 번개 기둥에 재사용할 발광 머티리얼입니다.
## StandardMaterial3D 생성과 emission 설정 비용을 첫 스킬 사용 전에 끝내기 위한 캐시입니다.
var
_lightning_material
:
StandardMaterial3D
=
null
func
_ready
()
->
void
:
func
_ready
()
->
void
:
# setup_summoner()를 통해 외부에서 데이터를 직접 바인딩할 때까지 대기
# setup_summoner()를 통해 외부에서 데이터를 직접 바인딩할 때까지 대기합니다.
pass
# 비주얼 이펙트 리소스는 스킬 첫 사용 끊김을 줄이기 위해 노드 준비 시점에 미리 만듭니다.
_prepare_lightning_effect_resources
()
## 소환사 데이터를 주입받아 초기 셋업을 완료하는 메서드
## 소환사 데이터를 주입받아 초기 셋업을 완료하는 메서드
func
setup_summoner
(
data
:
SummonerData
)
->
void
:
func
setup_summoner
(
data
:
SummonerData
)
->
void
:
...
@@ -177,20 +186,9 @@ func _create_lightning_strike_effect(strike_pos: Vector3) -> void:
...
@@ -177,20 +186,9 @@ func _create_lightning_strike_effect(strike_pos: Vector3) -> void:
return
return
# 1. 번개 기둥 역할을 할 실린더 메쉬 인스턴스 생성
# 1. 번개 기둥 역할을 할 실린더 메쉬 인스턴스 생성
var
mesh_inst
=
MeshInstance3D
.
new
()
var
mesh_inst
:
MeshInstance3D
=
MeshInstance3D
.
new
()
var
cyl_mesh
=
CylinderMesh
.
new
()
mesh_inst
.
mesh
=
_lightning_mesh
cyl_mesh
.
top_radius
=
0.05
mesh_inst
.
material_override
=
_lightning_material
cyl_mesh
.
bottom_radius
=
0.15
cyl_mesh
.
height
=
10.0
var
mat
=
StandardMaterial3D
.
new
()
mat
.
albedo_color
=
Color
(
0.1
,
0.6
,
1.0
)
# 강렬한 하늘색
mat
.
emission_enabled
=
true
mat
.
emission
=
Color
(
0.2
,
0.7
,
1.0
)
mat
.
emission_energy_multiplier
=
4.0
mesh_inst
.
mesh
=
cyl_mesh
mesh_inst
.
material_override
=
mat
root
.
add_child
(
mesh_inst
)
root
.
add_child
(
mesh_inst
)
# 번개 기둥 위치 정렬: 하늘에서 내리치는 연출이므로 y 오프셋
# 번개 기둥 위치 정렬: 하늘에서 내리치는 연출이므로 y 오프셋
mesh_inst
.
global_position
=
strike_pos
+
Vector3
(
0.0
,
5.0
,
0.0
)
mesh_inst
.
global_position
=
strike_pos
+
Vector3
(
0.0
,
5.0
,
0.0
)
...
@@ -210,3 +208,17 @@ func _create_lightning_strike_effect(strike_pos: Vector3) -> void:
...
@@ -210,3 +208,17 @@ func _create_lightning_strike_effect(strike_pos: Vector3) -> void:
if
is_instance_valid
(
flash_light
):
if
is_instance_valid
(
flash_light
):
flash_light
.
queue_free
()
flash_light
.
queue_free
()
)
)
## 강타 번개 이펙트에서 반복 사용하는 리소스를 미리 준비합니다.
## 실제 시전 시에는 MeshInstance3D와 OmniLight3D 노드만 짧게 만들고, 메쉬/머티리얼은 여기서 만든 것을 공유합니다.
func
_prepare_lightning_effect_resources
()
->
void
:
_lightning_mesh
=
CylinderMesh
.
new
()
_lightning_mesh
.
top_radius
=
0.05
_lightning_mesh
.
bottom_radius
=
0.15
_lightning_mesh
.
height
=
10.0
_lightning_material
=
StandardMaterial3D
.
new
()
_lightning_material
.
albedo_color
=
Color
(
0.1
,
0.6
,
1.0
)
# 강렬한 하늘색
_lightning_material
.
emission_enabled
=
true
_lightning_material
.
emission
=
Color
(
0.2
,
0.7
,
1.0
)
_lightning_material
.
emission_energy_multiplier
=
4.0
src/entities/units/base/base_unit.gd
View file @
45c18ca1
...
@@ -437,12 +437,6 @@ func _show_attack_visual() -> void:
...
@@ -437,12 +437,6 @@ func _show_attack_visual() -> void:
## 모델별 기본 공격 애니메이션 이름을 반환합니다.
## 모델별 기본 공격 애니메이션 이름을 반환합니다.
func
_get_attack_animation_name
(
model_name
:
String
)
->
String
:
func
_get_attack_animation_name
(
model_name
:
String
)
->
String
:
return
""
return
""
# var attack_key: String = "Slash"
# if model_name == "ranger":
# attack_key = "Draw"
# elif model_name == "mage":
# attack_key = "Casting"
# return model_name + "/" + attack_key
## 상태(대기, 이동, 공격)별 3D 애니메이션 트랙 제어 및 크로스페이드 블렌딩
## 상태(대기, 이동, 공격)별 3D 애니메이션 트랙 제어 및 크로스페이드 블렌딩
## 상태(대기, 이동, 공격)별 3D 애니메이션 트랙 제어 (상속 클래스에서 재정의)
## 상태(대기, 이동, 공격)별 3D 애니메이션 트랙 제어 (상속 클래스에서 재정의)
...
@@ -456,3 +450,13 @@ func _setup_unit_visuals() -> void:
...
@@ -456,3 +450,13 @@ func _setup_unit_visuals() -> void:
## 원거리 유닛의 발사체 생성을 처리하는 가상 함수
## 원거리 유닛의 발사체 생성을 처리하는 가상 함수
func
_spawn_projectile
(
_fire_position
:
Vector3
)
->
void
:
func
_spawn_projectile
(
_fire_position
:
Vector3
)
->
void
:
pass
pass
## 현재 씬에서 런타임 발사체 풀을 찾아 반환합니다.
## - Main이 ProjectilePool을 생성해 group에 등록하면 원거리 유닛은 이 경로로 풀을 공유합니다.
## - 풀을 찾지 못하는 테스트 씬에서는 null을 반환하여 기존 직접 생성 fallback을 사용할 수 있게 합니다.
func
_get_projectile_pool
()
->
Node
:
var
pools
:
Array
[
Node
]
=
get_tree
()
.
get_nodes_in_group
(
"projectile_pool"
)
if
pools
.
is_empty
():
return
null
return
pools
[
0
]
src/entities/units/base/projectile.gd
View file @
45c18ca1
...
@@ -13,6 +13,20 @@ var color: Color = Color(1.0, 0.9, 0.2, 1.0) # 기본 노란색 발사체
...
@@ -13,6 +13,20 @@ var color: Color = Color(1.0, 0.9, 0.2, 1.0) # 기본 노란색 발사체
# 커스텀 비주얼 씬 (마법사 불덩이, 레인저 화살 등 외부 씬 연동 지원)
# 커스텀 비주얼 씬 (마법사 불덩이, 레인저 화살 등 외부 씬 연동 지원)
var
custom_visual_scene
:
PackedScene
=
null
var
custom_visual_scene
:
PackedScene
=
null
## ProjectilePool에서 관리되는 경우 풀 노드 참조를 보관합니다.
## 값이 없으면 기존 방식처럼 충돌/소멸 시 queue_free()를 사용합니다.
var
projectile_pool
:
Node
=
null
## 풀 내부에서 발사체 종류를 구분하기 위한 키입니다.
## 예: "fireball", "arrow", "sphere"
var
pool_key
:
String
=
""
## 풀에 보관 중인 비활성 발사체가 물리 처리와 충돌 판정을 하지 않도록 막는 플래그입니다.
var
_is_active
:
bool
=
true
## 커스텀 비주얼 인스턴스를 한 번만 생성해 재사용하기 위한 캐시입니다.
var
_visual_inst
:
Node3D
=
null
func
_ready
()
->
void
:
func
_ready
()
->
void
:
if
custom_visual_scene
:
if
custom_visual_scene
:
_setup_custom_visual
()
_setup_custom_visual
()
...
@@ -21,8 +35,8 @@ func _ready() -> void:
...
@@ -21,8 +35,8 @@ func _ready() -> void:
## 커스텀 비주얼 씬 인스턴싱하여 자식으로 장착
## 커스텀 비주얼 씬 인스턴싱하여 자식으로 장착
func
_setup_custom_visual
()
->
void
:
func
_setup_custom_visual
()
->
void
:
var
visual_inst
:
Node3D
=
custom_visual_scene
.
instantiate
()
as
Node3D
_visual_inst
=
custom_visual_scene
.
instantiate
()
as
Node3D
add_child
(
visual_inst
)
add_child
(
_
visual_inst
)
## 구체 빛 구슬 비주얼 설정 (Ranger 이외 유닛 또는 arrow 로드 실패 시 Fallback)
## 구체 빛 구슬 비주얼 설정 (Ranger 이외 유닛 또는 arrow 로드 실패 시 Fallback)
...
@@ -41,15 +55,62 @@ func _setup_sphere_visual() -> void:
...
@@ -41,15 +55,62 @@ func _setup_sphere_visual() -> void:
mesh_instance
.
mesh
=
sphere_mesh
mesh_instance
.
mesh
=
sphere_mesh
add_child
(
mesh_instance
)
add_child
(
mesh_instance
)
_visual_inst
=
mesh_instance
## 풀에서 꺼낸 발사체에 이번 공격에 필요한 런타임 값을 주입하고 활성화합니다.
## 같은 발사체 노드를 재사용하므로 이전 타겟/데미지/색상 상태가 남지 않도록 여기에서 모두 덮어씁니다.
func
activate_from_pool
(
pool
:
Node
,
projectile_key
:
String
,
fire_position
:
Vector3
,
new_target
:
Node3D
,
new_damage
:
float
,
new_speed
:
float
,
new_color
:
Color
)
->
void
:
projectile_pool
=
pool
pool_key
=
projectile_key
target
=
new_target
damage
=
new_damage
speed
=
new_speed
color
=
new_color
global_position
=
fire_position
visible
=
true
_is_active
=
true
set_physics_process
(
true
)
_restart_particle_children
(
self
)
## 풀에 반환될 때 발사체를 완전히 비활성화합니다.
## 노드는 씬 트리에 남겨 두되 보이지 않고, 물리 프레임도 소모하지 않게 만듭니다.
func
deactivate_for_pool
()
->
void
:
_is_active
=
false
target
=
null
visible
=
false
global_position
=
Vector3
(
0.0
,
-
100.0
,
0.0
)
set_physics_process
(
false
)
_stop_particle_children
(
self
)
## 이펙트 워밍업 전용 활성화입니다.
## 타겟 추적이나 충돌 처리는 하지 않고, 비주얼 자식만 잠깐 켜서 리소스 준비를 유도합니다.
func
show_for_warmup
(
warmup_position
:
Vector3
)
->
void
:
_is_active
=
false
target
=
null
global_position
=
warmup_position
visible
=
true
set_physics_process
(
false
)
_restart_particle_children
(
self
)
func
_physics_process
(
delta
:
float
)
->
void
:
func
_physics_process
(
delta
:
float
)
->
void
:
if
not
_is_active
:
return
if
GameManager
.
is_game_over
:
if
GameManager
.
is_game_over
:
queue_free
()
_despawn
()
return
return
# 타겟이 도중에 사라지거나 사망 시 소멸
# 타겟이 도중에 사라지거나 사망 시 소멸
if
not
is_instance_valid
(
target
)
or
target
.
get
(
"is_dead"
)
==
true
:
if
not
is_instance_valid
(
target
)
or
target
.
get
(
"is_dead"
)
==
true
:
queue_free
()
_despawn
()
return
return
# 타겟 높이 오프셋 보정 (몬스터 중심부 y ~= 0.5를 향하도록)
# 타겟 높이 오프셋 보정 (몬스터 중심부 y ~= 0.5를 향하도록)
...
@@ -79,4 +140,31 @@ func _impact() -> void:
...
@@ -79,4 +140,31 @@ func _impact() -> void:
target
.
call
(
"take_damage"
,
damage
)
target
.
call
(
"take_damage"
,
damage
)
# 충돌 이펙트 (필요 시 연출)
# 충돌 이펙트 (필요 시 연출)
_despawn
()
## 발사체 수명이 끝났을 때 풀로 반환하거나, 풀이 없으면 기존처럼 삭제합니다.
func
_despawn
()
->
void
:
if
projectile_pool
and
projectile_pool
.
has_method
(
"release_projectile"
):
projectile_pool
.
call
(
"release_projectile"
,
self
)
else
:
queue_free
()
queue_free
()
## 재사용 발사체가 다시 발사될 때 GPUParticles3D 자식들의 방출을 재시작합니다.
## 파티클이 중간 상태로 남아 있지 않게 emitting을 껐다 켜는 방식으로 초기화합니다.
func
_restart_particle_children
(
root
:
Node
)
->
void
:
for
child
:
Node
in
root
.
get_children
():
if
child
is
GPUParticles3D
:
var
particles
:
GPUParticles3D
=
child
as
GPUParticles3D
particles
.
emitting
=
false
particles
.
restart
()
particles
.
emitting
=
true
_restart_particle_children
(
child
)
## 풀에 들어간 비활성 발사체의 파티클 방출을 멈춥니다.
## 보이지 않는 발사체가 백그라운드에서 파티클 시뮬레이션 비용을 쓰지 않게 합니다.
func
_stop_particle_children
(
root
:
Node
)
->
void
:
for
child
:
Node
in
root
.
get_children
():
if
child
is
GPUParticles3D
:
var
particles
:
GPUParticles3D
=
child
as
GPUParticles3D
particles
.
emitting
=
false
_stop_particle_children
(
child
)
src/entities/units/mage/mage_unit.gd
View file @
45c18ca1
...
@@ -112,6 +112,22 @@ func _update_animations() -> void:
...
@@ -112,6 +112,22 @@ func _update_animations() -> void:
## 마법사(Mage) 전용 화염 불덩이(Fireball) 발사체를 월드에 스폰하는 함수
## 마법사(Mage) 전용 화염 불덩이(Fireball) 발사체를 월드에 스폰하는 함수
func
_spawn_projectile
(
fire_position
:
Vector3
)
->
void
:
func
_spawn_projectile
(
fire_position
:
Vector3
)
->
void
:
# Main에서 준비한 ProjectilePool이 있으면 미리 생성된 화염구 발사체를 재사용합니다.
# 이 경로가 전투 중 반복 instantiate/free를 줄여 첫 발사와 연속 발사 끊김을 완화합니다.
var
projectile_pool
:
Node
=
_get_projectile_pool
()
if
projectile_pool
and
projectile_pool
.
has_method
(
"spawn_projectile"
):
projectile_pool
.
call
(
"spawn_projectile"
,
"fireball"
,
fire_position
,
_target_monster
,
unit_data
.
damage
,
18.0
,
Color
(
1.0
,
0.35
,
0.1
,
1.0
)
)
return
# ProjectilePool이 없는 독립 테스트 씬에서는 기존 방식으로 발사체를 직접 생성합니다.
# 공통 Projectile 스크립트를 로드하여 발사체 인스턴스를 동적 생성합니다.
# 공통 Projectile 스크립트를 로드하여 발사체 인스턴스를 동적 생성합니다.
var
projectile_script
:
=
preload
(
"res://src/entities/units/base/projectile.gd"
)
var
projectile_script
:
=
preload
(
"res://src/entities/units/base/projectile.gd"
)
var
proj
:
Node3D
=
projectile_script
.
new
()
as
Node3D
var
proj
:
Node3D
=
projectile_script
.
new
()
as
Node3D
...
...
src/entities/units/ranger/ranger_unit.gd
View file @
45c18ca1
...
@@ -92,6 +92,22 @@ func _update_animations() -> void:
...
@@ -92,6 +92,22 @@ func _update_animations() -> void:
## 레인저 전용 발사체 생성 및 스폰
## 레인저 전용 발사체 생성 및 스폰
func
_spawn_projectile
(
fire_position
:
Vector3
)
->
void
:
func
_spawn_projectile
(
fire_position
:
Vector3
)
->
void
:
# Main에서 준비한 ProjectilePool이 있으면 미리 생성된 화살 발사체를 재사용합니다.
# 빠르게 반복 발사되는 레인저 특성상 풀링 효과가 크며, 전투 중 생성/삭제 비용을 줄입니다.
var
projectile_pool
:
Node
=
_get_projectile_pool
()
if
projectile_pool
and
projectile_pool
.
has_method
(
"spawn_projectile"
):
projectile_pool
.
call
(
"spawn_projectile"
,
"arrow"
,
fire_position
,
_target_monster
,
unit_data
.
damage
,
28.0
,
unit_data
.
unit_color
)
return
# ProjectilePool이 없는 독립 테스트 씬에서는 기존 방식으로 발사체를 직접 생성합니다.
var
projectile_script
=
preload
(
"res://src/entities/units/base/projectile.gd"
)
var
projectile_script
=
preload
(
"res://src/entities/units/base/projectile.gd"
)
var
proj
:
Node3D
=
projectile_script
.
new
()
as
Node3D
var
proj
:
Node3D
=
projectile_script
.
new
()
as
Node3D
...
...
src/map/background/desert.tscn
View file @
45c18ca1
...
@@ -115,4 +115,4 @@ waterDefinition = SubResource("WaterResource_gbjga")
...
@@ -115,4 +115,4 @@ waterDefinition = SubResource("WaterResource_gbjga")
terrainZones = SubResource("ZonesResource_aj3fk")
terrainZones = SubResource("ZonesResource_aj3fk")
physics_interpolation_mode = 2
physics_interpolation_mode = 2
top_level = true
top_level = true
metadata/_edit_lock_ =
tru
e
metadata/_edit_lock_ =
fals
e
src/ui/hero_panel/hud_hero_panel.gd
0 → 100644
View file @
45c18ca1
This diff is collapsed.
Click to expand it.
src/ui/hero_panel/hud_hero_panel.gd.uid
0 → 100644
View file @
45c18ca1
uid://bkx7mv8uksflg
src/ui/hud.gd
View file @
45c18ca1
This diff is collapsed.
Click to expand it.
src/ui/summoner_panel/hud_summoner_panel.gd
0 → 100644
View file @
45c18ca1
class_name
HudSummonerPanel
extends
RefCounted
## HUD 하단의 소환사 상태/주문 UI를 생성하고 갱신하는 보조 클래스입니다.
## - Summoner 노드의 mana_changed, spell_cooldown_changed 신호를 받아 버튼 상태를 갱신합니다.
## - HUD 본문은 소환사 노드 생성과 게임 시작 호출만 담당하고, UI 세부 조립은 이 클래스가 맡습니다.
const
HASTE_SPELL_NAME
:
String
=
"haste"
const
SMITE_SPELL_NAME
:
String
=
"smite"
const
HASTE_MANA_COST
:
float
=
40.0
const
SMITE_MANA_COST
:
float
=
50.0
const
HASTE_ICON_PATH
:
String
=
"res://assets/ui/summoner/spells/spell_haste.png"
const
SMITE_ICON_PATH
:
String
=
"res://assets/ui/summoner/spells/spell_smite.png"
var
_summoner
:
Summoner
=
null
var
_mana_bar
:
ProgressBar
=
null
var
_mana_label
:
Label
=
null
var
_haste_button
:
Button
=
null
var
_smite_button
:
Button
=
null
## 소환사 UI를 BottomBar 앞쪽에 조립하고 신호 연결까지 완료합니다.
## data는 이미 GameManager에서 선택/디버그 기본값 보정이 끝난 SummonerData여야 합니다.
func
build
(
bottom_bar
:
Control
,
summoner
:
Summoner
,
data
:
SummonerData
)
->
void
:
_summoner
=
summoner
var
summoner_ui
:
HBoxContainer
=
HBoxContainer
.
new
()
summoner_ui
.
name
=
"SummonerUI"
summoner_ui
.
add_theme_constant_override
(
"separation"
,
10
)
summoner_ui
.
add_child
(
_create_portrait
(
data
))
summoner_ui
.
add_child
(
_create_mana_info_group
(
data
))
summoner_ui
.
add_child
(
_create_spell_group
())
bottom_bar
.
add_child
(
summoner_ui
)
bottom_bar
.
move_child
(
summoner_ui
,
0
)
_connect_summoner_signals
()
# UI 생성 직후 현재 마나 값을 한 번 강제 반영합니다.
# 신호 기반 UI이므로 초기 동기화도 같은 경로를 쓰면 이후 갱신과 표시 규칙이 일관됩니다.
_summoner
.
mana_changed
.
emit
(
_summoner
.
current_mana
,
_summoner
.
max_mana
)
## 소환사 초상화 TextureRect를 생성합니다.
## 선택 데이터에 portrait_texture가 없으면 빈 영역을 유지해 레이아웃 크기만 안정적으로 잡습니다.
func
_create_portrait
(
data
:
SummonerData
)
->
TextureRect
:
var
portrait
:
TextureRect
=
TextureRect
.
new
()
portrait
.
name
=
"SummonerPortrait"
portrait
.
custom_minimum_size
=
Vector2
(
48
,
48
)
portrait
.
expand_mode
=
TextureRect
.
EXPAND_IGNORE_SIZE
portrait
.
stretch_mode
=
TextureRect
.
STRETCH_KEEP_ASPECT_COVERED
if
data
.
portrait_texture
:
portrait
.
texture
=
data
.
portrait_texture
return
portrait
## 마나 바와 숫자 라벨을 담는 세로 그룹을 생성합니다.
## ProgressBar 스타일도 여기에서 함께 설정해 HUD 본문에 시각 세부사항이 새지 않게 합니다.
func
_create_mana_info_group
(
data
:
SummonerData
)
->
VBoxContainer
:
var
info_group
:
VBoxContainer
=
VBoxContainer
.
new
()
info_group
.
name
=
"InfoGroup"
info_group
.
custom_minimum_size
=
Vector2
(
110
,
48
)
_mana_bar
=
ProgressBar
.
new
()
_mana_bar
.
name
=
"ManaBar"
_mana_bar
.
show_percentage
=
false
_mana_bar
.
custom_minimum_size
=
Vector2
(
110
,
14
)
_mana_bar
.
max_value
=
data
.
max_mana
_mana_bar
.
value
=
data
.
max_mana
var
background_style
:
StyleBoxFlat
=
StyleBoxFlat
.
new
()
background_style
.
bg_color
=
Color
(
0.12
,
0.12
,
0.12
,
0.8
)
background_style
.
set_corner_radius_all
(
2
)
var
fill_style
:
StyleBoxFlat
=
StyleBoxFlat
.
new
()
fill_style
.
bg_color
=
Color
(
0.15
,
0.45
,
0.85
,
1.0
)
fill_style
.
set_corner_radius_all
(
2
)
_mana_bar
.
add_theme_stylebox_override
(
"background"
,
background_style
)
_mana_bar
.
add_theme_stylebox_override
(
"fill"
,
fill_style
)
info_group
.
add_child
(
_mana_bar
)
_mana_label
=
Label
.
new
()
_mana_label
.
name
=
"ManaLabel"
_mana_label
.
text
=
"MP:
%.1f
/
%.1f
"
%
[
data
.
max_mana
,
data
.
max_mana
]
_mana_label
.
add_theme_font_size_override
(
"font_size"
,
10
)
info_group
.
add_child
(
_mana_label
)
return
info_group
## 소환사 주문 버튼 그룹을 생성합니다.
## 각 버튼은 Summoner.cast_spell()만 호출하고, 사용 가능 여부는 신호 갱신에서 계산합니다.
func
_create_spell_group
()
->
HBoxContainer
:
var
spell_group
:
HBoxContainer
=
HBoxContainer
.
new
()
spell_group
.
name
=
"SpellGroup"
spell_group
.
add_theme_constant_override
(
"separation"
,
5
)
_haste_button
=
_create_spell_button
(
"SpellHaste"
,
"Haste (40 MP)"
,
HASTE_ICON_PATH
)
_haste_button
.
pressed
.
connect
(
func
()
->
void
:
_summoner
.
cast_spell
(
HASTE_SPELL_NAME
)
)
spell_group
.
add_child
(
_haste_button
)
_smite_button
=
_create_spell_button
(
"SpellSmite"
,
"Smite (50 MP)"
,
SMITE_ICON_PATH
)
_smite_button
.
pressed
.
connect
(
func
()
->
void
:
_summoner
.
cast_spell
(
SMITE_SPELL_NAME
)
)
spell_group
.
add_child
(
_smite_button
)
return
spell_group
## 주문 버튼 하나를 생성하고 아이콘이 있으면 함께 적용합니다.
## 아이콘 파일이 없어도 버튼 크기를 유지해 UI가 갑자기 줄어들지 않게 합니다.
func
_create_spell_button
(
button_name
:
String
,
text
:
String
,
icon_path
:
String
)
->
Button
:
var
button
:
Button
=
Button
.
new
()
button
.
name
=
button_name
button
.
text
=
text
if
ResourceLoader
.
exists
(
icon_path
):
button
.
icon
=
load
(
icon_path
)
as
Texture2D
button
.
expand_icon
=
true
button
.
custom_minimum_size
=
Vector2
(
90
,
45
)
else
:
button
.
custom_minimum_size
=
Vector2
(
90
,
30
)
return
button
## 소환사 신호를 UI 갱신 함수에 연결합니다.
## 문자열 기반 연결 대신 Callable 연결을 사용해 Godot 4 스타일을 유지합니다.
func
_connect_summoner_signals
()
->
void
:
_summoner
.
mana_changed
.
connect
(
_on_mana_changed
)
_summoner
.
spell_cooldown_changed
.
connect
(
_on_spell_cooldown_changed
)
## 현재 마나와 쿨다운 상태를 함께 보고 주문 버튼 활성/비활성을 갱신합니다.
func
_on_mana_changed
(
current
:
float
,
max_value
:
float
)
->
void
:
if
not
is_instance_valid
(
_mana_bar
)
or
not
is_instance_valid
(
_mana_label
):
return
_mana_bar
.
max_value
=
max_value
_mana_bar
.
value
=
current
_mana_label
.
text
=
"MP:
%.1f
/
%.1f
"
%
[
current
,
max_value
]
_update_spell_button_enabled
(
_haste_button
,
HASTE_SPELL_NAME
,
HASTE_MANA_COST
)
_update_spell_button_enabled
(
_smite_button
,
SMITE_SPELL_NAME
,
SMITE_MANA_COST
)
## 쿨다운 숫자를 버튼 텍스트에 표시하고, 쿨다운 종료 시 마나 조건을 다시 검사합니다.
func
_on_spell_cooldown_changed
(
spell_name
:
String
,
remaining
:
float
,
_duration
:
float
)
->
void
:
var
button
:
Button
=
_haste_button
if
spell_name
==
HASTE_SPELL_NAME
else
_smite_button
var
label_text
:
String
=
"Haste"
if
spell_name
==
HASTE_SPELL_NAME
else
"Smite"
var
cost
:
float
=
HASTE_MANA_COST
if
spell_name
==
HASTE_SPELL_NAME
else
SMITE_MANA_COST
if
remaining
>
0.0
:
button
.
text
=
"
%s
\n
(
%.1f
s)"
%
[
label_text
,
remaining
]
button
.
disabled
=
true
else
:
button
.
text
=
"
%s
(
%d
MP)"
%
[
label_text
,
cost
]
_update_spell_button_enabled
(
button
,
spell_name
,
cost
)
## 마나 부족 또는 쿨다운 중이면 주문 버튼을 비활성화합니다.
func
_update_spell_button_enabled
(
button
:
Button
,
spell_name
:
String
,
mana_cost
:
float
)
->
void
:
if
not
is_instance_valid
(
button
)
or
not
is_instance_valid
(
_summoner
):
return
var
cooldown_remaining
:
float
=
_summoner
.
spell_cooldowns
.
get
(
spell_name
,
0.0
)
button
.
disabled
=
_summoner
.
current_mana
<
mana_cost
or
cooldown_remaining
>
0.0
src/ui/summoner_panel/hud_summoner_panel.gd.uid
0 → 100644
View file @
45c18ca1
uid://xv3ptedjdn2o
src/ui/unit_placement/hud_unit_placement.gd
0 → 100644
View file @
45c18ca1
This diff is collapsed.
Click to expand it.
src/ui/unit_placement/hud_unit_placement.gd.uid
0 → 100644
View file @
45c18ca1
uid://cuuq64au1mfit
src/ui/unit_placement/placement_tile_overlay.gd
0 → 100644
View file @
45c18ca1
extends
MeshInstance3D
## 유닛 배치 모드에서 타일 위에 표시되는 3D 오버레이 노드입니다.
## - 이 노드는 placement_tile_overlay.tscn의 루트로 사용됩니다.
## - HudUnitPlacement는 이 씬을 풀로 미리 만들어 두고, 배치 모드마다 configure()로 재사용합니다.
## - PlaneMesh 자체는 씬에 포함된 1x1 크기를 사용하고, 실제 타일 크기는 scale로 맞춰 런타임 Mesh 생성을 피합니다.
const
HIDDEN_POSITION
:
Vector3
=
Vector3
(
0.0
,
-
100.0
,
0.0
)
## 풀에서 대기 중인지 여부입니다.
## 디버깅 중 씬 트리에서 오버레이 상태를 확인할 때 쓸 수 있도록 명시적으로 보관합니다.
var
is_available_in_pool
:
bool
=
true
func
_ready
()
->
void
:
# 오버레이는 순수 표시용이므로 그림자와 입력 충돌 비용을 만들지 않습니다.
cast_shadow
=
GeometryInstance3D
.
SHADOW_CASTING_SETTING_OFF
visible
=
false
global_position
=
HIDDEN_POSITION
## 풀에서 꺼낸 오버레이를 실제 타일 위치/크기/재질로 설정하고 표시합니다.
## PlaneMesh는 기본 1x1 크기이므로 scale.x/z로 GridMap 셀 크기에 맞춥니다.
func
configure
(
tile_center
:
Vector3
,
tile_size
:
Vector2
,
material
:
Material
,
is_occupied
:
bool
)
->
void
:
is_available_in_pool
=
false
name
=
"OccupiedTileOverlay"
if
is_occupied
else
"AvailableTileOverlay"
global_position
=
tile_center
scale
=
Vector3
(
tile_size
.
x
,
1.0
,
tile_size
.
y
)
material_override
=
material
visible
=
true
## 배치 모드가 끝나면 삭제하지 않고 풀에 반환될 수 있도록 숨깁니다.
## 씬 트리에는 남아 있으므로 다음 배치 모드에서는 instantiate 없이 바로 재사용됩니다.
func
release_to_pool
()
->
void
:
is_available_in_pool
=
true
visible
=
false
global_position
=
HIDDEN_POSITION
material_override
=
null
src/ui/unit_placement/placement_tile_overlay.gd.uid
0 → 100644
View file @
45c18ca1
uid://bd00wvrr48mfi
src/ui/unit_placement/placement_tile_overlay.tscn
0 → 100644
View file @
45c18ca1
[gd_scene format=3]
[ext_resource type="Script" path="res://src/ui/unit_placement/placement_tile_overlay.gd" id="1_67clr"]
[sub_resource type="PlaneMesh" id="PlaneMesh_y7kwe"]
size = Vector2(1, 1)
[node name="PlacementTileOverlay" type="MeshInstance3D" unique_id=1113555824]
visible = false
cast_shadow = 0
mesh = SubResource("PlaneMesh_y7kwe")
script = ExtResource("1_67clr")
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment