Commit 3aede6f6 authored by Gavin An's avatar Gavin An

유닛 만드는중

parent b87499ae
......@@ -4,12 +4,12 @@ importer="scene"
importer_version=1
type="PackedScene"
uid="uid://7aw71ibtccuf"
path="res://.godot/imported/azure_blade.fbx-425d5168a712b651930f75a0427db998.scn"
path="res://.godot/imported/azure_blade.fbx-9ebf095140efea605d7beb551dad626d.scn"
[deps]
source_file="res://assets/models/monsters/azure_blade.fbx"
dest_files=["res://.godot/imported/azure_blade.fbx-425d5168a712b651930f75a0427db998.scn"]
source_file="res://assets/models/items/weapons/azure_blade.fbx"
dest_files=["res://.godot/imported/azure_blade.fbx-9ebf095140efea605d7beb551dad626d.scn"]
[params]
......
......@@ -3,7 +3,7 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://fye2cyrwwe8o"
path.s3tc="res://.godot/imported/azure_blade_0.png-608beba35bccc9adab994252aea003af.s3tc.ctex"
path.s3tc="res://.godot/imported/azure_blade_0.png-af3f8658a30e83ce1363b6d1a8c68487.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
......@@ -14,8 +14,8 @@ generator_parameters={
[deps]
source_file="res://assets/models/monsters/azure_blade_0.png"
dest_files=["res://.godot/imported/azure_blade_0.png-608beba35bccc9adab994252aea003af.s3tc.ctex"]
source_file="res://assets/models/items/weapons/azure_blade_0.png"
dest_files=["res://.godot/imported/azure_blade_0.png-af3f8658a30e83ce1363b6d1a8c68487.s3tc.ctex"]
[params]
......
......@@ -3,7 +3,7 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://c3qqd8c1bgy5j"
path.s3tc="res://.godot/imported/azure_blade_1.png-122ec6698eb977084ec19a953030f078.s3tc.ctex"
path.s3tc="res://.godot/imported/azure_blade_1.png-2df52b6429f1065c06ccd2649e87aaec.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
......@@ -14,8 +14,8 @@ generator_parameters={
[deps]
source_file="res://assets/models/monsters/azure_blade_1.png"
dest_files=["res://.godot/imported/azure_blade_1.png-122ec6698eb977084ec19a953030f078.s3tc.ctex"]
source_file="res://assets/models/items/weapons/azure_blade_1.png"
dest_files=["res://.godot/imported/azure_blade_1.png-2df52b6429f1065c06ccd2649e87aaec.s3tc.ctex"]
[params]
......
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://ym45af2xwegi"
path="res://.godot/imported/guardian.fbx-84eb2d0d9d2314572eefd0a31b702465.scn"
[deps]
source_file="res://assets/models/units/guardian/guardian.fbx"
dest_files=["res://.godot/imported/guardian.fbx-84eb2d0d9d2314572eefd0a31b702465.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
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cwwchk1itkduy"
path.s3tc="res://.godot/imported/guardian_0.png-465517cd610787ece6553a0f096c207b.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={
"md5": "8c2ce66c925a00fc68c57af0b1583baf"
}
[deps]
source_file="res://assets/models/units/guardian/guardian_0.png"
dest_files=["res://.godot/imported/guardian_0.png-465517cd610787ece6553a0f096c207b.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
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -58,7 +58,11 @@
- [x] `hud.gd`에 소환 씬 분기 기능을 도입하여, 소환 시 ID에 맞춰 Striker 유닛일 때 전용 `striker_unit.tscn`을 소환하도록 구현
- [x] 유닛이 스폰될 때 3D 모델 하위 메쉬에 `striker_0.png` 텍스처를 씌우는 오버라이드 매핑 기능을 작동시켜 모델 렌더 텍스처 출력 완료
- [x] `assets/models/units/striker/` 폴더 내부의 개별 애니메이션 FBX 파일들(`striker_idle.fbx`, `striker_walk.fbx`, `striker_run.fbx`, `striker_attack.fbx`)을 추출하여 단일 `AnimationLibrary` 리소스(`striker_animations.tres`)로 병합 완료
- [x] `base_unit.gd`에서 `striker_animations.tres`를 런타임에 동적으로 주입하여 유닛 상태(대기, 이동, 공격)에 맞게 `idle`, `run`, `attack` 애니메이션이 호출되도록 유기적 연동 완료
- [x] 신규 유닛 `Guardian` 모델(`guardian.fbx`)에 탑재된 애니메이션들을 추출하고 루프 상태를 정밀 정규화하여 단일 라이브러리 리소스인 `guardian_animations.tres`로 빌드 완료
- [x] `base_unit.gd`에서 유닛 모델명(예: `striker`, `guardian`)을 동적으로 감지하여 해당 애니메이션 라이브러리(`.tres`)를 자동 주입하고 고유 이름 프리픽스(`striker/`, `guardian/`)로 적합한 애니메이션들을 실시간 교차 분기 재생하는 범용 애니메이션 시스템 일반화 리팩토링 완료
- [x] `res://src/entities/units/guardian/` 폴더 내에 `guardian_unit.tscn` 씬을 설계 및 신설하여 가디언 모델의 스킨 및 계층 구조 연동 완료
- [x] `hud.gd` 스크립트를 수정하여 기존의 중복된 유닛 ID 버그를 해결(Striker 외형으로만 고정 스폰되던 현상 픽스)하고, Guardian 유닛 소환 시 전용 `guardian_unit.tscn`이 스폰되도록 연동 완료
- [x] 사용자가 직접 `striker_unit.tscn`에서 모델 Y축 회전 보정(180도)을 조치한 내용을 인지하고, `base_unit.gd` 스크립트 상에서 불필요해진 수동 회전 보정 코드부를 완전히 삭제하여 씬 지향적 설정을 완수
---
......
......@@ -41,20 +41,37 @@ 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
# 자식 노드 중 3D 모델(striker, guardian 등) 노드 자동 탐색 및 초기화
var model_names: Array[String] = ["striker", "guardian"]
var detected_model_node: Node3D = null
var detected_model_name: String = ""
for m_name: String in model_names:
var node: Node3D = get_node_or_null(m_name) as Node3D
if node:
detected_model_node = node
detected_model_name = m_name
break
if detected_model_node:
_model_instance = detected_model_node
if detected_model_name == "striker":
_apply_striker_skin(_model_instance)
elif detected_model_name == "guardian":
_apply_guardian_skin(_model_instance)
_model_anim_player = _find_animation_player(_model_instance)
if _model_anim_player:
print("BaseUnit: Linked pre-configured striker model & AnimationPlayer.")
var anim_lib_path: String = "res://assets/models/units/striker/striker_animations.tres"
print("BaseUnit: Linked pre-configured model & AnimationPlayer: ", detected_model_name)
# 모델명_animations.tres 라이브러리를 동적으로 로드하여 등록
var anim_lib_path: String = "res://assets/models/units/" + detected_model_name + "/" + detected_model_name + "_animations.tres"
if ResourceLoader.exists(anim_lib_path):
var lib: AnimationLibrary = load(anim_lib_path) as AnimationLibrary
if lib:
_model_anim_player.add_animation_library("striker", lib)
print("BaseUnit: Loaded and registered striker animations library successfully.")
_model_anim_player.add_animation_library(detected_model_name, lib)
print("BaseUnit: Loaded and registered ", detected_model_name, " animations library successfully.")
......@@ -240,6 +257,19 @@ func _apply_striker_skin(node: Node) -> void:
for child: Node in node.get_children():
_apply_striker_skin(child)
## FBX 모델의 자식 메쉬에 guardian_0.png 텍스처를 씌우는 재귀 함수
func _apply_guardian_skin(node: Node) -> void:
if node is MeshInstance3D:
var mesh_inst: MeshInstance3D = node as MeshInstance3D
var texture: Texture2D = load("res://assets/models/units/guardian/guardian_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_guardian_skin(child)
## 모델 자식 노드 중 AnimationPlayer 탐색
func _find_animation_player(node: Node) -> AnimationPlayer:
if node is AnimationPlayer:
......@@ -255,25 +285,29 @@ func _update_animations() -> void:
if not _model_anim_player:
return
# 라이브러리가 주입되었는지 확인
var has_striker_anims: bool = _model_anim_player.has_animation("striker/idle")
var model_name: String = ""
if _model_instance:
model_name = _model_instance.name.to_lower()
var library_prefix: String = model_name + "/"
var has_custom_anims: bool = _model_anim_player.has_animation(library_prefix + "idle")
if has_striker_anims:
if has_custom_anims:
# 1. 공격 중 상태: 공격 타이머 차감 후 쿨타임 구간의 초입 0.4초간은 공격 애니메이션 우선 재생
if _attack_timer > (unit_data.cooldown - 0.4):
if _last_anim_state != "attack":
_last_anim_state = "attack"
_model_anim_player.play("striker/attack", -1, 1.5)
_model_anim_player.play(library_prefix + "attack", -1, 1.5)
# 2. 이동 중 상태: 속도 벡터가 존재할 때 (이동 상태)
elif velocity.length() > 0.1:
if _last_anim_state != "move":
_last_anim_state = "move"
_model_anim_player.play("striker/run", -1, 1.2)
_model_anim_player.play(library_prefix + "run", -1, 1.2)
# 3. 대기(Idle) 상태: 정지 상태일 때 대기 애니메이션 재생
else:
if _last_anim_state != "idle":
_last_anim_state = "idle"
_model_anim_player.play("striker/idle", -1, 1.0)
_model_anim_player.play(library_prefix + "idle", -1, 1.0)
else:
# Fallback: 기존 Jump 애니메이션 처리
var anim_name: String = "Armature|Armature|Basic_Jump|baselayer"
......
......@@ -25,7 +25,7 @@ outer_radius = 0.7
script = ExtResource("1_base_unit")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1651817390]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
transform = Transform3D(1.5, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 0, 0.6, 0)
shape = SubResource("CapsuleShape3D_body")
[node name="VisualMesh" type="MeshInstance3D" parent="." unique_id=1141960859]
......
[gd_scene format=3 uid="uid://dh00osxx32ll"]
[ext_resource type="PackedScene" uid="uid://ym45af2xwegi" path="res://assets/models/units/guardian/guardian.fbx" id="1_avjtn"]
[node name="guardian" unique_id=1303946976 instance=ExtResource("1_avjtn")]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0, 0)
[gd_scene format=3 uid="uid://cx4vbc5m3myqk"]
[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://dh00osxx32ll" path="res://src/entities/units/guardian/guardian.tscn" id="2_y84tp"]
[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="GuardianUnit" type="CharacterBody3D" unique_id=2140150158]
script = ExtResource("1_base_unit")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1623768716]
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=506359796]
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=1020833698]
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=1893995123]
[node name="guardian" parent="." unique_id=1303946976 instance=ExtResource("2_y84tp")]
......@@ -55,7 +55,7 @@ func _initialize_unit_templates() -> void:
# 2. Guardian (밸런스형 근접 유닛)
var guardian: UnitData = UnitData.new()
guardian.unit_id = "Unit_Striker"
guardian.unit_id = "Unit_Guardian"
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_Striker"
ranger.unit_id = "Unit_Ranger"
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_Striker"
slayer.unit_id = "Unit_Slayer"
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_Striker"
archmage.unit_id = "Unit_Archmage"
archmage.unit_name = "Archmage"
archmage.damage = 110.0
archmage.cooldown = 3.0
......@@ -136,12 +136,16 @@ func _on_spawn_pressed() -> void:
var random_index: int = randi() % _unit_templates.size()
var chosen_template: UnitData = _unit_templates[random_index]
# 유닛 객체 스폰 (Striker 전용 씬 분기 분할)
# 유닛 객체 스폰 (Striker 및 Guardian 전용 씬 분기 분할)
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
elif chosen_template.unit_id == "Unit_Guardian":
var guardian_scene: PackedScene = load("res://src/entities/units/guardian/guardian_unit.tscn") as PackedScene
if guardian_scene:
target_scene = guardian_scene
var new_unit: Node = target_scene.instantiate()
var parent_scene: Node = get_tree().current_scene
......
......@@ -47,4 +47,8 @@
- [x] Striker 전용 폴더 및 `striker_unit.tscn` 씬 파일 생성하여 FBX 인스턴스 링킹
- [x] `base_unit.gd``hud.gd` 리팩토링을 통해 소환 시 전용 씬 분기 소환 및 텍스처 오버라이드 맵핑 적용
- [x] 개별 FBX 파일들(`striker_idle.fbx`, `striker_walk.fbx`, `striker_run.fbx`, `striker_attack.fbx`)을 툴 스크립트로 단일 `AnimationLibrary` 리소스(`striker_animations.tres`)로 병합 완료
- [x] `base_unit.gd`에서 병합된 애니메이션 라이브러리를 동적 로드 및 주입하여 상태(Idle, Move, Attack)별 실제 애니메이션 연동 완료
- [x] 가디언 FBX 파일(`guardian.fbx`)에서 애니메이션들을 추출하여 단일 `AnimationLibrary` 리소스(`guardian_animations.tres`)로 병합 완료
- [x] `base_unit.gd`가 유닛 모델 노드명(예: `striker`, `guardian`)을 자동 감지해 해당 라이브러리를 바인딩하고 가변 배속으로 3D 애니메이션을 실시간 분기 연동하는 범용 3D 애니메이션 제어 시스템 구축 완료
- [x] `guardian_unit.tscn` 씬을 설계 및 신설하여 가디언 모델과 스킨 텍스처를 씬에 연계 완료
- [x] `hud.gd`에 중복되어 존재하던 유닛 ID 버그를 일괄 픽스하고, 가디언 유닛 소환 시 `guardian_unit.tscn`이 씬 분기로 올바르게 로드되도록 연동 완료
- [x] 사용자가 직접 `striker_unit.tscn`에서 모델 회전 보정을 적용한 상태를 인지하고, 스크립트(`base_unit.gd`)의 수동 Y축 회전 코드를 완벽히 제거
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