CapersProject/Packages/com.arongranberg.astar/ExampleScenes~/Scenes/OldExamples/Example18_RTS/RTSUI.cs
2024-06-04 03:26:03 +09:00

250 lines
7.7 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using Pathfinding;
using System.Linq;
namespace Pathfinding.Examples.RTS {
[HelpURL("https://arongranberg.com/astar/documentation/stable/rtsui.html")]
public class RTSUI : MonoBehaviour {
public static RTSUI active;
public RectTransform selectionBox;
public GameObject menuRoot;
public GameObject menuItemPrefab;
public State state;
public Button clickFallback;
public GameObject buildingPreview;
public LayerMask groundMask;
public AudioClip click;
public AudioClip notEnoughResources;
public RTSWorldSpaceUI worldSpaceUI;
RTSUnitBuilder.BuildingItem buildingInfo;
int ignoreFrame = -1;
Menu activeMenu;
public enum State {
Normal,
PlacingBuilding,
Dragging
}
[System.Serializable]
public class MenuItem {
public Sprite icon;
public string label;
public string description;
}
// Use this for initialization
void Awake () {
active = this;
/*foreach (var btn in buildingMenuRoot.GetComponentsInChildren<RTSBuildingButton>()) {
btn.gameObject.GetComponent<Button>().onClick.AddListener(() => {
StartBuildingPlacement(btn);
});
}*/
}
public class Menu {
GameObject root;
GameObject itemPrefab;
public Menu (GameObject root, GameObject itemPrefab) {
this.root = root;
this.itemPrefab = itemPrefab;
}
public void Hide () {
if (root != null) {
for (int i = 0; i < root.transform.childCount; i++) {
GameObject.Destroy(root.transform.GetChild(i).gameObject);
}
root = null;
}
}
public void AddItem (MenuItem item, System.Action callback) {
var go = GameObject.Instantiate(itemPrefab) as GameObject;
go.transform.SetParent(root.transform);
go.GetComponent<Button>().onClick.AddListener(() => callback());
go.transform.Find("Image/Icon").GetComponent<Image>().sprite = item.icon;
go.transform.Find("Label").GetComponent<Text>().text = item.label;
go.transform.Find("Description").GetComponent<Text>().text = item.description;
}
}
public Menu ShowMenu () {
if (activeMenu != null) {
activeMenu.Hide();
}
activeMenu = new Menu(menuRoot, menuItemPrefab);
return activeMenu;
}
Vector2 dragStart;
bool hasSelected = false;
// Update is called once per frame
void Update () {
HandleSelection();
HandleMovement();
HandleBuildingPlacement();
}
void HandleBuildingPlacement () {
var overUI = UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject();
if (state == State.PlacingBuilding) {
if (Input.GetKeyDown(KeyCode.Mouse1) || Input.GetKeyDown(KeyCode.Escape)) {
RTSManager.instance.audioManager.Play(notEnoughResources);
AbortBuildingPlacement();
}
buildingPreview.transform.position = RaycastScreenPoint(Input.mousePosition, groundMask).point;
// Ignore the first frame as that will also be a key down event
if (!overUI && Input.GetKeyDown(KeyCode.Mouse0) && Time.frameCount != ignoreFrame) {
if (RTSBuildingManager.IsValidBuildingPlacement(buildingPreview)) {
if (RTSManager.instance.GetPlayer(1).resources.GetResource(RTSUnit.Type.ResourceCrystal) < buildingInfo.cost) {
RTSManager.instance.audioManager.Play(notEnoughResources);
Debug.LogError("Not enouch resources");
} else {
RTSManager.instance.audioManager.Play(click);
RTSManager.instance.GetPlayer(1).resources.AddResource(RTSUnit.Type.ResourceCrystal, -buildingInfo.cost);
GameObject.Instantiate(buildingInfo.prefab, buildingPreview.transform.position, buildingPreview.transform.rotation);
}
GameObject.Destroy(buildingPreview);
state = State.Normal;
} else {
// Building placement failed
}
}
}
}
public void StartBuildingPlacement (RTSUnitBuilder.BuildingItem buildingInfo) {
if (state == State.PlacingBuilding) {
GameObject.Destroy(buildingPreview);
state = State.Normal;
}
if (RTSManager.instance.GetPlayer(1).resources.GetResource(RTSUnit.Type.ResourceCrystal) < buildingInfo.cost) {
Debug.LogError("Not enouch resources");
RTSManager.instance.audioManager.Play(notEnoughResources);
return;
}
this.buildingInfo = buildingInfo;
buildingPreview = GameObject.Instantiate(buildingInfo.prefab) as GameObject;
ignoreFrame = Time.frameCount;
state = State.PlacingBuilding;
// Disable all navmesh cuts and colliders on the preview
foreach (var cut in buildingPreview.GetComponentsInChildren<NavmeshCut>()) {
cut.enabled = false;
}
foreach (var coll in buildingPreview.GetComponentsInChildren<Collider>()) {
coll.enabled = false;
}
}
void AbortBuildingPlacement () {
if (buildingPreview != null) {
GameObject.Destroy(buildingPreview);
state = State.Normal;
}
}
void HandleMovement () {
if (state == State.Normal && Input.GetKeyDown(KeyCode.Mouse1)) {
RTSManager.instance.audioManager.Play(click);
RTSManager.instance.units.MoveGroupTo(RTSManager.instance.units.selectedUnits, RaycastScreenPoint(Input.mousePosition, groundMask).point, true, Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.A) ? MovementMode.AttackMove : MovementMode.Move);
}
}
void HandleSelection () {
var overUI = UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject();
if (state != State.Normal && state != State.Dragging) return;
if (!overUI && Input.GetKeyDown(KeyCode.Mouse0)) {
dragStart = Input.mousePosition;
state = State.Dragging;
hasSelected = false;
}
if (state == State.Dragging) {
Vector2 dragEnd = Input.mousePosition;
var mn = Vector2.Min(dragStart, dragEnd);
var mx = Vector2.Max(dragStart, dragEnd);
var rect = Rect.MinMaxRect(mn.x, mn.y, mx.x, mx.y);
bool isSelecting = (dragEnd - dragStart).magnitude > 5;
hasSelected |= isSelecting;
selectionBox.gameObject.SetActive(isSelecting);
if (isSelecting) {
selectionBox.offsetMin = Vector2.Min(dragStart, dragEnd);
selectionBox.offsetMax = Vector2.Max(dragStart, dragEnd);
}
if (!Input.GetKey(KeyCode.Mouse0)) {
state = State.Normal;
selectionBox.gameObject.SetActive(false);
if (isSelecting) {
RTSManager.instance.units.SetSelection(unit => {
var screenPos = RTSManager.instance.units.cam.WorldToScreenPoint(unit.transform.position);
return rect.Contains(screenPos);
});
} else {
// Clicking
var hit = RaycastScreenPoint(dragEnd, -1);
var p = hit.point;
float clickFuzzDistance = 0.1f;
float minDist = 0;
RTSUnit minUnit = hit.collider != null? hit.collider.gameObject.GetComponentInParent<RTSUnit>() : null;
if (minUnit == null) {
foreach (var unit in RTSManager.instance.units.units) {
var dir = unit.transform.position - p;
dir.y = 0;
var dist = dir.magnitude - unit.radius - clickFuzzDistance;
if (dist < minDist) {
minDist = dist;
minUnit = unit;
}
}
}
RTSManager.instance.units.SetSelection(u => u == minUnit);
}
} else if (hasSelected) {
foreach (var unit in RTSManager.instance.units.units) {
var screenPos = RTSManager.instance.units.cam.WorldToScreenPoint(unit.transform.position);
unit.selectionIndicatorEnabled = rect.Contains(screenPos);
}
}
}
}
RaycastHit RaycastScreenPoint (Vector2 mousePosition, LayerMask mask) {
var ray = RTSManager.instance.units.cam.ScreenPointToRay(mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, float.PositiveInfinity, mask)) {
Debug.DrawRay(hit.point, Vector3.up, Color.red, 2);
return hit;
} else {
throw new System.Exception("Mouse raycast did not hit anything");
}
}
}
}