- Home /
npc patrol and chase
This is the script that I currently have. It is on the NPC and when the spawn trigger is hit the NPC is spawned with this script on it. it will turn and chase the player currently however, i want it to stay within a certain radius until the player enters that circle and then chase the player. if the player is out of that radius then I want the NPC to go back to the original spawn point. it is set with an empty game object labeled spawnpoint1.
#pragma strict
var player = Transform;
var speed : float = 2; // well...the speed
var controller:CharacterController;
function Start(){
controller = gameObject.GetComponent(CharacterController);
}
function Update(){
transform.LookAt(GameObject.FindWithTag("Player").transform); // the NPC looks at the player
// Here you access the Character Controller component and move your NPC with SimpleMove() giving the speed and the direction(forward).
//As the NPC is looking at you, forward is in your direction.
controller.SimpleMove(speed*transform.forward);
animation.Play("WalkForwardNoGun"); //You play the animation
}
any thoughts as to how I can accomplish this?
Answer by cdrandin · Jan 17, 2013 at 06:14 AM
I won't write the code, but I figure pseudo code will be helpful. So you NPC has spawned and is in the game world. Start of by him walking, so do the animations and sounds, etc.
Now, lets have him follow a path. For now just do moving forward then backward. Have the script store target as a gameobject so you know what to look for. So, drop your player using the click and drag system. Then, check the distance. Vector3.Distance(target, transform) < 20 , so the player is within 20 units of your NPC, now have the NPC chase the target. At this point make sure to save initial position, so you can some back to it when you are done chasing. So, if NPC is chasing, check if Vector3.Distance(target, transform) > 20 and it has been 5.0 seconds , so you don't chase forever, meaning player is out of reach and enough time has passed for the NPC to forget about it. Then have NPC travel back to its initial position. Then from there continue patrol.
Thing you will need to make is an AI system which handles collision with obejobjects and what not. This assume no combat or anything for now. Just chases and follows.
Thanks for all of the suggestions. So here is the updated code. The main problem that I currently have is that it seems that the logic is backwards.
#pragma strict //var player = Transform; //player = GameObject.FindWithTag("Player").transform; var moveSpeed : float = 1.5; var rotSpeed : float = 10; var moveDir : int = 1; var speed : float = 2; // well...the speed var maxDistance : float = 50; var controller:CharacterController;
function Start(){ controller = gameObject.GetComponent(CharacterController); } function Update(){
//if an enemy as further than maxDistance from you, it cannot see you
var maxDistanceSquared = maxDistance * maxDistance;
var rayDirection : Vector3 = GameObject.FindWithTag("Player").transform.localPosition - transform.localPosition;
var enemyDirection : Vector3 = transform.TransformDirection(Vector3.forward);
var angleDot = Vector3.Dot(rayDirection, enemyDirection);
var playerInFrontOfEnemy = angleDot > 0.0;
var playerCloseToEnemy = rayDirection.sqr$$anonymous$$agnitude < maxDistanceSquared;
if ( playerInFrontOfEnemy && playerCloseToEnemy)
{
//by using a Raycast you make sure an enemy does not see you
//if there is a bulduing separating you from his view, for example
//the enemy only sees you if it has you in open view
var hit : RaycastHit;
if (Physics.Raycast (transform.position,rayDirection, hit, maxDistance)
&& hit.collider.gameObject == GameObject.FindWithTag("Player").transform) //player object here will be your Player GameObject
{
//enemy sees you - perform some action
// Here you access the Character Controller component and move your NPC with Simple$$anonymous$$ove() giving the speed and the direction(forward).
//As the NPC is looking at you, forward is in your direction.
controller.Simple$$anonymous$$ove(speed*transform.forward);
animation.Play("WalkForwardNoGun"); //You play the animation
}
else
{
//enemy doesn't see you
if(!Physics.Raycast(transform.position, transform.forward, 5))
{
transform.Translate(Vector3.forward * moveSpeed * Time.smoothDeltaTime);
}
else
{
if(Physics.Raycast(transform.position, - transform.right, 1))
{
moveDir = 1;
}
else if(Physics.Raycast(transform.position, transform.right, 1))
{
moveDir = -1;
}
transform.Rotate(Vector3.up, 90 * rotSpeed * Time.smoothDeltaTime * moveDir);
animation.Play("WalkForwardNoGun"); //You play the animation
}
}
}
}
the is detected portion is acting like the is not detected portion and vice-verse.
the part that should be //enemy doesn't see you
is actcually seeing the player. and the part that is
//enemy sees you - perform some action
is not seeing the player at all. I reversed the if statement and it seems to work correctly now. what do you think though? am I correct in reversing it? it seems fine...
When being specific with game logic don't just use else. if playerInFrontOfEnemy && playerCloseToEnemy is not true, then an other different possibility will still execute that else code section. Use an else if and make sure the enemy is not looking at you. Else statements in complex logic tend to act differently then how we would expect. Also, think about it as, don't let the computer decide the logic for you, Always use some constrictions. If, else if, switch, etc.
Doing that might work, but you should really test it out. I just don't like using else statement UNLESS there is a definite "this" or "that" logic. Like: if playerAlive: then this; else: then that; If you want a definite way to check if npc doesn't see, check that his LoS is greater than the cap and npc not facing target. This would obviously mean that the npc doesn't see the target.