건설 인터랙션 관련 버그 수정 및 건설 데이터 구조 개선

건설 인터랙션 시 움직이지 못하는 문제 수정
2개로 분리되어 있던 타워 데이터를 하나로 통합
 - 대신 타워가 아닌 건물도 공격력 등을 정의할 수 있음
This commit is contained in:
2026-02-01 16:09:57 +09:00
parent 7927dab72f
commit 4200288fae
24 changed files with 235 additions and 337 deletions

View File

@@ -1,6 +1,7 @@
using System;
using Unity.Netcode;
using UnityEngine;
using Northbound.Data;
namespace Northbound
{
@@ -9,11 +10,19 @@ namespace Northbound
/// </summary>
public class BuildingFoundation : NetworkBehaviour, IInteractable, ITeamMember
{
[Header("Building Info")]
public BuildingData buildingData;
[Header("Target Building")]
public TowerData buildingData;
public Vector3Int gridPosition;
public int rotation;
[Header("Construction Settings")]
[Tooltip("상호작용 쿨다운 (초)")]
public float interactionCooldown = 1f;
[Tooltip("건설 시 플레이어가 재생할 애니메이션 트리거")]
public string constructionAnimationTrigger = "Build";
[Tooltip("건설 시 사용할 도구 (선택사항)")]
public EquipmentData constructionEquipment;
[Header("Visual")]
public GameObject foundationVisual;
public GameObject progressBarPrefab;
@@ -73,7 +82,7 @@ namespace Northbound
/// <summary>
/// 토대 초기화
/// </summary>
public void Initialize(BuildingData data, Vector3Int pos, int rot, ulong ownerId, TeamType team)
public void Initialize(TowerData data, Vector3Int pos, int rot, ulong ownerId, TeamType team)
{
if (!IsServer) return;
@@ -84,7 +93,7 @@ namespace Northbound
_team.Value = team;
_currentProgress.Value = 0f;
// BuildingData의 크기를 기반으로 스케일 설정
// TowerData의 크기를 기반으로 스케일 설정
Vector3 size = data.GetSize(rot);
// foundationVisual의 스케일만 조정 (토대 자체의 pivot은 중앙에 유지)
@@ -127,19 +136,19 @@ namespace Northbound
public bool CanInteract(ulong playerId)
{
if (buildingData == null)
{
Debug.LogWarning($"[BuildingFoundation] buildingData is null");
return false;
}
// 이미 완성됨
if (_currentProgress.Value >= buildingData.requiredWorkAmount)
{
Debug.Log($"[BuildingFoundation] Already completed");
return false;
}
// 쿨다운 확인
if (Time.time - _lastInteractionTime < interactionCooldown)
{
return false;
}
// 같은 팀만 건설 가능 - 플레이어의 팀을 가져와서 비교
TeamType playerTeam = GetPlayerTeam(playerId);
if (playerTeam != _team.Value)
@@ -153,17 +162,20 @@ namespace Northbound
public void Interact(ulong playerId)
{
if (!IsServer || buildingData == null) return;
if (!IsServer) return;
if (!CanInteract(playerId))
return;
_lastInteractionTime = Time.time;
// 건설 진행
_currentProgress.Value += buildingData.workPerInteraction;
// 플레이어의 작업량 가져오기
float playerWorkPower = GetPlayerWorkPower(playerId);
Debug.Log($"<color=green>[BuildingFoundation] 건설 진행: {_currentProgress.Value}/{buildingData.requiredWorkAmount} ({(_currentProgress.Value / buildingData.requiredWorkAmount * 100f):F1}%)</color>");
// 건설 진행
_currentProgress.Value += playerWorkPower;
Debug.Log($"<color=green>[BuildingFoundation] 건설 진행: {_currentProgress.Value}/{buildingData.requiredWorkAmount} ({(_currentProgress.Value / buildingData.requiredWorkAmount * 100f):F1}%) - 작업량: {playerWorkPower}</color>");
// 완성 체크
if (_currentProgress.Value >= buildingData.requiredWorkAmount)
@@ -174,34 +186,19 @@ namespace Northbound
public string GetInteractionPrompt()
{
if (buildingData == null)
return "[E] 건설하기";
string buildingName = buildingData != null ? buildingData.buildingName : "건물";
float percentage = (_currentProgress.Value / buildingData.requiredWorkAmount) * 100f;
return $"[E] {buildingData.buildingName} 건설 ({percentage:F0}%)";
return $"[E] {buildingName} 건설 ({percentage:F0}%)";
}
public string GetInteractionAnimation()
{
// BuildingData에서 애니메이션 트리거 가져오기
if (buildingData != null && !string.IsNullOrEmpty(buildingData.constructionAnimationTrigger))
{
return buildingData.constructionAnimationTrigger;
}
// 기본값: 빈 문자열 (애니메이션 없음)
return "";
return constructionAnimationTrigger;
}
public EquipmentData GetEquipmentData()
{
// BuildingData에 건설 도구가 정의되어 있으면 반환
if (buildingData != null && buildingData.constructionEquipment != null)
{
return buildingData.constructionEquipment;
}
return null; // 특별한 도구 불필요
return constructionEquipment;
}
public Transform GetTransform()
@@ -251,6 +248,32 @@ namespace Northbound
return TeamType.Player;
}
/// <summary>
/// 플레이어의 작업량 가져오기 (PlayerData.manpower)
/// </summary>
private float GetPlayerWorkPower(ulong playerId)
{
// PlayerInteraction 컴포넌트에서 workPower 가져오기
if (NetworkManager.Singleton != null && NetworkManager.Singleton.SpawnManager != null)
{
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client))
{
if (client.PlayerObject != null)
{
var playerInteraction = client.PlayerObject.GetComponent<PlayerInteraction>();
if (playerInteraction != null)
{
return playerInteraction.WorkPower;
}
}
}
}
// 기본값: 10
Debug.LogWarning($"[BuildingFoundation] 플레이어 {playerId}의 workPower를 찾을 수 없어 기본값 10을 사용합니다.");
return 10f;
}
private void CompleteConstruction()
{
if (!IsServer) return;
@@ -301,16 +324,13 @@ namespace Northbound
private void OnProgressValueChanged(float oldValue, float newValue)
{
if (buildingData != null)
{
OnProgressChanged?.Invoke(newValue, buildingData.requiredWorkAmount);
}
OnProgressChanged?.Invoke(newValue, buildingData.requiredWorkAmount);
UpdateProgressBar();
}
private void UpdateProgressBar()
{
if (_progressBarInstance == null || buildingData == null) return;
if (_progressBarInstance == null) return;
// 진행바 UI 업데이트 (BuildingHealthBar와 유사한 구조 사용 가능)
var progressBar = _progressBarInstance.GetComponent<BuildingHealthBar>();