```
feat(gameplay): 添加建筑系统和改进摄像机控制 - 移除人类士兵数据资产文件,重构为建筑放置系统 - 在CharacterData中添加productionInterval和buildingCost字段用于建筑生产 - 实现CameraFollow脚本的完整重写,支持键盘WASD拖动、鼠标拖动、触摸拖动 - 添加摄像机缩放功能,支持上下键和触摸双指缩放 - 更新Projecttile.cs以同时处理单位和建筑目标的伤害检测 - 修改SummonCardButton从法力值召唤改为金币建筑放置模式 - 在UnitBase.cs中更新攻击逻辑以支持对建筑造成伤害 - 升级WorldHealthBar以显示建筑生产进度和更好的缩放补偿 - 修复MainCharacterDebugMovement移除键盘移动输入冲突 - 更新包管理器中的codely.bridge版本从1.0.80到1.0.81 ```
This commit is contained in:
1 parent
fb56cd7ede
commit
769aea30f3
55 files changed
+9328
-90
No files matched your search
@@ -0,0 +1,242 @@
|
||||
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 = currentCharacterData != null ? currentCharacterData.buildingCost : 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;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user