Files
daluandou/Assets/Script/建筑脚本/BuildingPlacementManager.cs
T
huadexuan 8d58c2223c 根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:
```
docs(readme): 更新文档说明

- 添加项目使用指南
- 完善API接口说明
- 修正错误的配置示例
```
2026-10-01 16:01:43 +08:00

243 lines
6.4 KiB
C#

using System.Collections.Generic;
using UnityEngine;
public class BuildingPlacementManager : MonoBehaviour
{
public static BuildingPlacementManager Instance { get; private set; }
[Header("建筑预制体")]
public GameObject barracksBasePrefab;
public GameObject goldMinePrefab;
[Header("虚拟网格")]
[Min(0.1f)] public float gridSize = 1f;
[Min(0f)] public float placementHeight;
public Vector2 xLimits = new Vector2(-7f, 7f);
public Vector2 zLimits = new Vector2(-10f, 20f);
[Header("放置检测")]
public LayerMask groundLayer;
[Min(0.1f)] public float buildingRadius = 1.25f;
public Material previewMaterialValid;
public Material previewMaterialInvalid;
private readonly List<GameObject> placedBuildings = new List<GameObject>();
private CharacterData currentCharacterData;
private GameObject currentPrefab;
private GameObject previewObject;
private Camera mainCamera;
private bool isPlacing;
private bool previewPositionValid;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
private void Start()
{
mainCamera = Camera.main;
RegisterExistingBuilding(GameObject.Find("主要基地"));
}
private void Update()
{
if (!isPlacing)
{
return;
}
UpdatePreview();
if (Input.GetMouseButtonDown(0))
{
TryPlaceBuilding();
}
else if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape))
{
CancelPlacement();
}
}
public void StartPlacingBuilding(CharacterData data)
{
if (data == null)
{
return;
}
StartPlacingBarracks(data);
}
public void StartPlacingBarracks(CharacterData data)
{
if (data == null || barracksBasePrefab == null)
{
Debug.LogError("兵营预制体或角色数据为空");
return;
}
BeginPlacement(barracksBasePrefab, data);
}
public void StartPlacingGoldMine()
{
if (goldMinePrefab == null)
{
Debug.LogError("金矿预制体为空");
return;
}
BeginPlacement(goldMinePrefab, null);
}
private void BeginPlacement(GameObject prefab, CharacterData data)
{
CancelPlacement();
currentPrefab = prefab;
currentCharacterData = data;
previewObject = Instantiate(prefab);
previewObject.name = "建筑预览";
SetCollidersEnabled(previewObject, false);
isPlacing = true;
mainCamera = Camera.main;
}
private void UpdatePreview()
{
if (previewObject == null || mainCamera == null)
{
return;
}
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
int mask = groundLayer.value == 0 ? Physics.DefaultRaycastLayers : groundLayer.value;
if (!Physics.Raycast(ray, out RaycastHit hit, 1000f, mask))
{
previewPositionValid = false;
return;
}
Vector3 position = hit.point;
position.x = Mathf.Round(position.x / gridSize) * gridSize;
position.y = placementHeight;
position.z = Mathf.Round(position.z / gridSize) * gridSize;
previewObject.transform.position = position;
previewPositionValid = IsValidPosition(position);
UpdatePreviewMaterial(previewPositionValid);
}
private bool IsValidPosition(Vector3 position)
{
if (position.x < xLimits.x || position.x > xLimits.y ||
position.z < zLimits.x || position.z > zLimits.y)
{
return false;
}
foreach (GameObject building in placedBuildings)
{
if (building != null && Vector3.Distance(position, building.transform.position) < buildingRadius * 2f)
{
return false;
}
}
return true;
}
private void TryPlaceBuilding()
{
if (!previewPositionValid || previewObject == null || currentPrefab == null)
{
return;
}
int cost = 100;
if (GoldSystem.Instance == null || !GoldSystem.Instance.TrySpend(cost))
{
Debug.Log($"金币不足,需要{cost}");
return;
}
Vector3 position = previewObject.transform.position;
GameObject building = Instantiate(currentPrefab, position, Quaternion.identity);
building.name = currentCharacterData != null
? "兵营_" + currentCharacterData.characterName
: "金矿";
building.tag = "Friend";
if (building.GetComponent<BuildingHealth>() == null)
{
building.AddComponent<BuildingHealth>();
}
if (currentCharacterData != null)
{
Barracks barracks = building.GetComponent<Barracks>();
if (barracks == null)
{
barracks = building.AddComponent<Barracks>();
}
barracks.characterData = currentCharacterData;
}
else if (building.GetComponent<GoldMine>() == null)
{
building.AddComponent<GoldMine>();
}
placedBuildings.Add(building);
CancelPlacement();
}
private void UpdatePreviewMaterial(bool valid)
{
Material material = valid ? previewMaterialValid : previewMaterialInvalid;
if (material == null || previewObject == null)
{
return;
}
foreach (Renderer renderer in previewObject.GetComponentsInChildren<Renderer>())
{
renderer.sharedMaterial = material;
}
}
private void SetCollidersEnabled(GameObject target, bool enabled)
{
foreach (Collider collider in target.GetComponentsInChildren<Collider>())
{
collider.enabled = enabled;
}
}
public void RegisterExistingBuilding(GameObject building)
{
if (building != null && !placedBuildings.Contains(building))
{
placedBuildings.Add(building);
}
}
public void CancelPlacement()
{
if (previewObject != null)
{
Destroy(previewObject);
}
previewObject = null;
currentPrefab = null;
currentCharacterData = null;
isPlacing = false;
previewPositionValid = false;
}
}