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

건설 인터랙션 시 움직이지 못하는 문제 수정
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,13 +1,14 @@
using System;
using Unity.Netcode;
using UnityEngine;
using Northbound.Data;
namespace Northbound
{
public class Building : NetworkBehaviour, IDamageable, IVisionProvider, ITeamMember
{
[Header("References")]
public BuildingData buildingData;
public TowerData buildingData;
[Header("Runtime Info")]
public Vector3Int gridPosition;
@@ -152,7 +153,7 @@ namespace Northbound
/// <summary>
/// 건물 초기화 (BuildingManager가 동적 생성 시 호출)
/// </summary>
public void Initialize(BuildingData data, Vector3Int gridPos, int rot, ulong ownerId, TeamType team = TeamType.Player)
public void Initialize(TowerData data, Vector3Int gridPos, int rot, ulong ownerId, TeamType team = TeamType.Player)
{
buildingData = data;
gridPosition = gridPos;
@@ -462,7 +463,7 @@ namespace Northbound
#region Grid Bounds
/// <summary>
/// Gets the grid-based bounds (from BuildingData width/length/height)
/// Gets the grid-based bounds (from TowerData width/length/height)
/// This is used for placement validation, NOT the actual collider bounds
/// Bounds are slightly shrunk to allow adjacent buildings to touch
/// </summary>

View File

@@ -1,65 +0,0 @@
using UnityEngine;
namespace Northbound
{
[CreateAssetMenu(fileName = "NewBuilding", menuName = "Northbound/Building Data")]
public class BuildingData : ScriptableObject
{
[Header("Building Info")]
public string buildingName;
public GameObject prefab;
[Tooltip("UI에 표시될 건물 아이콘")]
public Sprite icon;
[Header("Grid Size")]
[Tooltip("Width in grid units")]
public int width = 1;
[Tooltip("Length in grid units")]
public int length = 1;
[Tooltip("Height for placement validation")]
public float height = 2f;
[Header("Placement Settings")]
[Tooltip("Offset from grid position")]
public Vector3 placementOffset = Vector3.zero;
[Tooltip("Can rotate this building?")]
public bool allowRotation = true;
[Header("Construction Settings")]
[Tooltip("건설 완료에 필요한 총 작업량")]
public float requiredWorkAmount = 100f;
[Tooltip("1회 상호작용당 작업량")]
public float workPerInteraction = 10f;
[Tooltip("상호작용 쿨다운 (초)")]
public float interactionCooldown = 1f;
[Tooltip("건설 시 플레이어가 재생할 애니메이션 트리거 (예: Build, Hammer, Construct)")]
public string constructionAnimationTrigger = "Build";
[Tooltip("건설 시 사용할 도구 (선택사항)")]
public EquipmentData constructionEquipment;
[Header("Health Settings")]
[Tooltip("Maximum health of the building")]
public int maxHealth = 100;
[Tooltip("Can this building be damaged?")]
public bool isIndestructible = false;
[Tooltip("Auto-regenerate health over time")]
public bool autoRegenerate = false;
[Tooltip("Health regeneration per second")]
public int regenPerSecond = 1;
[Header("Vision Settings")]
[Tooltip("Does this building provide vision?")]
public bool providesVision = true;
[Tooltip("Vision range in world units")]
public float visionRange = 15f;
public Vector3 GetSize(int rotation)
{
// Rotation 0,180 = normal, 90,270 = swap width/length
bool isRotated = (rotation == 1 || rotation == 3);
float w = isRotated ? length : width;
float l = isRotated ? width : length;
return new Vector3(w, height, l);
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 937e64980d44d6b46acb35b8046adf34

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>();

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using Northbound.Data;
namespace Northbound
{
@@ -13,7 +14,7 @@ namespace Northbound
public LayerMask groundLayer;
[Header("Building Database")]
public List<BuildingData> availableBuildings = new List<BuildingData>();
public List<TowerData> availableBuildings = new List<TowerData>();
[Header("Foundation Settings")]
public GameObject foundationPrefab; // 토대 프리팹 (Inspector에서 할당)
@@ -58,7 +59,7 @@ namespace Northbound
);
}
public bool IsValidPlacement(BuildingData data, Vector3 position, int rotation, out Vector3 groundPosition)
public bool IsValidPlacement(TowerData data, Vector3 position, int rotation, out Vector3 groundPosition)
{
groundPosition = position;
@@ -71,7 +72,7 @@ namespace Northbound
Vector3 snappedPosition = SnapToGrid(groundPosition);
groundPosition = snappedPosition; // Update groundPosition to snapped value
// Overlap check using GRID SIZE from BuildingData (not actual colliders)
// Overlap check using GRID SIZE from TowerData (not actual colliders)
Vector3 gridSize = data.GetSize(rotation);
// 프리팹의 실제 배치 위치 계산 (placementOffset 포함)
@@ -130,7 +131,7 @@ namespace Northbound
/// Get the grid bounds for a building at a given position
/// Useful for preview visualization
/// </summary>
public Bounds GetPlacementBounds(BuildingData data, Vector3 position, int rotation)
public Bounds GetPlacementBounds(TowerData data, Vector3 position, int rotation)
{
Vector3 gridSize = data.GetSize(rotation);
// position은 이미 placementOffset이 적용된 위치
@@ -183,7 +184,7 @@ namespace Northbound
return;
}
BuildingData data = availableBuildings[buildingIndex];
TowerData data = availableBuildings[buildingIndex];
// 보안 검증 3: 건물 데이터 유효성 확인
if (data == null || data.prefab == null)
@@ -335,7 +336,7 @@ namespace Northbound
return;
}
BuildingData data = availableBuildings[buildingIndex];
TowerData data = availableBuildings[buildingIndex];
// 보안 검증 3: 건물 데이터 유효성 확인
if (data == null)
@@ -427,8 +428,8 @@ namespace Northbound
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void SpawnCompletedBuildingServerRpc(string buildingDataName, Vector3Int gridPosition, int rotation, ulong ownerId, TeamType team)
{
// BuildingData 찾기
BuildingData data = availableBuildings.Find(b => b.name == buildingDataName);
// TowerData 찾기
TowerData data = availableBuildings.Find(b => b.name == buildingDataName);
if (data == null || data.prefab == null)
{
Debug.LogError($"<color=red>[BuildingManager] 건물 데이터를 찾을 수 없습니다: {buildingDataName}</color>");

View File

@@ -3,6 +3,7 @@ using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.EventSystems;
using Northbound.Data;
namespace Northbound
{
@@ -248,20 +249,20 @@ namespace Northbound
return;
}
BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
TowerData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
if (data == null)
{
Debug.LogError($"[BuildingPlacement] BuildingData is NULL at index {selectedBuildingIndex}");
Debug.LogError($"[BuildingPlacement] TowerData is NULL at index {selectedBuildingIndex}");
return;
}
if (data.prefab == null)
{
Debug.LogError($"[BuildingPlacement] BuildingData.prefab is NULL at index {selectedBuildingIndex}. Run 'Northbound > Diagnose Tower System'");
Debug.LogError($"[BuildingPlacement] TowerData.prefab is NULL at index {selectedBuildingIndex}. Run 'Northbound > Diagnose Tower System'");
return;
}
Debug.Log($"<color=green>[BuildingPlacement] BuildingData: {data.buildingName}, Prefab: {data.prefab.name}</color>");
Debug.Log($"<color=green>[BuildingPlacement] TowerData: {data.buildingName}, Prefab: {data.prefab.name}</color>");
Debug.Log($"<color=green>[BuildingPlacement] Prefab scale: {data.prefab.transform.localScale}</color>");
// 완성 건물 프리팹으로 프리뷰 생성 (사용자가 완성 모습을 볼 수 있도록)
@@ -319,7 +320,7 @@ namespace Northbound
if (selectedBuildingIndex < 0 || selectedBuildingIndex >= BuildingManager.Instance.availableBuildings.Count)
return;
BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
TowerData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
if (data == null || data.prefab == null)
return;
@@ -444,10 +445,10 @@ namespace Northbound
return;
}
BuildingData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
TowerData data = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
if (data == null || data.prefab == null)
{
Debug.LogError($"[BuildingPlacement] BuildingData or prefab is null at index {selectedBuildingIndex}. Please run 'Northbound > Populate Towers from Prefabs' and update BuildingManager.");
Debug.LogError($"[BuildingPlacement] TowerData or prefab is null at index {selectedBuildingIndex}. Please run 'Northbound > Populate Towers from Prefabs' and update BuildingManager.");
return;
}
@@ -516,7 +517,7 @@ namespace Northbound
}
}
private List<Vector3> CalculateDragBuildingPositions(Vector3 start, Vector3 end, BuildingData data)
private List<Vector3> CalculateDragBuildingPositions(Vector3 start, Vector3 end, TowerData data)
{
List<Vector3> positions = new List<Vector3>();
@@ -566,7 +567,7 @@ namespace Northbound
return;
}
BuildingData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
int successCount = 0;
foreach (var position in dragBuildingPositions)
@@ -606,7 +607,7 @@ namespace Northbound
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
{
BuildingData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
if (BuildingManager.Instance.IsValidPlacement(selectedData, hit.point, currentRotation, out Vector3 groundPosition))
{

View File

@@ -3,6 +3,7 @@ using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
using Northbound.Data;
namespace Northbound
{
@@ -196,7 +197,7 @@ namespace Northbound
/// <summary>
/// 개별 슬롯 버튼 생성
/// </summary>
private void CreateSlot(BuildingData buildingData, int index)
private void CreateSlot(TowerData buildingData, int index)
{
GameObject slotObj = Instantiate(slotButtonPrefab, slotContainer);
BuildingSlotButton slotButton = slotObj.GetComponent<BuildingSlotButton>();

View File

@@ -2,6 +2,7 @@ using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using Northbound.Data;
namespace Northbound
{
@@ -23,7 +24,7 @@ namespace Northbound
[SerializeField] private Color selectedColor = new Color(0.3f, 0.6f, 0.3f, 1f);
[SerializeField] private Color hoverColor = new Color(0.3f, 0.3f, 0.3f, 1f);
private BuildingData buildingData;
private TowerData buildingData;
private int slotIndex;
private BuildingQuickslotUI quickslotUI;
private bool isSelected = false;
@@ -42,7 +43,7 @@ namespace Northbound
/// <summary>
/// 슬롯 초기화
/// </summary>
public void Initialize(BuildingData data, int index, BuildingQuickslotUI ui)
public void Initialize(TowerData data, int index, BuildingQuickslotUI ui)
{
buildingData = data;
slotIndex = index;

View File

@@ -123,10 +123,9 @@ namespace Northbound.Editor
}
// If towers were imported, auto-configure BuildingManager
// TowerData now extends BuildingData, so it can be used directly!
if (typeName == "Tower")
{
Debug.Log($"<color=cyan>[CSVToSOImporter] Tower import complete, TowerData extends BuildingData now!</color>");
Debug.Log($"<color=cyan>[CSVToSOImporter] Tower import complete!</color>");
}
return true;
@@ -203,10 +202,10 @@ namespace Northbound.Editor
}
// Now set the prefab reference on data
if (data is BuildingData buildingData)
if (data is TowerData towerData)
{
buildingData.prefab = prefabObj;
Debug.Log($"[CSVToSOImporter] Set prefab reference: {buildingData.name} -> {prefabObj.name}");
towerData.prefab = prefabObj;
Debug.Log($"[CSVToSOImporter] Set prefab reference: {towerData.name} -> {prefabObj.name}");
}
// Save data asset
@@ -236,9 +235,9 @@ namespace Northbound.Editor
return;
}
// Load TowerData (which extends BuildingData)
// Load TowerData
string[] towerDataGuids = AssetDatabase.FindAssets("t:TowerData", new[] { "Assets/Data/ScriptableObjects" });
List<BuildingData> allTowers = new List<BuildingData>();
List<TowerData> allTowers = new List<TowerData>();
Debug.Log($"<color=cyan>[CSVToSOImporter] Found {towerDataGuids.Length} TowerData assets</color>");

View File

@@ -84,6 +84,15 @@ namespace Northbound.Editor
Debug.Log($"[PlayerPrefabSetup] Updated PlayerResourceInventory: maxResourceCapacity={playerData.capacity}");
}
var playerInteraction = prefab.GetComponent<PlayerInteraction>();
if (playerInteraction != null)
{
SerializedObject so = new SerializedObject(playerInteraction);
so.FindProperty("workPower").floatValue = playerData.manpower;
so.ApplyModifiedProperties();
Debug.Log($"[PlayerPrefabSetup] Updated PlayerInteraction: workPower={playerData.manpower}");
}
EditorUtility.SetDirty(prefab);
PrefabUtility.SavePrefabAsset(prefab);
Debug.Log($"[PlayerPrefabSetup] Player prefab updated successfully from {playerData.name}");

View File

@@ -159,9 +159,6 @@ namespace Northbound.Editor
if (go.GetComponent<Building>() == null)
go.AddComponent<Building>();
if (go.GetComponent<TowerDataComponent>() == null)
go.AddComponent<TowerDataComponent>();
if (go.GetComponent<BoxCollider>() == null)
{
BoxCollider collider = go.AddComponent<BoxCollider>();

View File

@@ -30,10 +30,10 @@ namespace Northbound.Editor
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
TowerDataComponent tower = prefab?.GetComponent<TowerDataComponent>();
string towerStatus = tower != null && tower.towerData != null ? "<color=green>✓</color>" : "<color=red>✗</color>";
string towerDataName = tower?.towerData?.name ?? "MISSING";
Debug.Log($" {towerStatus} {prefab.name} - TowerDataComponent: {tower != null}, TowerData: {towerDataName}");
Building building = prefab?.GetComponent<Building>();
string towerStatus = building != null && building.buildingData != null ? "<color=green>✓</color>" : "<color=red>✗</color>";
string towerDataName = building?.buildingData?.name ?? "MISSING";
Debug.Log($" {towerStatus} {prefab.name} - Building: {building != null}, TowerData: {towerDataName}");
}
}

View File

@@ -20,24 +20,9 @@ namespace Northbound.Editor
return;
}
var towerDataComponent = prefab.GetComponent<TowerDataComponent>();
if (towerDataComponent == null)
{
towerDataComponent = prefab.AddComponent<TowerDataComponent>();
Debug.Log($"[TowerPrefabSetup] Added TowerDataComponent component");
}
if (towerDataComponent != null)
{
towerDataComponent.towerData = towerData;
}
// TowerData now extends BuildingData, so set prefab reference
// Set prefab reference
towerData.prefab = prefab;
// Ensure TowerData fields are synced to BuildingData
towerData.EnsureSynced();
Transform modelTransform = null;
if (!string.IsNullOrEmpty(towerData.modelPath))

View File

@@ -12,19 +12,20 @@ namespace Northbound
[Header("Interaction Settings")]
public float interactionRange = 3f;
public LayerMask interactableLayer = ~0;
public float workPower = 10f;
[Header("Detection")]
public Transform rayOrigin;
public bool useForwardDirection = true;
[Header("Animation")]
public bool playAnimations = true;
public bool useAnimationEvents = true;
public bool blockDuringAnimation = true;
[Header("Equipment")]
public bool useEquipment = true;
[Header("Debug")]
public bool showDebugRay = true;
@@ -41,6 +42,7 @@ namespace Northbound
// 다른 컴포넌트가 이동 차단 여부를 확인할 수 있도록 public 프로퍼티 제공
public bool IsInteracting => _isInteracting;
public float WorkPower => workPower;
public override void OnNetworkSpawn()
{
@@ -71,6 +73,17 @@ namespace Northbound
private void Update()
{
if (!IsOwner) return;
// Check if current interactable is no longer valid (e.g., building completed)
if (_isInteracting && _currentInteractable != null)
{
if (!_currentInteractable.CanInteract(OwnerClientId))
{
Debug.Log("[PlayerInteraction] Interactable no longer valid - ending interaction");
EndInteraction();
}
}
DetectInteractable();
}
@@ -243,6 +256,16 @@ namespace Northbound
}
}
private void EndInteraction()
{
_isInteracting = false;
if (_interactionTimeoutCoroutine != null)
{
StopCoroutine(_interactionTimeoutCoroutine);
_interactionTimeoutCoroutine = null;
}
}
private void OnGUI()
{
if (!IsOwner || _currentInteractable == null) return;

View File

@@ -1,26 +0,0 @@
using Northbound.Data;
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
[RequireComponent(typeof(Building))]
[RequireComponent(typeof(NetworkObject))]
public class TowerDataComponent : MonoBehaviour
{
[Header("Data Reference")]
[Tooltip("ScriptableObject containing tower data")]
public TowerData towerData;
private void Awake()
{
// TowerData now extends BuildingData, so just pass it directly
Building building = GetComponent<Building>();
if (building != null && towerData != null)
{
building.buildingData = towerData;
building.initialTeam = TeamType.Player;
}
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 56c4536effc49fe47af593bf9d17e979