Commit 9939b856 authored by Gavin An's avatar Gavin An

적 스킨 입혀보기

parent 75637f7e
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://8pu2q731ei7i"
path="res://.godot/imported/noble_man.fbx-80379b336d6564d95d818f6c95855444.scn"
[deps]
source_file="res://assets/models/monsters/noble_man/noble_man.fbx"
dest_files=["res://.godot/imported/noble_man.fbx-80379b336d6564d95d818f6c95855444.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://ci7uko0kt5ggc"
path.s3tc="res://.godot/imported/noble_man_0.png-c89c315cc96625e1b3c7d50a395d7a2a.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={
"md5": "0c6aa6755e0a85b8056f439c30891ea3"
}
[deps]
source_file="res://assets/models/monsters/noble_man/noble_man_0.png"
dest_files=["res://.godot/imported/noble_man_0.png-c89c315cc96625e1b3c7d50a395d7a2a.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.
...@@ -2,7 +2,7 @@ ...@@ -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://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="Script" uid="uid://cq7r51whh6po" path="res://src/core/stage_manager.gd" id="2_stage_mgr"]
[ext_resource type="PackedScene" uid="uid://bslqp550s3j0s" path="res://sandbox/monsters/monster_fit_test.tscn" id="3_base_monster"] [ext_resource type="PackedScene" path="res://src/entities/monsters/noble_man/noble_man_unit.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="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"] [ext_resource type="PackedScene" uid="uid://bqga1rvcjyydy" path="res://src/ui/hud.tscn" id="5_hud"]
......
...@@ -10,6 +10,10 @@ var current_hp: float = 100.0 ...@@ -10,6 +10,10 @@ var current_hp: float = 100.0
var gold_reward: int = 15 var gold_reward: int = 15
var is_dead: bool = false var is_dead: bool = false
var _hp_bar: ProgressBar = null
var _model_instance: Node3D = null
var _model_anim_player: AnimationPlayer = null
var _last_anim_state: String = ""
func _ready() -> void: func _ready() -> void:
# 몬스터 그룹 등록 # 몬스터 그룹 등록
...@@ -17,14 +21,71 @@ func _ready() -> void: ...@@ -17,14 +21,71 @@ func _ready() -> void:
# PathFollow3D 루프 설정 활성화 (경로 끝 도달 시 처음으로 돌아감) # PathFollow3D 루프 설정 활성화 (경로 끝 도달 시 처음으로 돌아감)
loop = true loop = true
# 자식 노드 중 3D 모델(noble_man 등) 노드 자동 탐색 및 초기화 (base_unit.gd 매커니즘 준수)
var model_names: Array[String] = ["noble_man"]
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 == "noble_man":
_apply_noble_man_skin(_model_instance)
_model_anim_player = _find_animation_player(_model_instance)
if _model_anim_player:
print("BaseMonster: Linked model AnimationPlayer: ", detected_model_name)
# 모델명_animations.tres 라이브러리를 동적으로 로드하여 등록 (base_unit.gd 방식 준수)
var anim_lib_path: String = "res://assets/models/monsters/" + 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(detected_model_name, lib)
print("BaseMonster: Loaded and registered ", detected_model_name, " animations library successfully.")
# 초기 Idle 애니메이션 재생 시도
var init_idle: String = detected_model_name + "/Idle"
if _model_anim_player.has_animation(init_idle):
_model_anim_player.play(init_idle)
elif _model_anim_player.has_animation("Armature|Idle"):
_model_anim_player.play("Armature|Idle")
## 몬스터 자식 메쉬에 noble_man_0.png 텍스처를 입히는 재귀 함수
func _apply_noble_man_skin(node: Node) -> void:
if node is MeshInstance3D:
var mesh_inst: MeshInstance3D = node as MeshInstance3D
var texture_path: String = "res://assets/models/monsters/noble_man/noble_man_0.png"
if ResourceLoader.exists(texture_path):
var texture: Texture2D = load(texture_path) 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_noble_man_skin(child)
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if GameManager.is_game_over or is_dead: if GameManager.is_game_over or is_dead:
if _model_anim_player and _model_anim_player.is_playing():
_model_anim_player.stop()
return return
# 경로 이동 거리 갱신 # 경로 이동 거리 갱신
progress += speed * delta progress += speed * delta
# 걷는 애니메이션 갱신
_update_monster_animation()
## 몬스터 초기화 (StageManager에 의해 스폰 시 호출됨) ## 몬스터 초기화 (StageManager에 의해 스폰 시 호출됨)
func initialize_monster(hp: float, reward: int) -> void: func initialize_monster(hp: float, reward: int) -> void:
max_hp = hp max_hp = hp
...@@ -32,12 +93,18 @@ func initialize_monster(hp: float, reward: int) -> void: ...@@ -32,12 +93,18 @@ func initialize_monster(hp: float, reward: int) -> void:
gold_reward = reward gold_reward = reward
is_dead = false is_dead = false
# 체력바 생성
_create_hp_bar()
## 피해 가하기 ## 피해 가하기
func take_damage(amount: float) -> void: func take_damage(amount: float) -> void:
if is_dead: if is_dead:
return return
current_hp = maxf(0.0, current_hp - amount) current_hp = maxf(0.0, current_hp - amount)
if _hp_bar:
_hp_bar.value = current_hp
print("Monster ", name, " took ", amount, " damage. HP: ", current_hp, "/", max_hp) print("Monster ", name, " took ", amount, " damage. HP: ", current_hp, "/", max_hp)
if current_hp <= 0.0: if current_hp <= 0.0:
...@@ -57,3 +124,79 @@ func _die() -> void: ...@@ -57,3 +124,79 @@ func _die() -> void:
# 씬에서 제거 # 씬에서 제거
queue_free() queue_free()
## 체력바 UI 생성 및 3D 공간 머리 위 빌보드 배치
func _create_hp_bar() -> void:
# 1. SubViewport 생성 (2D UI를 3D 텍스처로 렌더링하기 위함)
var viewport: SubViewport = SubViewport.new()
viewport.size = Vector2i(100, 12)
viewport.transparent_bg = true
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
add_child(viewport)
# 2. ProgressBar 생성
_hp_bar = ProgressBar.new()
_hp_bar.size = Vector2(100, 12)
_hp_bar.show_percentage = false
_hp_bar.min_value = 0.0
_hp_bar.max_value = max_hp
_hp_bar.value = current_hp
# 스타일박스를 사용하여 빨간색 HP 게이지 디자인 커스텀
var style_bg: StyleBoxFlat = StyleBoxFlat.new()
style_bg.bg_color = Color(0.15, 0.15, 0.15, 0.8) # 어두운 회색 배경
style_bg.set_corner_radius_all(2)
var style_fg: StyleBoxFlat = StyleBoxFlat.new()
style_fg.bg_color = Color(0.9, 0.1, 0.1, 1.0) # 강렬한 빨간색 fill
style_fg.set_corner_radius_all(2)
_hp_bar.add_theme_stylebox_override("background", style_bg)
_hp_bar.add_theme_stylebox_override("fill", style_fg)
viewport.add_child(_hp_bar)
# 3. Sprite3D 생성 (Viewport의 2D 렌더링 텍스처를 3D 공간에 띄움)
var sprite: Sprite3D = Sprite3D.new()
sprite.billboard = BaseMaterial3D.BILLBOARD_ENABLED # 카메라를 항상 마주하도록 설정
sprite.position = Vector3(0.0, 1.2, 0.0) # 몬스터 머리 위 오프셋
sprite.texture = viewport.get_texture()
sprite.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF # 그림자 연산 제외
sprite.no_depth_test = false # 지형이나 다른 장막 뒤에 가려지도록 설정
add_child(sprite)
## 몬스터 이동 상태에 맞춘 애니메이션 재생 제어
func _update_monster_animation() -> void:
if not _model_anim_player:
return
# 기본 트랙 이름 탐색 순서: 동적 로드된 라이브러리(noble_man/walking) -> FBX 내장 트랙(Armature|Walking)
var anim_name: String = ""
var model_name: String = ""
if _model_instance:
model_name = _model_instance.name.to_lower()
var lib_walking: String = model_name + "/Walking"
if _model_anim_player.has_animation(lib_walking):
anim_name = lib_walking
elif _model_anim_player.has_animation("Armature|Walking"):
anim_name = "Armature|Walking"
if anim_name != "":
# 걷는 애니메이션 루프 활성화
var anim: Animation = _model_anim_player.get_animation(anim_name)
if anim:
anim.loop_mode = Animation.LOOP_LINEAR
if _last_anim_state != "walking":
_last_anim_state = "walking"
_model_anim_player.play(anim_name, -1, 1.2) # 1.2배속 재생
## 헬퍼: 자식 노드 중 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
[gd_scene format=3 uid="uid://dy3qfnuybgjg6"]
[ext_resource type="PackedScene" uid="uid://8pu2q731ei7i" path="res://assets/models/monsters/noble_man/noble_man.fbx" id="1_fbx"]
[node name="noble_man" unique_id=1062436170 instance=ExtResource("1_fbx")]
transform = Transform3D(1, 0, 0, 0, 0.8, 0, 0, 0, 1, 0, 0, 0)
[gd_scene format=3 uid="uid://dimlohck6ebg7"]
[ext_resource type="Script" uid="uid://bj0j32wc3fvkg" path="res://src/entities/monsters/base_monster.gd" id="1_base_monster"]
[ext_resource type="PackedScene" uid="uid://dy3qfnuybgjg6" path="res://src/entities/monsters/noble_man/noble_man.tscn" id="2_noble_man"]
[sub_resource type="SphereShape3D" id="SphereShape3D_collision"]
radius = 0.6
[node name="NobleManMonster" type="PathFollow3D" unique_id=1485091855]
script = ExtResource("1_base_monster")
[node name="noble_man" parent="." unique_id=174344433 instance=ExtResource("2_noble_man")]
transform = Transform3D(-1, 0, 1.509958e-07, 0, 1, 0, -1.509958e-07, 0, -1, 0, 0, 0)
[node name="Skeleton3D" parent="noble_man/Armature" parent_id_path=PackedInt32Array(174344433, 789802200) index="0" unique_id=1272502782]
bones/0/rotation = Quaternion(0.61798733, -0.23847091, -0.29544434, 0.68843013)
bones/0/scale = Vector3(1.1764706, 1.1764706, 1.1764708)
bones/1/position = Vector3(0.10183821, -0.10193097, -0.0022784735)
bones/1/rotation = Quaternion(0.948611, 0.16393991, -0.13692817, 0.23347755)
bones/1/scale = Vector3(1.0000077, 1, 1)
bones/2/position = Vector3(8.925652e-09, 0.417691, -5.1505884e-09)
bones/2/rotation = Quaternion(0.45852306, 0.19937582, 0.07257126, 0.8629828)
bones/2/scale = Vector3(1.0000001, 1.0000004, 1.0000002)
bones/3/position = Vector3(-2.5261881e-09, 0.42174494, 7.2241504e-11)
bones/3/rotation = Quaternion(-0.58492714, -0.06132251, 0.009246678, 0.8087116)
bones/3/scale = Vector3(1, 1, 1)
bones/4/position = Vector3(1.2221635e-08, 0.13995555, 2.1287123e-08)
bones/4/rotation = Quaternion(-0.36768854, -0.001687522, 0.01695024, 0.929793)
bones/4/scale = Vector3(0.9999998, 1, 0.9999998)
bones/5/position = Vector3(-0.099749625, -0.1055433, -0.00022072843)
bones/5/rotation = Quaternion(0.97120684, -0.17415474, 0.16172291, 0.016525293)
bones/5/scale = Vector3(1.000016, 0.99999976, 1.0000005)
bones/6/position = Vector3(-2.6841812e-08, 0.4172189, 1.4898632e-08)
bones/6/rotation = Quaternion(0.41857097, -0.0034188193, -0.012350971, 0.90809375)
bones/6/scale = Vector3(1.0000001, 1, 1.0000001)
bones/7/position = Vector3(-1.1679395e-08, 0.41914502, -1.1094577e-07)
bones/7/rotation = Quaternion(-0.6098559, 0.15362522, -0.09189053, 0.7720306)
bones/7/scale = Vector3(1, 1.0000001, 1)
bones/8/position = Vector3(5.047954e-10, 0.12296724, -2.2279302e-08)
bones/8/rotation = Quaternion(-0.41545272, 0.041144814, 0.034620646, 0.9080241)
bones/8/scale = Vector3(0.9999999, 0.9999999, 0.9999999)
bones/9/position = Vector3(-0.0020885684, 0.116008654, 0.0024992328)
bones/9/rotation = Quaternion(0.057457034, 0.05244976, 0.0038327165, 0.99696195)
bones/9/scale = Vector3(0.99999994, 0.9999998, 0.99999976)
bones/10/position = Vector3(-2.2647062e-09, 0.11605439, -9.138862e-09)
bones/10/rotation = Quaternion(0.09807169, 0.08359734, -0.014605932, 0.9915544)
bones/10/scale = Vector3(1.0000001, 1.0000002, 1.0000002)
bones/11/position = Vector3(5.6057953e-16, 0.11605399, -1.8735637e-09)
bones/11/rotation = Quaternion(0.04436318, 0.07711244, -0.0016378432, 0.9960336)
bones/11/scale = Vector3(0.9999999, 1, 1)
bones/12/position = Vector3(0.042316522, 0.018807229, -0.0012655992)
bones/12/rotation = Quaternion(0.56446123, 0.5134929, -0.49502933, 0.41551715)
bones/12/scale = Vector3(1.0000001, 1.0000001, 1.0000002)
bones/13/position = Vector3(1.2083032e-07, 0.1687637, -1.5166692e-07)
bones/13/rotation = Quaternion(0.50597435, 0.2815535, 0.34607968, 0.73820496)
bones/13/scale = Vector3(1.0000001, 1.0000001, 1)
bones/14/position = Vector3(7.0695954e-08, 0.28124455, -4.496629e-08)
bones/14/rotation = Quaternion(-0.34847364, 0.062623285, 0.18896937, 0.91593397)
bones/14/scale = Vector3(0.99999994, 1, 1)
bones/15/position = Vector3(5.1876157e-08, 0.2978702, 1.1475281e-07)
bones/15/rotation = Quaternion(0.04238946, 0.23705958, -0.05192386, 0.96918)
bones/15/scale = Vector3(1, 0.99999994, 0.99999994)
bones/16/position = Vector3(-0.042962536, 0.012112379, -0.0065097106)
bones/16/rotation = Quaternion(-0.6090661, 0.47468537, -0.4630349, -0.4350989)
bones/16/scale = Vector3(0.9999999, 1, 1)
bones/17/position = Vector3(-1.3961997e-07, 0.17218974, -1.2206406e-06)
bones/17/rotation = Quaternion(0.6119551, -0.3172246, -0.11668171, 0.715028)
bones/17/scale = Vector3(1.0000001, 1, 1.0000002)
bones/18/position = Vector3(4.2020838e-07, 0.26897195, 9.862248e-08)
bones/18/rotation = Quaternion(-0.31137317, 0.04883886, -0.2067891, 0.9262288)
bones/18/scale = Vector3(0.99999994, 1, 1)
bones/19/position = Vector3(-8.227692e-08, 0.2969355, 4.939664e-09)
bones/19/rotation = Quaternion(0.1326664, -0.22648887, -0.21849182, 0.9398743)
bones/19/scale = Vector3(0.99999994, 0.9999998, 0.9999998)
bones/20/position = Vector3(0.00064602116, 0.07547628, 0.007775514)
bones/20/rotation = Quaternion(0.01384508, -0.0055730203, -0.0030556368, 0.999884)
bones/20/scale = Vector3(1, 1, 0.9999998)
bones/21/position = Vector3(-2.7577591e-09, 0.07526942, -1.1876011e-07)
bones/21/rotation = Quaternion(0.18938631, 0.16970475, -0.04936101, 0.96586573)
bones/21/scale = Vector3(1, 1.0000001, 1.0000002)
bones/22/position = Vector3(-3.6878883e-10, 0.30715173, -0.13331519)
bones/22/rotation = Quaternion(-0.20926115, 0.001348063, 0.001918764, 0.977857)
bones/22/scale = Vector3(1, 1.0000001, 1)
bones/23/position = Vector3(3.687908e-10, 0.06441903, 0.13331476)
bones/23/rotation = Quaternion(0.53147227, 2.0621675e-07, -3.5311455e-08, 0.84707576)
bones/23/scale = Vector3(1, 1, 1.0000001)
[node name="MonsterArea" type="Area3D" parent="." unique_id=2000374352]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="MonsterArea" unique_id=1747323172]
shape = SubResource("SphereShape3D_collision")
[editable path="noble_man"]
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