From 8722a9920c1f6119bf6e769cba270e63097f8e25 Mon Sep 17 00:00:00 2001
From: chai <215380520@qq.com>
Date: Thu, 23 May 2024 10:08:29 +0800
Subject: + astar project
---
.../Scenes/OldExamples/Example18_RTS/RTSUnit.cs | 278 +++++++++++++++++++++
1 file changed, 278 insertions(+)
create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/RTSUnit.cs
(limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/RTSUnit.cs')
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/RTSUnit.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/RTSUnit.cs
new file mode 100644
index 0000000..b1e0b9c
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/RTSUnit.cs
@@ -0,0 +1,278 @@
+using UnityEngine;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine.Profiling;
+
+namespace Pathfinding.Examples.RTS {
+ using Pathfinding;
+ using Pathfinding.RVO;
+ using Pathfinding.Util;
+
+ [HelpURL("https://arongranberg.com/astar/documentation/stable/rtsunit.html")]
+ public class RTSUnit : VersionedMonoBehaviour {
+ public GameObject selectionIndicator;
+ public GameObject deathEffect;
+ public int team;
+ public float detectionRange;
+
+ public float maxHealth;
+
+ public enum Type {
+ Infantry,
+ Heavy,
+ Worker,
+ Harvester,
+
+ HarvesterDropoff = 100,
+ HarvesterDropoffQueue,
+ ResourceCrystal = 200,
+ }
+
+ public Type type;
+ [System.NonSerialized]
+ public float health;
+ IAstarAI ai;
+ RVOController rvo;
+ MovementMode movementMode;
+ Vector3 lastDestination;
+ RTSUnit attackTarget;
+ RTSWeapon weapon;
+ float lastSeenAttackTarget = float.NegativeInfinity;
+ bool reachedDestination;
+ public int storedCrystals;
+ public RTSUnit reservedBy;
+ public bool locked;
+ new Transform transform;
+
+ /// Position at the start of the current frame
+ protected Vector3 position;
+
+ public System.Action onMakeActiveUnit;
+
+ public RTSPlayer owner {
+ get {
+ return RTSManager.instance.GetPlayer(team);
+ }
+ }
+
+ public bool selectionIndicatorEnabled {
+ get {
+ if (selectionIndicator == null) return false;
+ return selectionIndicator.activeSelf;
+ }
+ set {
+ if (selectionIndicator != null) selectionIndicator.SetActive(value);
+ }
+ }
+
+ public RTSHarvestableResource resource {
+ get {
+ return GetComponent();
+ }
+ }
+
+ public float radius {
+ get {
+ return rvo != null ? rvo.radius : 1f;
+ }
+ }
+
+ bool mSelected;
+ public bool selected {
+ get {
+ return mSelected;
+ }
+ set {
+ mSelected = value;
+ selectionIndicatorEnabled = value;
+ if (value) {
+ RTSManager.instance.units.OnSelected(this);
+ } else {
+ RTSManager.instance.units.OnDeselected(this);
+ }
+ }
+ }
+
+ public void OnMakeActiveUnit (bool active) {
+ if (onMakeActiveUnit != null) onMakeActiveUnit(active);
+ }
+
+ public void SetDestination (Vector3 destination, MovementMode mode) {
+ if (ai != null && this) {
+ reachedDestination = false;
+ movementMode = mode;
+ ai.destination = lastDestination = destination;
+ (ai as AIBase).rvoDensityBehavior.ClearDestinationReached();
+ ai.SearchPath();
+ if (mode == MovementMode.Move) {
+ attackTarget = null;
+ }
+ }
+ }
+
+ protected override void Awake () {
+ base.Awake();
+ transform = (this as MonoBehaviour).transform;
+ ai = GetComponent();
+ rvo = GetComponent();
+ weapon = GetComponent();
+ }
+
+ static System.Action OnUpdateDelegate;
+ void OnEnable () {
+ if (OnUpdateDelegate == null) OnUpdateDelegate = OnUpdate;
+ RTSManager.instance.units.AddUnit(this);
+ selected = false;
+ health = maxHealth;
+ movementMode = MovementMode.AttackMove;
+ reachedDestination = true;
+ if (ai != null) lastDestination = ai.destination;
+ BatchedEvents.Add(this, BatchedEvents.Event.Update, OnUpdateDelegate);
+ }
+
+ void OnDisable () {
+ BatchedEvents.Remove(this);
+ if (RTSManager.instance != null) RTSManager.instance.units.RemoveUnit(this);
+ }
+
+ static void OnUpdate (RTSUnit[] units, int count) {
+ // Get some lists and arrays from an object pool
+ List[] unitsByOwner = ArrayPool >.ClaimWithExactLength(RTSManager.instance.PlayerCount);
+ for (int i = 0; i < unitsByOwner.Length; i++) {
+ unitsByOwner[i] = ListPool.Claim();
+ }
+ for (int i = 0; i < count; i++) {
+ units[i].position = units[i].transform.position;
+ unitsByOwner[units[i].owner.index].Add(units[i]);
+ }
+ for (int i = 0; i < count; i++) {
+ units[i].OnUpdate(unitsByOwner);
+ }
+
+ // Release allocated lists back to a pool
+ for (int i = 0; i < unitsByOwner.Length; i++) {
+ ListPool.Release(ref unitsByOwner[i]);
+ }
+ ArrayPool >.Release(ref unitsByOwner, true);
+ }
+
+ // Update is called once per frame
+ protected virtual void OnUpdate (List[] unitsByOwner) {
+ if (ai == null) {
+ // Stationary unit
+
+ if (weapon != null) {
+ float minDist = detectionRange*detectionRange;
+ for (int player = 0; player < unitsByOwner.Length; player++) {
+ if (!owner.IsHostile(RTSManager.instance.GetPlayer(player))) continue;
+
+ for (int i = 0; i < unitsByOwner[player].Count; i++) {
+ var unit = unitsByOwner[player][i];
+ var dist = (unit.position - position).sqrMagnitude;
+ if (dist < minDist) {
+ attackTarget = unit;
+ minDist = dist;
+ }
+ }
+ }
+
+ if (attackTarget != null) {
+ if (!weapon.InRangeOf(attackTarget.position)) {
+ attackTarget = null;
+ } else {
+ if (weapon.Aim(attackTarget)) {
+ weapon.Attack(attackTarget);
+ }
+ }
+ }
+ }
+
+ if (attackTarget != null) {
+ lastSeenAttackTarget = Time.time;
+ }
+ } else {
+ rvo.locked = false | locked;
+
+ // this.reachedDestination will be true once the AI has reached its destination
+ // and it will stay true until the next time SetDestination is called.
+ reachedDestination |= (ai as AIBase).rvoDensityBehavior.reachedDestination;
+
+ if (weapon != null) {
+ bool canAttack = movementMode == MovementMode.AttackMove;
+ // This takes into account path calculations as well as if the AI stops far away from the destination due to being part of a large group
+ canAttack |= reachedDestination && movementMode == MovementMode.Move;
+
+ if (canAttack) {
+ float minDist = detectionRange*detectionRange;
+
+ Profiler.BeginSample("Distance");
+ var pos = position;
+ for (int player = 0; player < unitsByOwner.Length; player++) {
+ if (!owner.IsHostile(RTSManager.instance.GetPlayer(player))) continue;
+
+ var enemies = unitsByOwner[player];
+ for (int i = 0; i < enemies.Count; i++) {
+ var enemy = enemies[i];
+ var dist = (enemy.position - pos).sqrMagnitude;
+ if (dist < minDist) {
+ attackTarget = enemy;
+ minDist = dist;
+ }
+ }
+ }
+ Profiler.EndSample();
+
+ float rangeFuzz = 1.1f;
+ if (attackTarget != null && (attackTarget.position - position).magnitude > detectionRange*rangeFuzz) {
+ attackTarget = null;
+ }
+
+ bool wantsToAttack = false;
+
+ if (attackTarget != null) {
+ if (!weapon.InRangeOf(attackTarget.position)) {
+ ai.destination = attackTarget.position;
+ } else {
+ wantsToAttack = true;
+ if (weapon.Aim(attackTarget)) {
+ weapon.Attack(attackTarget);
+ }
+ }
+ }
+
+ if (attackTarget != null) {
+ lastSeenAttackTarget = Time.time;
+ }
+
+ if (!weapon.canMoveWhileAttacking && (wantsToAttack || weapon.isAttacking)) {
+ rvo.locked = true;
+ }
+ }
+ }
+
+ // Move back to original destination in case we followed an enemy for some time
+ if (Time.time - lastSeenAttackTarget > 2) {
+ ai.destination = lastDestination;
+ }
+ }
+ }
+
+ public void Die () {
+ StartCoroutine(DieCoroutine());
+ }
+
+ IEnumerator DieCoroutine () {
+ yield return new WaitForEndOfFrame();
+ if (deathEffect != null) GameObject.Instantiate(deathEffect, transform.position, transform.rotation);
+ GameObject.Destroy(gameObject);
+ }
+
+ public void ApplyDamage (float damage) {
+ health = Mathf.Clamp(health - damage, 0, maxHealth);
+ if (health <= 0) {
+ Die();
+ }
+ }
+ }
+}
--
cgit v1.1-26-g67d0