вот скрипт.в нем надо вместо AstarPath и Seeker прикрутить SimplePath от Алекса Крига.
Синтаксис:
Используется javascript
@script AddComponentMenu("Shooter Engine/Enemy/Enemy AI")
var walkSpeed : float = 1.6;
var runSpeed : float = 3.0;
var attackRange : float = 50.0;
var shootRange : float = 30.0;
var shootDistStep : float = 5.0;
var shootTimeStep : float = 5.0;
var shootAngle : float = 4.0;
var dontComeCloserRange : float = 5.0;
var shootEnemies : boolean = true;
var moveTowardsEnemies : boolean = true;
var searchForEnemies : boolean = true;
var moveOnRange : float = 10.0;
var searchTimeMin : float = 15.0;
var searchTimeMax : float = 30.0;
var burstIntervalMin : float = 0.5;
var burstIntervalMax : float = 1.0;
var burstTimeMax : float = 0.3;
var waypointsGroupName : String = "Shared";
var pickNextWaypointDistance : float = 2.0;
var pickNextFoundPosDistance : float = 1.0;
var maxStop : float = 3.0;
var detectionSound : AudioClip[];
var detectionInterval : float = 10.0;
var oneTimeDetection : boolean = false;
var beforeShootSound : AudioClip[];
var beforeShootInterval : float = 10.0;
var searchSound : AudioClip[];
var searchInterval : float = 30.0;
var playerDeadSound : AudioClip[];
var playerDeadInterval : float = 10.0;
var lookFrom : Transform;
var lookFromLayerMask : LayerMask = -1; // CanSeeTarget layer mask
var gridProjectionMask : LayerMask = 0; // Usually layer of your navmeshes
var usePathfinding : boolean = true;
private var target : Transform;
private var currDistance : float;
private var controller : CharacterController;
private var headLookControl : HeadLookController;
private var aiWeapons : AIWeapons;
private var aimOffscreen : AimOffscreen;
private var command : String = "Stay";
private var foundPosition : Vector3;
private var points : Vector3[];
private var curpoint : int = 0;
private var canSearchAgain : boolean = true;
private var patrolPauseTime : float = 10.0;
private var startPathTimer : float = 0.2;
private var detectionTimer : float = -1.0;
private var shootTimer : float = -1.0;
private var beforeShootTimer : float = -1.0;
private var searchTimer : float = -1.0;
private var playerDeadTimer : float = -1.0;
private var wasDetected : boolean = false;
private var playing : boolean = false;
private var reloading : boolean = false;
private var vol : float;
// Make sure there is always a character controller
@script RequireComponent (CharacterController)
function Start () {
controller = GetComponent(CharacterController);
headLookControl = GetComponent(HeadLookController);
aiWeapons = GetComponent(AIWeapons);
aimOffscreen = GetComponentInChildren(AimOffscreen);
currDistance = shootRange;
vol = audio.volume;
foundPosition = transform.position;
command = "Stay";
Patrol ();
if (usePathfinding) {
yield WaitForSeconds (Random.value*0.2);
while (true) {
FindPoint (curpoint);
yield WaitForSeconds (0.2);
}
}
}
function Update () {
if (usePathfinding)
Debug.DrawLine (transform.position, foundPosition, Color.blue);
}
function PathComplete (newPoints : Vector3[]) {
canSearchAgain = true;
points = newPoints;
FindPoint (0);
command = "Walk";
}
function PathError () {
canSearchAgain = true;
}
function HasReachedTarget () : boolean {
return curpoint >= points.Length;
}
function FindPoint (cpoint : int) {
curpoint = cpoint;
if (points == null || points.Length == 0 || curpoint >= points.Length) {
foundPosition = transform.position;
Stop ();
return;
}
if (points.Length == 1) {
foundPosition = points[0];
command = "Walk";
return;
}
command = "Walk";
foundPosition = points[curpoint];
var p : Vector3 = foundPosition;
p.y = transform.position.y;
if (curpoint < points.Length - 1) {
if ((transform.position-p).sqrMagnitude < pickNextFoundPosDistance*pickNextFoundPosDistance) {
curpoint++;
FindPoint (curpoint);
}
} else {
if ((transform.position-p).sqrMagnitude < maxStop*maxStop) {
curpoint++;
FindPoint (curpoint);
}
}
}
function Stop () {
command = "Stay";
SendMessage("SetSpeed", 0.0, SendMessageOptions.DontRequireReceiver);
}
function FindPath (destination : Vector3) {
if (usePathfinding) {
seeker = GetComponent("Seeker");
var startProj = transform.position;
// var startProj = GridProjection(transform.position, 2.5);
var destinationProj = GridProjection(destination, 50);
if (Time.time > startPathTimer) {
seeker.StartPath(startProj, destinationProj);
startPathTimer = Time.time + 0.2;
}
}
// Move towards our target
if (command == "Walk")
MoveTowards(foundPosition);
else
MoveTowards(destination);
}
function Patrol () {
cm = GetComponent("CharacterMotor");
var curWayPoint = AutoWayPoint.FindClosest(transform.position, waypointsGroupName);
while (true) {
if (shootEnemies) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
}
if (FindClosest () != null)
target = FindClosest ().transform;
var waypointPosition = curWayPoint.transform.position;
patrolPauseTime = curWayPoint.pauseTime;
// Are we close to a waypoint? -> pick the next one!
if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance) {
curWayPoint = PickNextWaypoint (curWayPoint);
SendMessage("StartIdle", SendMessageOptions.DontRequireReceiver);
yield StartCoroutine("Idle");
}
// Attack the player and wait until
// - player is killed
// - player is out of sight
if (CanSeeTarget (target, attackRange)) {
if (detectionSound.length!=0 && Time.time > detectionTimer && !wasDetected) {
MaySpeak (detectionSound, 0.3);
detectionTimer = Time.time + Random.Range(0.75, 1.25) * detectionInterval;
if (oneTimeDetection)
wasDetected = true;
}
if (shootEnemies) {
cm.maxForwardSpeed = runSpeed;
yield StartCoroutine("AttackPlayer");
}
}
cm.maxForwardSpeed = walkSpeed;
FindPath (waypointPosition);
yield;
}
}
function Idle () {
var timeout : float;
timeout = Random.Range(0.75, 1.25) * patrolPauseTime;
while (timeout > 0.0) {
if (FindClosest () != null)
target = FindClosest ().transform;
if (CanSeeTarget (target, attackRange))
return;
Stop ();
timeout -= Time.deltaTime;
yield;
}
}
function CanSeeTarget (target : Transform, distanceToTarget : float) : boolean {
if (target != null && target.gameObject.active) {
if (Vector3.Distance(transform.position, target.position) > distanceToTarget)
return false;
var hit : RaycastHit;
if (Physics.Linecast (lookFrom.position, target.position, hit, lookFromLayerMask.value))
return hit.transform == target;
return false;
} else {
return false;
}
}
function Shoot () {
var timeout : float;
timeout = Random.Range(0.05, burstTimeMax);
// Start aim animation
animation.CrossFade("aiming"+aiWeapons.weaponIndex, 0.1);
// Wait for the rest of the animation to finish
yield WaitForSeconds(Random.Range(burstIntervalMin, burstIntervalMax));
// Start shoot animation
animation.CrossFade("shoot"+aiWeapons.weaponIndex, 0.0);
// Wait random time for some inacurracy of a first shot
// (Inacurracy depends on shot animation)
yield WaitForSeconds(Random.Range(0, 0.1));
while (timeout > 0.0) {
if ((!CanSeeTarget (target, shootRange) && Random.value > 0.2) || reloading) {
animation.Stop("shoot"+aiWeapons.weaponIndex);
return;
}
if (target != null && target.gameObject.active)
RotateTowards(target.position);
// Fire gun
BroadcastMessage("Fire", SendMessageOptions.DontRequireReceiver);
timeout -= Time.deltaTime;
yield;
}
animation.Stop("shoot"+aiWeapons.weaponIndex);
}
function Reloading (reloadTime : float) {
reloading = true;
yield WaitForSeconds(reloadTime);
reloading = false;
}
function AttackPlayer () {
var lastVisiblePlayerPosition = target.position;
while (true) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
if (FindClosest () != null)
target = FindClosest ().transform;
// Target is dead - stop hunting
if (target == null || !target.gameObject.active) {
if (playerDeadSound.length!=0 && Time.time > playerDeadTimer) {
MaySpeak (playerDeadSound, 0.3);
playerDeadTimer = Time.time + Random.Range(0.75, 1.25) * playerDeadInterval;
}
return;
}
// Target is too far away - give up
var distance = Vector3.Distance(transform.position, target.position);
if (distance > attackRange)
return;
if (CanSeeTarget (target, attackRange)) {
lastVisiblePlayerPosition = target.position;
var forward = transform.TransformDirection(Vector3.forward);
var targetDirection = lastVisiblePlayerPosition - transform.position;
targetDirection.y = 0;
var angle = Vector3.Angle(targetDirection, forward);
if (distance < moveOnRange && (!moveTowardsEnemies || !searchForEnemies)) {
moveTowardsEnemies = true;
searchForEnemies = true;
}
if (moveTowardsEnemies && distance > dontComeCloserRange)
FindPath (lastVisiblePlayerPosition);
if (distance < dontComeCloserRange) {
currDistance = dontComeCloserRange;
if (beforeShootSound.length!=0 && Time.time > beforeShootTimer) {
MaySpeak (beforeShootSound, 0.1);
beforeShootTimer = Time.time + Random.Range(0.75, 1.25) * beforeShootInterval;
}
RotateTowards(lastVisiblePlayerPosition);
if (distance > 2.0 && angle < shootAngle && !reloading) {
headLookControl.effect = 1;
aimOffscreen.target = target;
yield StartCoroutine("Shoot");
}
}
// Start shooting if close and play is in sight
if (distance < shootRange && distance > dontComeCloserRange && (Mathf.Abs(distance - currDistance) > shootDistStep || Time.time > shootTimer)) {
if (beforeShootSound.length!=0 && Time.time > beforeShootTimer) {
MaySpeak (beforeShootSound, 0.1);
beforeShootTimer = Time.time + Random.Range(0.75, 1.25) * beforeShootInterval;
}
RotateTowards(lastVisiblePlayerPosition);
if (angle < shootAngle && !reloading) {
headLookControl.effect = 1;
aimOffscreen.target = target;
yield StartCoroutine("Shoot");
currDistance = distance;
shootTimer = Time.time + Random.Range(0.75, 1.25) * shootTimeStep;
}
}
if (distance > shootRange) {
currDistance = shootRange;
}
if (distance < 2.0) {
var stepBackwards = transform.position - targetDirection * (2.0 - distance);
MoveBackwards(stepBackwards);
}
} else {
currDistance = shootRange;
if (searchForEnemies)
yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
// Player not visible anymore - stop attacking
if (!CanSeeTarget (target, attackRange))
return;
}
yield;
}
}
function SearchPlayer (position : Vector3) {
// Run towards the player but after 3 seconds timeout and go back to Patroling
var timeout = Random.Range(searchTimeMin, searchTimeMax);
while (timeout > 0.0) {
if (shootEnemies) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
}
// Target is dead - stop hunting
if (target == null || !target.gameObject.active)
return;
// We found the player
if (CanSeeTarget (target, attackRange))
return;
FindPath (position);
if (searchSound.length!=0 && Time.time > searchTimer) {
MaySpeak (searchSound, 0.5);
searchTimer = Time.time + Random.Range(0.75, 1.25) * searchInterval;
}
timeout -= Time.deltaTime;
yield;
}
}
function RotateTowards (position : Vector3) {
cm = GetComponent("CharacterMotor");
Stop ();
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.1)
return;
// Rotate towards the target
var facingDirection = direction;
if (facingDirection.magnitude>1) facingDirection = facingDirection.normalized;
cm.desiredFacingDirection = facingDirection;
}
function MoveTowards (position : Vector3) {
cm = GetComponent("CharacterMotor");
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.5) {
Stop ();
return;
}
// Rotate towards the target
var facingDirection = direction;
if (facingDirection.magnitude>1) facingDirection = facingDirection.normalized;
cm.desiredFacingDirection = facingDirection;
// Modify speed so we slow down when we are not facing the target
var forward = transform.TransformDirection(Vector3.forward);
var speedModifier = Vector3.Dot(forward, direction.normalized);
speedModifier = Mathf.Clamp01(speedModifier);
// Move the character
direction = forward * cm.maxForwardSpeed * speedModifier;
var directionVector = direction.forward;
if (directionVector.magnitude>1) directionVector = directionVector.normalized;
cm.desiredMovementDirection = directionVector;
SendMessage("SetSpeed", cm.maxForwardSpeed * speedModifier, SendMessageOptions.DontRequireReceiver);
}
function MoveBackwards (position : Vector3) {
cm = GetComponent("CharacterMotor");
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude > 2.0) {
Stop ();
return;
}
var directionVector = direction.forward;
if (directionVector.magnitude>1) directionVector = directionVector.normalized;
cm.desiredMovementDirection = -directionVector;
SendMessage("SetSpeed", cm.maxForwardSpeed, SendMessageOptions.DontRequireReceiver);
}
function PickNextWaypoint (currentWaypoint : AutoWayPoint) {
// We want to find the waypoint where the character has to turn the least
// The direction in which we are walking
var forward = transform.TransformDirection(Vector3.forward);
// The closer two vectors, the larger the dot product will be.
var best = currentWaypoint;
var bestDot = -10.0;
for (var cur : AutoWayPoint in currentWaypoint.connected) {
var direction = Vector3.Normalize(cur.transform.position - transform.position);
var dot = Vector3.Dot(direction, forward);
if (dot > bestDot && cur != currentWaypoint) {
bestDot = dot;
best = cur;
}
}
return best;
}
function FindClosest () : GameObject {
// Find all game objects with tag Enemy
var gof : GameObject[];
gof = GameObject.FindGameObjectsWithTag("Friend");
var gofs = new Array (gof);
var gop : GameObject[];
gop = GameObject.FindGameObjectsWithTag("Player");
var gops = new Array (gop);
var gos = gofs.Concat(gops);
var closest : GameObject;
var distance = Mathf.Infinity;
var position = transform.position;
// Iterate through them and find the closest one
for (var go : GameObject in gos) {
var diff = (go.transform.position - position);
var curDistance = diff.sqrMagnitude;
if (curDistance < distance && CanSeeTarget (go.transform, attackRange)) {
closest = go;
distance = curDistance;
}
}
return closest;
}
function MaySpeak (sound : AudioClip[], delay : float) {
yield WaitForSeconds (delay);
if (!playing) {
playing = true;
audio.clip = sound[Random.Range(0, sound.length)];
audio.volume = vol;
audio.Play();
yield WaitForSeconds(audio.clip.length);
playing = false;
}
}
function GridProjection (target : Vector3, gridProjectionDist : float) : Vector3 {
var gridHit : RaycastHit;
if (Physics.Raycast (target, -Vector3.up, gridHit, gridProjectionDist, gridProjectionMask.value)) {
Debug.DrawRay(target, -Vector3.up * gridHit.distance, Color.cyan);
return gridHit.point;
} else {
return target;
}
}
function OnEnable () {
if (usePathfinding) {
foundPosition = transform.position;
PathComplete(null);
}
}
var walkSpeed : float = 1.6;
var runSpeed : float = 3.0;
var attackRange : float = 50.0;
var shootRange : float = 30.0;
var shootDistStep : float = 5.0;
var shootTimeStep : float = 5.0;
var shootAngle : float = 4.0;
var dontComeCloserRange : float = 5.0;
var shootEnemies : boolean = true;
var moveTowardsEnemies : boolean = true;
var searchForEnemies : boolean = true;
var moveOnRange : float = 10.0;
var searchTimeMin : float = 15.0;
var searchTimeMax : float = 30.0;
var burstIntervalMin : float = 0.5;
var burstIntervalMax : float = 1.0;
var burstTimeMax : float = 0.3;
var waypointsGroupName : String = "Shared";
var pickNextWaypointDistance : float = 2.0;
var pickNextFoundPosDistance : float = 1.0;
var maxStop : float = 3.0;
var detectionSound : AudioClip[];
var detectionInterval : float = 10.0;
var oneTimeDetection : boolean = false;
var beforeShootSound : AudioClip[];
var beforeShootInterval : float = 10.0;
var searchSound : AudioClip[];
var searchInterval : float = 30.0;
var playerDeadSound : AudioClip[];
var playerDeadInterval : float = 10.0;
var lookFrom : Transform;
var lookFromLayerMask : LayerMask = -1; // CanSeeTarget layer mask
var gridProjectionMask : LayerMask = 0; // Usually layer of your navmeshes
var usePathfinding : boolean = true;
private var target : Transform;
private var currDistance : float;
private var controller : CharacterController;
private var headLookControl : HeadLookController;
private var aiWeapons : AIWeapons;
private var aimOffscreen : AimOffscreen;
private var command : String = "Stay";
private var foundPosition : Vector3;
private var points : Vector3[];
private var curpoint : int = 0;
private var canSearchAgain : boolean = true;
private var patrolPauseTime : float = 10.0;
private var startPathTimer : float = 0.2;
private var detectionTimer : float = -1.0;
private var shootTimer : float = -1.0;
private var beforeShootTimer : float = -1.0;
private var searchTimer : float = -1.0;
private var playerDeadTimer : float = -1.0;
private var wasDetected : boolean = false;
private var playing : boolean = false;
private var reloading : boolean = false;
private var vol : float;
// Make sure there is always a character controller
@script RequireComponent (CharacterController)
function Start () {
controller = GetComponent(CharacterController);
headLookControl = GetComponent(HeadLookController);
aiWeapons = GetComponent(AIWeapons);
aimOffscreen = GetComponentInChildren(AimOffscreen);
currDistance = shootRange;
vol = audio.volume;
foundPosition = transform.position;
command = "Stay";
Patrol ();
if (usePathfinding) {
yield WaitForSeconds (Random.value*0.2);
while (true) {
FindPoint (curpoint);
yield WaitForSeconds (0.2);
}
}
}
function Update () {
if (usePathfinding)
Debug.DrawLine (transform.position, foundPosition, Color.blue);
}
function PathComplete (newPoints : Vector3[]) {
canSearchAgain = true;
points = newPoints;
FindPoint (0);
command = "Walk";
}
function PathError () {
canSearchAgain = true;
}
function HasReachedTarget () : boolean {
return curpoint >= points.Length;
}
function FindPoint (cpoint : int) {
curpoint = cpoint;
if (points == null || points.Length == 0 || curpoint >= points.Length) {
foundPosition = transform.position;
Stop ();
return;
}
if (points.Length == 1) {
foundPosition = points[0];
command = "Walk";
return;
}
command = "Walk";
foundPosition = points[curpoint];
var p : Vector3 = foundPosition;
p.y = transform.position.y;
if (curpoint < points.Length - 1) {
if ((transform.position-p).sqrMagnitude < pickNextFoundPosDistance*pickNextFoundPosDistance) {
curpoint++;
FindPoint (curpoint);
}
} else {
if ((transform.position-p).sqrMagnitude < maxStop*maxStop) {
curpoint++;
FindPoint (curpoint);
}
}
}
function Stop () {
command = "Stay";
SendMessage("SetSpeed", 0.0, SendMessageOptions.DontRequireReceiver);
}
function FindPath (destination : Vector3) {
if (usePathfinding) {
seeker = GetComponent("Seeker");
var startProj = transform.position;
// var startProj = GridProjection(transform.position, 2.5);
var destinationProj = GridProjection(destination, 50);
if (Time.time > startPathTimer) {
seeker.StartPath(startProj, destinationProj);
startPathTimer = Time.time + 0.2;
}
}
// Move towards our target
if (command == "Walk")
MoveTowards(foundPosition);
else
MoveTowards(destination);
}
function Patrol () {
cm = GetComponent("CharacterMotor");
var curWayPoint = AutoWayPoint.FindClosest(transform.position, waypointsGroupName);
while (true) {
if (shootEnemies) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
}
if (FindClosest () != null)
target = FindClosest ().transform;
var waypointPosition = curWayPoint.transform.position;
patrolPauseTime = curWayPoint.pauseTime;
// Are we close to a waypoint? -> pick the next one!
if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance) {
curWayPoint = PickNextWaypoint (curWayPoint);
SendMessage("StartIdle", SendMessageOptions.DontRequireReceiver);
yield StartCoroutine("Idle");
}
// Attack the player and wait until
// - player is killed
// - player is out of sight
if (CanSeeTarget (target, attackRange)) {
if (detectionSound.length!=0 && Time.time > detectionTimer && !wasDetected) {
MaySpeak (detectionSound, 0.3);
detectionTimer = Time.time + Random.Range(0.75, 1.25) * detectionInterval;
if (oneTimeDetection)
wasDetected = true;
}
if (shootEnemies) {
cm.maxForwardSpeed = runSpeed;
yield StartCoroutine("AttackPlayer");
}
}
cm.maxForwardSpeed = walkSpeed;
FindPath (waypointPosition);
yield;
}
}
function Idle () {
var timeout : float;
timeout = Random.Range(0.75, 1.25) * patrolPauseTime;
while (timeout > 0.0) {
if (FindClosest () != null)
target = FindClosest ().transform;
if (CanSeeTarget (target, attackRange))
return;
Stop ();
timeout -= Time.deltaTime;
yield;
}
}
function CanSeeTarget (target : Transform, distanceToTarget : float) : boolean {
if (target != null && target.gameObject.active) {
if (Vector3.Distance(transform.position, target.position) > distanceToTarget)
return false;
var hit : RaycastHit;
if (Physics.Linecast (lookFrom.position, target.position, hit, lookFromLayerMask.value))
return hit.transform == target;
return false;
} else {
return false;
}
}
function Shoot () {
var timeout : float;
timeout = Random.Range(0.05, burstTimeMax);
// Start aim animation
animation.CrossFade("aiming"+aiWeapons.weaponIndex, 0.1);
// Wait for the rest of the animation to finish
yield WaitForSeconds(Random.Range(burstIntervalMin, burstIntervalMax));
// Start shoot animation
animation.CrossFade("shoot"+aiWeapons.weaponIndex, 0.0);
// Wait random time for some inacurracy of a first shot
// (Inacurracy depends on shot animation)
yield WaitForSeconds(Random.Range(0, 0.1));
while (timeout > 0.0) {
if ((!CanSeeTarget (target, shootRange) && Random.value > 0.2) || reloading) {
animation.Stop("shoot"+aiWeapons.weaponIndex);
return;
}
if (target != null && target.gameObject.active)
RotateTowards(target.position);
// Fire gun
BroadcastMessage("Fire", SendMessageOptions.DontRequireReceiver);
timeout -= Time.deltaTime;
yield;
}
animation.Stop("shoot"+aiWeapons.weaponIndex);
}
function Reloading (reloadTime : float) {
reloading = true;
yield WaitForSeconds(reloadTime);
reloading = false;
}
function AttackPlayer () {
var lastVisiblePlayerPosition = target.position;
while (true) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
if (FindClosest () != null)
target = FindClosest ().transform;
// Target is dead - stop hunting
if (target == null || !target.gameObject.active) {
if (playerDeadSound.length!=0 && Time.time > playerDeadTimer) {
MaySpeak (playerDeadSound, 0.3);
playerDeadTimer = Time.time + Random.Range(0.75, 1.25) * playerDeadInterval;
}
return;
}
// Target is too far away - give up
var distance = Vector3.Distance(transform.position, target.position);
if (distance > attackRange)
return;
if (CanSeeTarget (target, attackRange)) {
lastVisiblePlayerPosition = target.position;
var forward = transform.TransformDirection(Vector3.forward);
var targetDirection = lastVisiblePlayerPosition - transform.position;
targetDirection.y = 0;
var angle = Vector3.Angle(targetDirection, forward);
if (distance < moveOnRange && (!moveTowardsEnemies || !searchForEnemies)) {
moveTowardsEnemies = true;
searchForEnemies = true;
}
if (moveTowardsEnemies && distance > dontComeCloserRange)
FindPath (lastVisiblePlayerPosition);
if (distance < dontComeCloserRange) {
currDistance = dontComeCloserRange;
if (beforeShootSound.length!=0 && Time.time > beforeShootTimer) {
MaySpeak (beforeShootSound, 0.1);
beforeShootTimer = Time.time + Random.Range(0.75, 1.25) * beforeShootInterval;
}
RotateTowards(lastVisiblePlayerPosition);
if (distance > 2.0 && angle < shootAngle && !reloading) {
headLookControl.effect = 1;
aimOffscreen.target = target;
yield StartCoroutine("Shoot");
}
}
// Start shooting if close and play is in sight
if (distance < shootRange && distance > dontComeCloserRange && (Mathf.Abs(distance - currDistance) > shootDistStep || Time.time > shootTimer)) {
if (beforeShootSound.length!=0 && Time.time > beforeShootTimer) {
MaySpeak (beforeShootSound, 0.1);
beforeShootTimer = Time.time + Random.Range(0.75, 1.25) * beforeShootInterval;
}
RotateTowards(lastVisiblePlayerPosition);
if (angle < shootAngle && !reloading) {
headLookControl.effect = 1;
aimOffscreen.target = target;
yield StartCoroutine("Shoot");
currDistance = distance;
shootTimer = Time.time + Random.Range(0.75, 1.25) * shootTimeStep;
}
}
if (distance > shootRange) {
currDistance = shootRange;
}
if (distance < 2.0) {
var stepBackwards = transform.position - targetDirection * (2.0 - distance);
MoveBackwards(stepBackwards);
}
} else {
currDistance = shootRange;
if (searchForEnemies)
yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
// Player not visible anymore - stop attacking
if (!CanSeeTarget (target, attackRange))
return;
}
yield;
}
}
function SearchPlayer (position : Vector3) {
// Run towards the player but after 3 seconds timeout and go back to Patroling
var timeout = Random.Range(searchTimeMin, searchTimeMax);
while (timeout > 0.0) {
if (shootEnemies) {
headLookControl.effect = 0;
headLookControl.targetTransform = target;
}
// Target is dead - stop hunting
if (target == null || !target.gameObject.active)
return;
// We found the player
if (CanSeeTarget (target, attackRange))
return;
FindPath (position);
if (searchSound.length!=0 && Time.time > searchTimer) {
MaySpeak (searchSound, 0.5);
searchTimer = Time.time + Random.Range(0.75, 1.25) * searchInterval;
}
timeout -= Time.deltaTime;
yield;
}
}
function RotateTowards (position : Vector3) {
cm = GetComponent("CharacterMotor");
Stop ();
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.1)
return;
// Rotate towards the target
var facingDirection = direction;
if (facingDirection.magnitude>1) facingDirection = facingDirection.normalized;
cm.desiredFacingDirection = facingDirection;
}
function MoveTowards (position : Vector3) {
cm = GetComponent("CharacterMotor");
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.5) {
Stop ();
return;
}
// Rotate towards the target
var facingDirection = direction;
if (facingDirection.magnitude>1) facingDirection = facingDirection.normalized;
cm.desiredFacingDirection = facingDirection;
// Modify speed so we slow down when we are not facing the target
var forward = transform.TransformDirection(Vector3.forward);
var speedModifier = Vector3.Dot(forward, direction.normalized);
speedModifier = Mathf.Clamp01(speedModifier);
// Move the character
direction = forward * cm.maxForwardSpeed * speedModifier;
var directionVector = direction.forward;
if (directionVector.magnitude>1) directionVector = directionVector.normalized;
cm.desiredMovementDirection = directionVector;
SendMessage("SetSpeed", cm.maxForwardSpeed * speedModifier, SendMessageOptions.DontRequireReceiver);
}
function MoveBackwards (position : Vector3) {
cm = GetComponent("CharacterMotor");
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude > 2.0) {
Stop ();
return;
}
var directionVector = direction.forward;
if (directionVector.magnitude>1) directionVector = directionVector.normalized;
cm.desiredMovementDirection = -directionVector;
SendMessage("SetSpeed", cm.maxForwardSpeed, SendMessageOptions.DontRequireReceiver);
}
function PickNextWaypoint (currentWaypoint : AutoWayPoint) {
// We want to find the waypoint where the character has to turn the least
// The direction in which we are walking
var forward = transform.TransformDirection(Vector3.forward);
// The closer two vectors, the larger the dot product will be.
var best = currentWaypoint;
var bestDot = -10.0;
for (var cur : AutoWayPoint in currentWaypoint.connected) {
var direction = Vector3.Normalize(cur.transform.position - transform.position);
var dot = Vector3.Dot(direction, forward);
if (dot > bestDot && cur != currentWaypoint) {
bestDot = dot;
best = cur;
}
}
return best;
}
function FindClosest () : GameObject {
// Find all game objects with tag Enemy
var gof : GameObject[];
gof = GameObject.FindGameObjectsWithTag("Friend");
var gofs = new Array (gof);
var gop : GameObject[];
gop = GameObject.FindGameObjectsWithTag("Player");
var gops = new Array (gop);
var gos = gofs.Concat(gops);
var closest : GameObject;
var distance = Mathf.Infinity;
var position = transform.position;
// Iterate through them and find the closest one
for (var go : GameObject in gos) {
var diff = (go.transform.position - position);
var curDistance = diff.sqrMagnitude;
if (curDistance < distance && CanSeeTarget (go.transform, attackRange)) {
closest = go;
distance = curDistance;
}
}
return closest;
}
function MaySpeak (sound : AudioClip[], delay : float) {
yield WaitForSeconds (delay);
if (!playing) {
playing = true;
audio.clip = sound[Random.Range(0, sound.length)];
audio.volume = vol;
audio.Play();
yield WaitForSeconds(audio.clip.length);
playing = false;
}
}
function GridProjection (target : Vector3, gridProjectionDist : float) : Vector3 {
var gridHit : RaycastHit;
if (Physics.Raycast (target, -Vector3.up, gridHit, gridProjectionDist, gridProjectionMask.value)) {
Debug.DrawRay(target, -Vector3.up * gridHit.distance, Color.cyan);
return gridHit.point;
} else {
return target;
}
}
function OnEnable () {
if (usePathfinding) {
foundPosition = transform.position;
PathComplete(null);
}
}