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
9168d476
Commit
9168d476
authored
Jun 17, 2026
by
Gavin An
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
스킨 입혀보기
parent
9af0b9d6
Changes
10
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
325 additions
and
54 deletions
+325
-54
assets/models/units/striker.fbx
assets/models/units/striker.fbx
+0
-0
assets/models/units/striker.fbx.import
assets/models/units/striker.fbx.import
+44
-0
assets/models/units/striker_0.png
assets/models/units/striker_0.png
+0
-0
assets/models/units/striker_0.png.import
assets/models/units/striker_0.png.import
+44
-0
docs/agents_docs/architecture.md
docs/agents_docs/architecture.md
+12
-1
docs/agents_docs/todo.md
docs/agents_docs/todo.md
+99
-46
src/core/main.tscn
src/core/main.tscn
+1
-1
src/entities/units/base_unit.gd
src/entities/units/base_unit.gd
+70
-0
src/entities/units/striker/striker_unit.tscn
src/entities/units/striker/striker_unit.tscn
+43
-0
src/ui/hud.gd
src/ui/hud.gd
+12
-6
No files found.
assets/models/units/striker.fbx
0 → 100644
View file @
9168d476
File added
assets/models/units/striker.fbx.import
0 → 100644
View file @
9168d476
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://ddqbm4y6brray"
path="res://.godot/imported/striker.fbx-bc1f4af7c3cd42cf4653a106a2b4cd60.scn"
[deps]
source_file="res://assets/models/units/striker.fbx"
dest_files=["res://.godot/imported/striker.fbx-bc1f4af7c3cd42cf4653a106a2b4cd60.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=true
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
fbx/naming_version=2
assets/models/units/striker_0.png
0 → 100644
View file @
9168d476
6.41 MB
assets/models/units/striker_0.png.import
0 → 100644
View file @
9168d476
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ccilxf3k1hhpb"
path.s3tc="res://.godot/imported/striker_0.png-33c061e5427709c43bfd101c9c356d76.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={
"md5": "4bf449ff8612570375bc5092fac3ec8b"
}
[deps]
source_file="res://assets/models/units/striker_0.png"
dest_files=["res://.godot/imported/striker_0.png-33c061e5427709c43bfd101c9c356d76.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
docs/agents_docs/architecture.md
View file @
9168d476
...
...
@@ -17,4 +17,15 @@ ldefense/
│ │ └── units/ # 플레이어 유닛 관련 씬 및 스크립트
│ ├── ui/ # UI 관련 씬 및 스크립트
│ └── utils/ # 기타 유틸리티 함수
├── assets/
│ ├── models/ # 3D 모델 (.glb, .gltf, .obj) 및 애니메이션
│ │ ├── units/ # 플레이어 유닛 3D 애셋 (Striker, Ranger 등)
│ │ ├── monsters/ # 몬스터 3D 애셋
│ │ └── environment/ # 지형 장애물, 소품, 타일 등
│ ├── textures/ # 3D 맵핑용 재질 텍스처, 노이즈 맵, 하늘(Skybox) HDRI
│ ├── ui/ # 버튼, 테두리, 아이콘 등 2D 스프라이트 이미지 (.png)
│ ├── audio/ # 사운드 파일
│ │ ├── sfx/ # 효과음 (즉시 재생을 위해 .wav 확장자 권장)
│ │ └── music/ # 배경음악 (스트리밍 재생을 위해 .ogg 또는 .mp3 권장)
│ └── fonts/ # UI 텍스트용 외부 폰트 (.ttf, .otf)
└── project.godot
docs/agents_docs/todo.md
View file @
9168d476
This diff is collapsed.
Click to expand it.
src/core/main.tscn
View file @
9168d476
...
...
@@ -2,7 +2,7 @@
[ext_resource type="Script" uid="uid://dd1xgi6hnpuvs" path="res://src/core/rts_camera.gd" id="1_rts_cam"]
[ext_resource type="Script" uid="uid://cq7r51whh6po" path="res://src/core/stage_manager.gd" id="2_stage_mgr"]
[ext_resource type="PackedScene" path="res://src/entities/monsters/base_monster.tscn" id="3_base_monster"]
[ext_resource type="PackedScene"
uid="uid://bslqp550s3j0s"
path="res://src/entities/monsters/base_monster.tscn" id="3_base_monster"]
[ext_resource type="Script" uid="uid://dkplkt6q8e3b5" path="res://src/core/unit_controller.gd" id="4_unit_ctrl"]
[ext_resource type="PackedScene" uid="uid://bqga1rvcjyydy" path="res://src/ui/hud.tscn" id="5_hud"]
...
...
src/entities/units/base_unit.gd
View file @
9168d476
...
...
@@ -21,6 +21,11 @@ var _auto_target_cooldown: float = 0.0
@
onready
var
_selection_ring
:
MeshInstance3D
=
$
SelectionRing
@
onready
var
_visual_mesh
:
MeshInstance3D
=
$
VisualMesh
# 3D 모델 및 애니메이션 연동 변수 (정적 타이핑 캐싱)
var
_model_instance
:
Node3D
=
null
var
_model_anim_player
:
AnimationPlayer
=
null
var
_last_anim_state
:
String
=
""
func
_ready
()
->
void
:
# 유닛 그룹에 등록
add_to_group
(
"units"
)
...
...
@@ -36,6 +41,17 @@ func _ready() -> void:
if
unit_data
:
_apply_unit_style
()
# 씬 트리에 조립된 Striker 3D 모델 탐색 및 초기화
var
striker_node
:
Node3D
=
get_node_or_null
(
"striker"
)
as
Node3D
if
striker_node
:
_model_instance
=
striker_node
_apply_striker_skin
(
_model_instance
)
_model_anim_player
=
_find_animation_player
(
_model_instance
)
if
_model_anim_player
:
print
(
"BaseUnit: Linked pre-configured striker model & AnimationPlayer."
)
func
_physics_process
(
delta
:
float
)
->
void
:
if
GameManager
.
is_game_over
:
velocity
=
Vector3
.
ZERO
...
...
@@ -61,6 +77,9 @@ func _physics_process(delta: float) -> void:
else
:
_process_normal_logic
(
delta
)
# 4. 3D 애니메이션 재생 업데이트
_update_animations
()
## 1. 공격 타겟이 존재할 때의 동작 로직
func
_process_attack_logic
(
_delta
:
float
)
->
void
:
if
not
_target_monster
:
...
...
@@ -200,3 +219,54 @@ func deselect() -> void:
is_selected
=
false
if
_selection_ring
:
_selection_ring
.
visible
=
false
## FBX 모델의 자식 메쉬에 striker_0.png 텍스처를 씌우는 재귀 함수
func
_apply_striker_skin
(
node
:
Node
)
->
void
:
if
node
is
MeshInstance3D
:
var
mesh_inst
:
MeshInstance3D
=
node
as
MeshInstance3D
var
texture
:
Texture2D
=
load
(
"res://assets/models/units/striker_0.png"
)
as
Texture2D
if
texture
:
var
mat
:
StandardMaterial3D
=
StandardMaterial3D
.
new
()
mat
.
albedo_texture
=
texture
mat
.
roughness
=
0.5
mesh_inst
.
material_override
=
mat
for
child
:
Node
in
node
.
get_children
():
_apply_striker_skin
(
child
)
## 모델 자식 노드 중 AnimationPlayer 탐색
func
_find_animation_player
(
node
:
Node
)
->
AnimationPlayer
:
if
node
is
AnimationPlayer
:
return
node
as
AnimationPlayer
for
child
:
Node
in
node
.
get_children
():
var
res
:
AnimationPlayer
=
_find_animation_player
(
child
)
if
res
:
return
res
return
null
## 상태(대기, 이동, 공격)별 3D 애니메이션 트랙 제어
func
_update_animations
()
->
void
:
if
not
_model_anim_player
:
return
# 사용할 애니메이션 클립 이름
var
anim_name
:
String
=
"Armature|Armature|Basic_Jump|baselayer"
if
not
_model_anim_player
.
has_animation
(
anim_name
):
return
# 1. 공격 중 상태: 공격 타이머 차감 후 쿨타임 구간의 초입 0.4초간은 공격 애니메이션 우선 재생
# Striker의 공격 속도(cooldown)는 0.5초이므로, 공격 직후 0.4초 동안 2.5배속으로 순간 재생하면 활기찬 펀칭 타격을 표현함
if
_attack_timer
>
(
unit_data
.
cooldown
-
0.4
):
if
_last_anim_state
!=
"attack"
:
_last_anim_state
=
"attack"
_model_anim_player
.
play
(
anim_name
,
-
1
,
2.5
)
# 2. 이동 중 상태: 속도 벡터가 존재할 때 (이동 상태)
elif
velocity
.
length
()
>
0.1
:
if
_last_anim_state
!=
"move"
:
_last_anim_state
=
"move"
_model_anim_player
.
play
(
anim_name
,
-
1
,
1.5
)
# 3. 대기(Idle) 상태: 정지 상태일 때 애니메이션 정지 처리 (T-Pose 상태로 대기)
else
:
if
_last_anim_state
!=
"idle"
:
_last_anim_state
=
"idle"
_model_anim_player
.
stop
()
src/entities/units/striker/striker_unit.tscn
0 → 100644
View file @
9168d476
[gd_scene format=3 uid="uid://dwvbc5m3myqbk"]
[ext_resource type="Script" uid="uid://daq4ko8ryry3w" path="res://src/entities/units/base_unit.gd" id="1_base_unit"]
[ext_resource type="PackedScene" uid="uid://ddqbm4y6brray" path="res://assets/models/units/striker.fbx" id="2_striker_fbx"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
radius = 0.4
height = 1.2
[sub_resource type="CapsuleMesh" id="CapsuleMesh_unit"]
radius = 0.4
height = 1.2
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ring"]
albedo_color = Color(0.098039, 0.901961, 0.098039, 1)
emission_enabled = true
emission = Color(0.098039, 0.901961, 0.098039, 1)
emission_energy_multiplier = 2.0
[sub_resource type="TorusMesh" id="TorusMesh_selection"]
material = SubResource("StandardMaterial3D_ring")
inner_radius = 0.65
outer_radius = 0.7
[node name="StrikerUnit" type="CharacterBody3D" unique_id=1844747242]
script = ExtResource("1_base_unit")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=332342782]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
shape = SubResource("CapsuleShape3D_body")
[node name="VisualMesh" type="MeshInstance3D" parent="." unique_id=758090532]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
visible = false
mesh = SubResource("CapsuleMesh_unit")
[node name="SelectionRing" type="MeshInstance3D" parent="." unique_id=1378906746]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.02, 0)
mesh = SubResource("TorusMesh_selection")
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="." unique_id=462079662]
[node name="striker" parent="." unique_id=1562791213 instance=ExtResource("2_striker_fbx")]
src/ui/hud.gd
View file @
9168d476
...
...
@@ -55,7 +55,7 @@ func _initialize_unit_templates() -> void:
# 2. Guardian (밸런스형 근접 유닛)
var
guardian
:
UnitData
=
UnitData
.
new
()
guardian
.
unit_id
=
"Unit_
Guardian
"
guardian
.
unit_id
=
"Unit_
Striker
"
guardian
.
unit_name
=
"Guardian"
guardian
.
damage
=
25.0
guardian
.
cooldown
=
1.0
...
...
@@ -67,7 +67,7 @@ func _initialize_unit_templates() -> void:
# 3. Ranger (원거리 유닛)
var
ranger
:
UnitData
=
UnitData
.
new
()
ranger
.
unit_id
=
"Unit_
Rang
er"
ranger
.
unit_id
=
"Unit_
Strik
er"
ranger
.
unit_name
=
"Ranger"
ranger
.
damage
=
18.0
ranger
.
cooldown
=
0.8
...
...
@@ -79,7 +79,7 @@ func _initialize_unit_templates() -> void:
# 4. Slayer (고화력 대형 유닛)
var
slayer
:
UnitData
=
UnitData
.
new
()
slayer
.
unit_id
=
"Unit_S
lay
er"
slayer
.
unit_id
=
"Unit_S
trik
er"
slayer
.
unit_name
=
"Slayer"
slayer
.
damage
=
55.0
slayer
.
cooldown
=
1.8
...
...
@@ -91,7 +91,7 @@ func _initialize_unit_templates() -> void:
# 5. Archmage (극단적 극딜 마법 유닛)
var
archmage
:
UnitData
=
UnitData
.
new
()
archmage
.
unit_id
=
"Unit_
Archmage
"
archmage
.
unit_id
=
"Unit_
Striker
"
archmage
.
unit_name
=
"Archmage"
archmage
.
damage
=
110.0
archmage
.
cooldown
=
3.0
...
...
@@ -136,8 +136,14 @@ func _on_spawn_pressed() -> void:
var
random_index
:
int
=
randi
()
%
_unit_templates
.
size
()
var
chosen_template
:
UnitData
=
_unit_templates
[
random_index
]
# 유닛 객체 스폰
var
new_unit
:
Node
=
base_unit_scene
.
instantiate
()
# 유닛 객체 스폰 (Striker 전용 씬 분기 분할)
var
target_scene
:
PackedScene
=
base_unit_scene
if
chosen_template
.
unit_id
==
"Unit_Striker"
:
var
striker_scene
:
PackedScene
=
load
(
"res://src/entities/units/striker/striker_unit.tscn"
)
as
PackedScene
if
striker_scene
:
target_scene
=
striker_scene
var
new_unit
:
Node
=
target_scene
.
instantiate
()
var
parent_scene
:
Node
=
get_tree
()
.
current_scene
# 맵 중앙 스폰 존(0, 0) 기준 분산 스폰 좌표 지정
...
...
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