override public void Execute() { directionChangeTimer -= Time.deltaTime; if (directionChangeTimer <= 0.0f) { fleeVelocity = StaticMovementAlgorithms.KinematicWander(selfBody, SPEED, movementVariance, Owner.transform.forward); directionChangeTimer = Random.Range(MIN_TIME, MAX_TIME); } Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle"), selfColliders); //if we're in range of the thing we want to flee stop wandering if (Vector3.Distance(Owner.transform.position, target.transform.position) < FLEE_RADIUS) { Debug.Log(Vector3.Distance(Owner.transform.position, target.transform.position)); fleeVelocity = StaticMovementAlgorithms.KinematicFlee(selfBody, target.transform.position, SPEED); } if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.6f * fleeVelocity + 0.4f * avoidanceVelocity; } else { targetVelocity = fleeVelocity; } targetVelocity.y = 0.0f; targetVelocity = targetVelocity.normalized * SPEED; }
override public void Execute() { directionChangeTimer -= Time.deltaTime; if (directionChangeTimer <= 0.0f) { fleeVelocity = StaticMovementAlgorithms.KinematicWander(selfBody, SPEED, movementVariance, Owner.transform.forward); directionChangeTimer = Random.Range(MIN_TIME, MAX_TIME); } Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle"), selfColliders); //if we're in range of the thing we want to flee stop wandering float closestPosition = fleeGroup.Select(x => Mathf.Min(Vector3.Distance(Owner.transform.position, x.transform.position))).Aggregate((x, y) => Mathf.Min(x, y)); if (closestPosition < FLEE_RADIUS) { //Debug.Log(Vector3.Distance(Owner.transform.position, target.transform.position)); fleeVelocity = StaticMovementAlgorithms.KinematicFleeMultiple(this.Owner.GetComponent <Rigidbody>(), fleeGroup.Select(x => x.transform.position).ToList <Vector3>(), SPEED, 1.0f).normalized; } if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.6f * fleeVelocity + 0.4f * avoidanceVelocity; } else { targetVelocity = fleeVelocity; } targetVelocity.y = 0.0f; targetVelocity = targetVelocity.normalized * SPEED; }
void Update() { Vector3 newVelocity = StaticMovementAlgorithms.KinematicAvoidObstacles(rigidbody, obstacles, 10, radius, speed); newVelocity = StaticMovementAlgorithms.GetInterpolatedVelocity(rigidbody, newVelocity, 1); rigidbody.velocity = newVelocity; rigidbody.rotation = StaticMovementAlgorithms.GetOrientation(newVelocity, Vector3.forward); }
override public void Execute() { Rigidbody body = Owner.GetComponent <Rigidbody>(); directionChangeTimer -= Time.deltaTime; if (directionChangeTimer <= 0.0f) { wanderVelocity = StaticMovementAlgorithms.KinematicWander(body, SPEED, movementVariance, Owner.transform.forward); directionChangeTimer = Random.Range(MIN_TIME, MAX_TIME); } targetVelocity = wanderVelocity; targetVelocity.y = 0.0f; }
override public void Execute() { flockTimer -= Time.deltaTime; if (flockTimer > 0.0f) { return; } Rigidbody selfBody = this.Owner.GetComponent <Rigidbody>(); Vector3 velocityMatching = target.GetComponent <Rigidbody>().velocity; Vector3 separation = StaticMovementAlgorithms.KinematicFleeMultiple(this.Owner.GetComponent <Rigidbody>(), group.Select(x => x.transform.position).ToList <Vector3>(), SPEED, 0.2f); Vector3 centerOfMass = new Vector3(); foreach (Enemy member in group) { centerOfMass += member.transform.position; } centerOfMass = centerOfMass / group.Count; Vector3 displace = centerOfMass - selfBody.position; Vector3 cohesion = displace.magnitude * StaticMovementAlgorithms.KinematicSeek(this.Owner.GetComponent <Rigidbody>(), centerOfMass, SPEED).normalized; flockingVelocity = velocityMatching + separation + cohesion; if (flockingVelocity.sqrMagnitude > SPEED * SPEED) { flockingVelocity = flockingVelocity.normalized * SPEED; } //Vector3 avoidanceVelocity = StaticMovementAlgorithms.KinematicAvoidObstacles(Owner.GetComponent<Rigidbody>(), LayerMask.GetMask("Obstacle"), 5.0f, 1.0f, SPEED); Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle"), selfColliders); avoidanceVelocity.y = 0; if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.4f * avoidanceVelocity + 0.6f * flockingVelocity; } else { targetVelocity = flockingVelocity; } targetVelocity = targetVelocity.normalized * SPEED; flockTimer = FLOCK_PERIOD; }
override public void Execute() { targetVelocity = StaticMovementAlgorithms.KinematicArrive(selfBody, nextNode.transform.position, ELECTRIC_SPEED, ARRIVE_RADIUS); /* * if (Controls.getDirection() != Vector3.zero) * { * Debug.Log("Controller decided"); * Debug.DrawLine(nextNode.transform.position, nextNode.getNextNavPoint(Controls.getDirection()).transform.position); * } * else * { * Debug.Log("Velocity Decided"); * Debug.DrawLine(nextNode.transform.position, nextNode.getNextNavPoint(selfBody.velocity).transform.position); * } */ if (targetVelocity == Vector3.zero) { if (nextNode.isEndpoint) { Owner.ActionFsm.ChangeState(new IdleState(Owner, Owner.ActionFsm)); } else { ElectricNavpoint nextNodeCandidate; Vector3 input_direction = Controls.getDirection(); if (input_direction != Vector3.zero && Owner.stamina > 0.0f) { nextNodeCandidate = nextNode.getNextNavPoint(input_direction, previousNode); if (nextNodeCandidate == previousNode) { nextNodeCandidate = nextNode.getNextNavPoint(selfBody.velocity, previousNode); } } else { nextNodeCandidate = nextNode.getNextNavPoint(selfBody.velocity, previousNode); } previousNode = nextNode; nextNode = nextNodeCandidate; //Now we trigger any associated devices previousNode.Trigger(); } } Owner.UseStamina(STAMINA_COST_PER_SECOND * Time.deltaTime); }
override public void Execute() { Vector3 arriveVelocity = StaticMovementAlgorithms.KinematicArrive(selfBody, target.transform.position, SPEED, ARRIVE_RADIUS); Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle"), selfColliders); if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.6f * arriveVelocity + 0.4f * avoidanceVelocity; } else { targetVelocity = arriveVelocity; } targetVelocity.y = 0.0f; targetVelocity = targetVelocity.normalized * SPEED; }
override public void Execute() { targetVelocity = StaticMovementAlgorithms.KinematicArrive(selfBody, nextNode.transform.position, ELECTRIC_SPEED, ARRIVE_RADIUS); /* * if (Controls.getDirection() != Vector3.zero) * { * Debug.Log("Controller decided"); * Debug.DrawLine(nextNode.transform.position, nextNode.getNextNavPoint(Controls.getDirection()).transform.position); * } * else * { * Debug.Log("Velocity Decided"); * Debug.DrawLine(nextNode.transform.position, nextNode.getNextNavPoint(selfBody.velocity).transform.position); * } */ if (targetVelocity == Vector3.zero) { if (nextNode.isEndpoint) { Owner.ActionFsm.ChangeState(new IdleState(Owner, Owner.ActionFsm)); } else { ElectricNavpoint nextNodeCandidate; Vector3 input_direction = Controls.getDirection(); if (input_direction != Vector3.zero) { nextNodeCandidate = nextNode.getNextNavPoint(input_direction); if (nextNodeCandidate == previousNode) { nextNodeCandidate = nextNode.getNextNavPoint(selfBody.velocity); } } else { nextNodeCandidate = nextNode.getNextNavPoint(selfBody.velocity); } previousNode = nextNode; nextNode = nextNodeCandidate; } } }
override public void Execute() { //Initialization of basic parameters Rigidbody body = Owner.GetComponent <Rigidbody>(); directionChangeTimer -= Time.deltaTime; if (directionChangeTimer <= 0.0f) { wanderVelocity = StaticMovementAlgorithms.KinematicWander(body, SPEED, movementVariance, Owner.transform.forward); directionChangeTimer = Random.Range(MIN_TIME, MAX_TIME); } //Calculates the velocity for not colliding into things Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle")); //StaticMovementAlgorithms.KinematicAvoidObstacles(body, LayerMask.GetMask("Obstacle"), 5.0f, 1.0f, SPEED); avoidanceVelocity.y = 0; //Vector3 targetVelocity = new Vector3(); if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.6f * wanderVelocity + 0.4f * avoidanceVelocity; targetVelocity = targetVelocity.normalized * SPEED; wanderVelocity = targetVelocity;//avoidanceVelocity; } else { targetVelocity = wanderVelocity; } targetVelocity.y = 0.0f; targetVelocity = targetVelocity.normalized * SPEED; //Debug.Log("wander " + wanderVelocity); //Debug.Log("avoid " + avoidanceVelocity); }
public static Vector3 AvoidCollisions(GameObject self, float detectRadius, float avoidMargin, float speed, int mask = Physics.DefaultRaycastLayers, Collider[] selfColliders = null) { Vector3 results = new Vector3(); Rigidbody selfBody = self.GetComponent <Rigidbody>(); // Cannot operate if we have no sense of self movement if (selfBody == null) { return(results); } if (selfColliders == null) { selfColliders = self.GetComponentsInChildren <Collider>(); } Collider[] nearbyColliders = Physics.OverlapSphere(selfBody.position, detectRadius, mask); foreach (Collider col in nearbyColliders) { // Ignore colliders that belong to self bool skipSelf = false; foreach (Collider c in selfColliders) { if (col == c) { skipSelf = true; break; } } if (skipSelf) { continue; } // Ignore terrain (probably unneeded) if (col.gameObject.tag.Equals("Terrain")) { continue; } // Moving obstacles if (col.gameObject.GetComponent <Rigidbody>() != null) { // self = A // other = B Rigidbody other = col.gameObject.GetComponent <Rigidbody>(); Vector3 dv = other.velocity - selfBody.velocity; Vector3 dp = other.position - selfBody.position; float closestTime = -(Vector3.Dot(dv, dp) / dv.sqrMagnitude); Vector3 closestA = selfBody.position + selfBody.velocity * closestTime; Vector3 closestB = other.position + other.velocity * closestTime; Vector3 distance = closestB - closestA; if (distance.sqrMagnitude < avoidMargin * avoidMargin) { Debug.Log("Avoiding " + other.gameObject.name); results += 0.5f * (avoidMargin / distance.magnitude) * StaticMovementAlgorithms.KinematicFlee(selfBody, closestB, speed); } continue; } } // Not really worried about static obstacles if we're not moving if (selfBody.velocity.sqrMagnitude > 0.0001) { RaycastHit[] hitInfos = selfBody.SweepTestAll(selfBody.velocity.normalized, detectRadius); if (hitInfos.Length > 0) { foreach (RaycastHit hitInfo in hitInfos) { if ((mask & (1 << hitInfo.collider.gameObject.layer)) > 0) { Vector3 distance = hitInfo.point - selfBody.position; if (distance.sqrMagnitude < avoidMargin * avoidMargin) { Debug.Log("Avoiding " + hitInfo.collider.gameObject.name); Vector3 dest = hitInfo.point + hitInfo.normal * 2.0f * avoidMargin; results += (avoidMargin / distance.magnitude) * StaticMovementAlgorithms.KinematicSeek(selfBody, dest, 1.0f); } break; } } } } return(results.normalized * speed); }
override public void Execute() { Vector3 targetDest; //if(Path.Count - PathIndex >= 3) //{ // targetDest = 0.7f * Path[PathIndex].transform.position // + 0.2f * Path[PathIndex + 1].transform.position // + 0.1f * Path[PathIndex + 2].transform.position; //} //else if (Path.Count - PathIndex >= 2) //{ // targetDest = 0.8f * Path[PathIndex].transform.position // + 0.2f * Path[PathIndex + 1].transform.position; //} //else if (Path.Count - PathIndex >= 1) //{ // targetDest = Path[PathIndex].transform.position; //} //else //{ // targetDest = currentTarget.transform.position; //} targetDest = currentTarget.transform.position; Debug.DrawLine(targetDest, targetDest + Vector3.up * 1.0f, Color.red); Vector3 arriveVelocity = StaticMovementAlgorithms.KinematicArrive(selfBody, targetDest, 1.0f, ARRIVE_RADIUS); //Vector3 avoidanceVelocity = // CollisionPrediction.AvoidCollisionsHelper(Owner.gameObject, // AVOID_DETECTION_RADIUS, // 1.5f * Owner.BodyBounds.extents.magnitude, // LayerMask.GetMask("Obstacle"), // selfColliders); Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisions(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, SPEED, LayerMask.GetMask("Obstacle"), selfColliders); avoidanceVelocity.y = 0.0f; if (avoidanceVelocity != Vector3.zero) { targetVelocity = 0.6f * arriveVelocity + 0.4f * avoidanceVelocity; } else { targetVelocity = arriveVelocity; } //targetVelocity.y = 0.0f; targetVelocity = targetVelocity.normalized * Owner.speed; //targetVelocity.y = 0.0f; //float avoidanceSpeed = avoidanceVelocity.magnitude; //avoidanceVelocity.y = 0.0f; //avoidanceVelocity = avoidanceVelocity.normalized * avoidanceSpeed; //targetVelocity = arriveVelocity + avoidanceVelocity; //if (targetVelocity.sqrMagnitude > 1.0f) //{ // targetVelocity = targetVelocity.normalized; //} //targetVelocity *= SPEED; //Debug.Log("chosen target velocity: " + targetVelocity); if (Vector3.Distance(Owner.transform.position, currentTarget.transform.position) < ARRIVE_RADIUS) { //invariant that the path has a unique set of targets PathIndex++; if (PathIndex < Path.Count) { currentTarget = Path[PathIndex]; } } }
override public void Execute() { Vector3 selfPos = Owner.transform.position; Vector3 targetPos = target.transform.position; if (Vector3.Distance(targetPos, selfPos) < ARRIVE_RADIUS) { targetVelocity = Vector3.zero; return; } Vector3 arrivePoint; if (path == null) { if (Mathf.Abs(selfPos.y - targetPos.y) < 0.1f && !Physics.Linecast(selfPos, targetPos, LayerMask.GetMask("Obstacle"))) { // If we're on the same y-plane, and the target is visible // Just target the enemy arrivePoint = targetPos; targetLastPosition = targetPos; } else { // Otherwise, find a path. GeneratePathToTarget(); arrivePoint = pathPointTarget; } } else { // If the target has moved significantly, create a new path. if (Vector3.Distance(targetLastPosition, targetPos) > REPATH_THRESHOLD) { if (repathWait <= 0) { GeneratePathToTarget(); repathWait = Random.Range(0, REPATH_WAIT_MAX); } else { repathWait -= 1; } } // Otherwise, keep following our current path. else { // If we've reached our path way point, get the next if it exists if (Vector3.Distance(selfPos, pathPointTarget) < ARRIVE_RADIUS) { pathIndex++; if (pathIndex < path.Count) { pathPointTarget = path[pathIndex]; } else { path = null; pathPointTarget = targetPos; } } } arrivePoint = pathPointTarget; } Debug.DrawLine(arrivePoint, arrivePoint + Vector3.up * 1.0f, Color.red); Vector3 arriveVelocity = StaticMovementAlgorithms.KinematicArrive(selfBody, arrivePoint, 1.0f, ARRIVE_RADIUS); Vector3 avoidanceVelocity = CollisionPrediction.AvoidCollisionsHelper(Owner.gameObject, AVOID_DETECTION_RADIUS, AVOID_MARGIN, LayerMask.GetMask("Obstacle"), selfColliders); avoidanceVelocity.y = 0.0f; if (avoidanceVelocity != Vector3.zero) { targetVelocity = targetVelocity + avoidanceVelocity * Owner.speed; if (targetVelocity.sqrMagnitude > Owner.speed * Owner.speed) { targetVelocity = targetVelocity.normalized * Owner.speed; } } else { targetVelocity = Vector3.Lerp(targetVelocity, arriveVelocity * Owner.speed, 0.2f); } if (Owner.gameObject == UnityEditor.Selection.activeGameObject) { Debug.Log(Owner.name + " has target vel " + targetVelocity + " arrive vel: " + arriveVelocity + " avoid vel : " + avoidanceVelocity); } }
public static Vector3 AvoidCollisionsHelper(GameObject self, float detectRadius, float avoidMargin, int mask = Physics.DefaultRaycastLayers, Collider[] selfColliders = null) { Vector3 results = new Vector3(); Rigidbody selfBody = self.GetComponent <Rigidbody>(); // Cannot operate if we have no sense of self movement if (selfBody == null) { return(results); } Vector3 currentDirection = selfBody.velocity.normalized; if (selfColliders == null) { selfColliders = self.GetComponentsInChildren <Collider>(); } Collider[] nearbyColliders = Physics.OverlapSphere(selfBody.position, detectRadius, mask); foreach (Collider col in nearbyColliders) { // Ignore colliders that belong to self bool skipSelf = false; foreach (Collider c in selfColliders) { if (col == c) { skipSelf = true; break; } } if (skipSelf) { continue; } // Moving obstacles if (col.gameObject.GetComponent <Rigidbody>() != null) { // self = A // other = B Rigidbody other = col.gameObject.GetComponent <Rigidbody>(); if (other.velocity.sqrMagnitude < 0.01f) { continue; } Vector3 dv = other.velocity - selfBody.velocity; Vector3 dp = other.position - selfBody.position; float closestTime = -(Vector3.Dot(dv, dp) / dv.sqrMagnitude); Vector3 closestA = selfBody.position + selfBody.velocity * closestTime; Vector3 closestB = other.position + other.velocity * closestTime; Vector3 distance = closestB - closestA; if (distance.sqrMagnitude < avoidMargin * avoidMargin) { //Debug.Log("Avoiding " + other.gameObject.name); Vector3 deltaV = StaticMovementAlgorithms.KinematicFlee(selfBody, closestB, 1.0f) - currentDirection; deltaV.Normalize(); float proportionalToDist = (1.0f - distance.magnitude / avoidMargin); deltaV *= proportionalToDist; // Scale by distance results += deltaV; } continue; } } // Not really worried about static obstacles if we're not moving if (selfBody.velocity.sqrMagnitude > 0.0001) { RaycastHit[] hitInfos = selfBody.SweepTestAll(selfBody.velocity.normalized, detectRadius); if (hitInfos.Length > 0) { foreach (RaycastHit hitInfo in hitInfos) { if ((mask & (1 << hitInfo.collider.gameObject.layer)) > 0) { Vector3 displacement = hitInfo.point - selfBody.position; if (displacement.sqrMagnitude < detectRadius * detectRadius) // Within Avoid Margin { //Debug.Log("Avoiding " + hitInfo.collider.gameObject.name); //Vector3 avoidPoint = hitInfo.point + hitInfo.normal * avoidMargin; //Vector3 targetV = StaticMovementAlgorithms.KinematicSeek(selfBody, avoidPoint, 1.0f); //Vector3 deltaV = (targetV - currentDirection); //if(deltaV.magnitude > 1.0f) //{ // deltaV.Normalize(); //} Vector3 up = Vector3.Cross(currentDirection, hitInfo.normal); Vector3 avoidDirection = Vector3.Cross(up, currentDirection).normalized; avoidDirection.y = 0.0f; Vector3 deltaV = avoidDirection.normalized; float proportionalToDist = (1.0f - displacement.magnitude / (detectRadius)); deltaV *= proportionalToDist; results += deltaV; } break; } } } } return(results); }