diff options
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/BTNode.cs')
-rw-r--r-- | Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/BTNode.cs | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/BTNode.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/BTNode.cs new file mode 100644 index 0000000..68d3c00 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/OldExamples/Example18_RTS/BTNode.cs @@ -0,0 +1,420 @@ +using System; +using UnityEngine; +using System.Linq; +using Pathfinding.RVO; + +namespace Pathfinding.Examples.RTS { + public enum Status { + Invalid, + Failure, + Success, + Running + }; + + public class BTContext { + public RTSUnit unit; + public Transform transform; + public Animator animator; + } + + /// <summary>Implements a simple behavior tree. This is the base class for all nodes in the tree.</summary> + public abstract class BTNode { + protected Status lastStatus; + public Status Tick (BTContext ctx) { + if (lastStatus == Status.Invalid) OnInit(ctx); + lastStatus = DoTick(ctx); + if (lastStatus == Status.Invalid) throw new System.Exception(); + return lastStatus; + } + + public void Terminate (BTContext ctx) { + OnTerminate(ctx); + lastStatus = Status.Invalid; + } + + protected virtual void OnInit (BTContext ctx) { + } + + protected virtual void OnTerminate (BTContext ctx) { + } + + protected abstract Status DoTick(BTContext ctx); + } + + public class BTTransparent : BTNode { + public BTNode child; + protected override void OnTerminate (BTContext ctx) { + child.Terminate(ctx); + } + + protected override Status DoTick (BTContext ctx) { + return child.Tick(ctx); + } + } + + public class Once : BTNode { + public BTNode child; + + public Once (BTNode child) { this.child = child; } + + protected override void OnTerminate (BTContext ctx) { + if (lastStatus == Status.Running) child.Terminate(ctx); + } + + protected override Status DoTick (BTContext ctx) { + if (lastStatus == Status.Success) return Status.Success; + var s = child.Tick(ctx); + if (s == Status.Success) { + child.Terminate(ctx); + } + return s; + } + } + + public class SimpleAction : BTNode { + public System.Action<BTContext> action; + public SimpleAction (System.Action<BTContext> action) { this.action = action; } + + protected override Status DoTick (BTContext ctx) { + action(ctx); + return Status.Success; + } + } + + public class Condition : BTNode { + public System.Func<BTContext, bool> predicate; + public Condition (System.Func<BTContext, bool> predicate) { this.predicate = predicate; } + + protected override Status DoTick (BTContext ctx) { + return predicate(ctx) ? Status.Success : Status.Failure; + } + } + + public class BTSequence : BTNode { + public BTNode[] children; + int childIndex = -1; + + public BTSequence (BTNode[] children) { + this.children = children; + } + + protected override void OnInit (BTContext ctx) { + childIndex = 0; + } + + protected override void OnTerminate (BTContext ctx) { + for (int i = 0; i <= childIndex; i++) { + children[i].Terminate(ctx); + } + childIndex = -1; + } + + protected override Status DoTick (BTContext ctx) { + int i; + + for (i = 0; i < children.Length; i++) { + var s = children[i].Tick(ctx); + if (s != Status.Success) { + // Terminate all nodes that executed the last frame, but did not execute this frame + for (int j = i + 1; j <= childIndex; j++) children[j].Terminate(ctx); + childIndex = i; + return s; + } + } + childIndex = i - 1; + return Status.Success; + } + } + + public class BTSelector : BTNode { + public BTNode[] children; + int childIndex = -1; + + public BTSelector (BTNode[] children) { + this.children = children; + } + + protected override void OnInit (BTContext ctx) { + } + + protected override void OnTerminate (BTContext ctx) { + for (int i = 0; i <= childIndex; i++) { + children[i].Terminate(ctx); + } + childIndex = -1; + } + + protected override Status DoTick (BTContext ctx) { + int i; + + for (i = 0; i < children.Length; i++) { + var s = children[i].Tick(ctx); + if (s != Status.Failure) { + // Terminate all nodes that executed the last frame, but did not execute this frame + for (int j = i + 1; j <= childIndex; j++) children[j].Terminate(ctx); + + childIndex = i; + return s; + } + } + childIndex = i - 1; + return Status.Failure; + } + } + + class Binding<T> { + T val; + public System.Func<T> getter; + public System.Action<T> setter; + public T value { + get { + if (getter != null) return getter(); + return val; + } + set { + if (setter != null) setter(value); + val = value; + } + } + } + + public struct Value<T> { + T val; + Binding<T> binding; + public T value { + get { + if (binding != null) return binding.value; + return val; + } + set { + if (binding != null) binding.value = value; + val = value; + } + } + + public void Bind (ref Value<T> other) { + if (other.binding != null && binding == null) binding = other.binding; + else if (binding == null && other.binding != null) other.binding = binding; + else if (binding == null) binding = other.binding = new Binding<T>(); + else throw new System.Exception("Too complex binding"); + } + + public void Bind (System.Func<T> other) { + if (binding != null) throw new System.Exception("Already has a binding"); + binding = new Binding<T>(); + binding.getter = other; + binding.setter = _ => { + throw new System.InvalidOperationException("Trying to assign a value which has been bound as read-only (using a delegate)"); + }; + } + + public Value<T> Bound { + get { + var r = this; + if (binding == null) Bind(ref r); + return r; + } + } + + public Value (System.Func<T> getter) { + val = default(T); + binding = null; + Bind(getter); + } + + public static implicit operator Value<T>(System.Func<T> getter) { + var val = new Value<T>(); + + val.Bind(getter); + return val; + } + } + + public class BTMove : BTNode { + public Value<Vector3> destination; + + public BTMove (Value<Vector3> destination) { + this.destination = destination; + } + + protected override void OnInit (BTContext ctx) { + ctx.unit.SetDestination(destination.value, MovementMode.Move); + } + + protected override Status DoTick (BTContext ctx) { + var dest = destination.value; + + if ((Time.frameCount % 100) == 0) ctx.unit.SetDestination(dest, MovementMode.Move); + if (VectorMath.SqrDistanceXZ(ctx.transform.position, dest) < 0.5f * 0.5f) { + return Status.Success; + } else { + return Status.Running; + } + } + } + + public class FindClosestUnit : BTNode { + public Value<RTSUnit> target; + public bool reserve; + RTSUnit.Type type; + + public FindClosestUnit (RTSUnit.Type type) { + this.type = type; + } + + protected override void OnTerminate (BTContext ctx) { + if (reserve && target.value != null) { + if (target.value.reservedBy != ctx.unit) throw new System.Exception(); + target.value.reservedBy = null; + } + target.value = null; + } + + RTSUnit FindClosest (Vector3 point) { + var units = RTSManager.instance.units.units; + RTSUnit closest = null; + var dist = float.PositiveInfinity; + + for (int i = 0; i < units.Count; i++) { + var unit = units[i]; + if (unit.type != type || (reserve && unit.reservedBy != null)) { + continue; + } + if (unit.resource != null && !unit.resource.harvestable) { + continue; + } + + var d = (unit.transform.position - point).sqrMagnitude; + if (d < dist) { + dist = d; + closest = unit; + } + } + return closest; + } + + protected override Status DoTick (BTContext ctx) { + if (target.value != null) { + return Status.Success; + } + + target.value = FindClosest(ctx.transform.position); + if (target.value != null) { + if (reserve) target.value.reservedBy = ctx.unit; + return Status.Success; + } + return Status.Failure; + } + } + + static class Behaviors { + public static BTNode HarvestBehavior () { + var reserve = new FindClosestUnit(RTSUnit.Type.ResourceCrystal) { reserve = true }; + var dropoff = new FindClosestUnit(RTSUnit.Type.HarvesterDropoff) { reserve = true }; + var dropoffQueue = new FindClosestUnit(RTSUnit.Type.HarvesterDropoffQueue); + + return new BTSelector(new BTNode[] { + new HarvestMode() { + child = new BTSelector(new BTNode[] { + new BTSequence(new BTNode[] { + new Condition(ctx => ctx.unit.storedCrystals > 0), + new BTSequence(new BTNode[] { + dropoff, + new BTMove(new Value<Vector3>(() => dropoff.target.value.transform.position)), + new SimpleAction(ctx => { + ctx.unit.owner.resources.AddResource(RTSUnit.Type.ResourceCrystal, ctx.unit.storedCrystals); + ctx.unit.storedCrystals = 0; + }), + }) + //new Deposit(move1), + }), + new BTSequence(new BTNode[] { + new Condition(ctx => ctx.unit.storedCrystals == 0), + new BTSequence(new BTNode[] { + reserve, + new BTMove(new Value<Vector3>(() => reserve.target.value.transform.position)), + new Harvest { resource = new Value<RTSHarvestableResource>(() => reserve.target.value.resource), duration = 5 }, + }), + }) + }) + }, + new BTSequence(new BTNode[] { + dropoffQueue, + new BTMove(new Value<Vector3>(() => dropoffQueue.target.value.transform.position)), + }) + }); + } + } + + public class HarvestMode : BTTransparent { + protected override void OnTerminate (BTContext ctx) { + ctx.unit.GetComponent<RVOController>().layer = RVO.RVOLayer.Layer2; + base.OnTerminate(ctx); + } + + protected override Status DoTick (BTContext ctx) { + var s = base.DoTick(ctx); + + ctx.unit.GetComponent<RVOController>().layer = s == Status.Running ? RVO.RVOLayer.Layer3 : RVO.RVOLayer.Layer2; + return s; + } + } + + public class Harvest : BTNode { + public Value<RTSHarvestableResource> resource; + public float duration = 5; + float time; + + protected override void OnInit (BTContext ctx) { + ctx.animator.SetBool("harvesting", true); + + //ctx.unit.locked = true; + } + + protected override void OnTerminate (BTContext ctx) { + Debug.Log("Terminated harvesting"); + ctx.animator.SetBool("harvesting", false); + } + + protected override Status DoTick (BTContext ctx) { + time += Time.deltaTime; + if (time > duration) { + ctx.animator.SetBool("harvesting", false); + if (ctx.animator.GetCurrentAnimatorStateInfo(0).IsName("RTSHarvesterHarvesting") || ctx.animator.GetCurrentAnimatorStateInfo(0).IsName("RTSHarvesterHarvestingExit")) { + return Status.Running; + } else { + ctx.unit.storedCrystals += 50; + resource.value.value -= 50; + time = 0; + //ctx.unit.locked = false; + return Status.Success; + } + } else { + return Status.Running; + } + } + } + + public class BTHarvest { + /*RTSCommandMove moveToDepositPoint; + RTSCommandMove moveToHarvestPoint; + + void Deposit () { + + } + + public override void Tick () { + if (HasResources()) { + if (moveToDepositPoint.Tick() == Success) { + Deposit(); + } + } else { + var target = ReserveTarget(); + moveToHarvestPoint.target = target; + if (moveToHarvestPoint.Tick() == Success) { + Harvest(target); + } + } + }*/ + } +} |