Hiya, Sorry to post another question but I require one last scripting assistance! I just really need a very basic AI script, as I don't understand AI very well. All the script needs to do is have the enemy object move towards the FPS Controller when in range, and when the enemy is within very close range, deal regular damage every 1 or 2 seconds. Any help would be greatly appreciated! I'm not concerned with animations just yet! Thanks Kira
Grab the FPS tutorial from the Resources section here on the site - grab the scripts off the Robot. They do exactly what you are looking for and are in javascript as well.
Hi, thanks for the reply. I tried looking at the scripts and fashioned something myself as it was getting a bit messy (they're using projectiles and have animations) but it needs work. I can't get rotation to work at the moment though. Code (csharp): var player : GameObject; var speed = 3.0; var range = 20.0; var hitRange = 3.0; var enemyDamage = 100.0; function Start () { player = GameObject.FindGameObjectWithTag("1Player"); } function Update() { //move towards player var distance = Vector3.Distance( player.transform.position, transform.position); if (distance > range) { return; } else { var delta = player.transform.position - transform.position; delta.Normalize(); var moveSpeed = speed * Time.deltaTime; transform.position = transform.position + (delta * moveSpeed); if (distance < hitRange) { player.SendMessageUpwards ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver); } } } Also, I've set it to do the damage within a smaller range. It is, obviously, calling it every update (which is probably very frame). Is there an easy way to reduce the frequency of that check being made whilst keep it regularly updated?
Ok so I've made SOME progress with the rotation, but now for some reason when you get within range, he rotates 90 degrees on the x axis so that he's flying head first at me. =S Not sure how to change this. (I'll admit, I just adapted the code from the tutorial). Also, still not sure how to make the damage occur fewer times than once every frame (perhaps down to once every 1.5 seconds while within range?) I've tried WaitForSeconds(1.5); within the damage receiving script but it didn't agree. Any advances please? =] Ooo yea and here's my code thus far: Code (csharp): var player : GameObject; var speed = 6.0; var range = 10.0; var hitRange = 5.0; var enemyDamage = 10.0; var rotationSpeed = 5.0; function Start () { player = GameObject.FindGameObjectWithTag("1Player"); } function Update() { //move towards player var distance = Vector3.Distance( player.transform.position, transform.position); if (distance > range) { return; } else { var delta = player.transform.position - transform.position; delta.Normalize(); delta.y = 0; var moveSpeed = speed * Time.deltaTime; transform.position = transform.position + (delta * moveSpeed); delta.y = 0; transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed * Time.deltaTime); transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); if (distance < hitRange) { player.SendMessageUpwards ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver); } } }
Mathematically, one of the best way to model 1 moving object A searching another moving object B is to do: x->x+sign(x'-x)*speed y->y+sign(y'-y)*speed z->z+sign(z'-z)*speed knowing A(x,y,z) and B(x',y',z') It is also very fast and elegant. Condition is obvious: speed of A must be higher than B. EDIT: sorry, but this is not really AI...
I am going to take a closer look at this code, but let me just say quickly that the conditional return branch is not necessary because there is no code following outside the conditional branches. Code (csharp): function Update() { if ( x > 10) { return; } else { // code } // no code } can be reduced to Code (csharp): function Update() { if ( x <= 10 ) { // code } }
Hopefully this is a bit closer to the code you were wanting. You can add your Start() in as well. Code (csharp): var player : GameObject; var speed : float=6f; var range : float=10f; var hitRange : float=5f; var enemyDamage : float=10f; var rotationSpeed : float=5f; var damageTimer : float=0f; function Update() { //move towards player var distance = Vector3.Distance(transform.position, player.transform.position); if(distance<=range) { var delta = player.transform.position - transform.position; delta.Normalize(); delta.y = 0; var moveSpeed = speed * Time.deltaTime; transform.position = transform.position + (delta * moveSpeed); transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed * Time.deltaTime); transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); damageTimer+=Time.deltaTime; if (distance < hitRange damageTimer>=1.5) { damageTimer=0f; player.SendMessageUpwards ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver); } } }
Hiya, Thank you ever so much! The damage timer works a treat now! Unfortunately though, the enemy is still rotating 90 degrees on the x axis so that he's flying head first at you, any ideas? I've tried a few things but I'm not sure if I'm going about it the right way).
I've posted my rotation problem on Unity Answers but still no joy! Here's the link if you wish to look at the progress, any help is greatly appreciated! Rotation Problem
I will have another look. Is it possible that the MeshRenderer is rotated 90 or -90 on the x axis, but the parent GameObject is not?
I am so sorry to all of you trying to help me! I can't believe I overlooked something so simple! Thank you for pointing me in the direction Mike Stampone, it was the fact that I had to rotate my model 270 degrees around the x to get him stood up right in Unity, so when transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); was called it set it back to 0. Just changed that to transform.eulerAngles = Vector3(270, transform.eulerAngles.y, 0); and it works fine. Again, I sincerely apologise for being so idiotic! Thanks again for all of your help, I still learn a lot! Kira
Just thought I would add a couple comments, as it made it easier for me to read. You can take them or leave them. Anyway, your "enemy" should not be rotating in the x axis, because you throw away your x and z rotation with : transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); One of your GameObjects within the "enemy" must be rotated 90 or -90 in the x axis. At the moment, the "enemy" will point it's +z axis toward the "player". I assume this is because forward is Vector3(0,0,1) in Unity. Code (csharp): var player : GameObject; var speed : float=6f; var range : float=10f; var hitRange : float=5f; var enemyDamage : float=10f; var rotationSpeed : float=5f; var damageTimer : float=0f; function Start() { player = GameObject.FindGameObjectWithTag("1Player"); } function Update() { // Move the Player var distance = Vector3.Distance(transform.position, player.transform.position); if(distance<=range) { // Translate var delta = player.transform.position - transform.position; delta.Normalize(); delta.y = 0; var moveSpeed = speed * Time.deltaTime; transform.position = transform.position + (delta * moveSpeed); // Rotate transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed * Time.deltaTime); transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); // Apply damage every 1.5 seconds damageTimer+=Time.deltaTime; if (distance < hitRange damageTimer>=1.5) { damageTimer=0f; player.SendMessageUpwards ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver); } } }
Thank you for the help, sorry for making you go through all of that for pretty much nothing! Just a simple mistake made by myself! I really appreciate all of your help, this forum is a great place to go for help. EDIT: I was thinking that I would like to add some code to make the zombie stop moving towards you if say the distance is 1.5 so that it doesn't move inside you, but make it continue rotating towards you regardless of the distance. Could this be done with a simple check before the movement code? I think I need to start separating the things in to methods now to make the code cleaner.
Sorry to post again but I'm quite chuffed with my code right now! It may not be "proper" AI, nor particularly advanced or have extended functionality but it works and does a simple job relatively well. I know that when I was first trying to get this script together, I was desperately looking for ANY starting point to work off of (I hit lucky and found a thread which started me off) and think that this may be helpful to those in a similar situation. So here's the code so far, it currently moves towards you (the game object with tag "1player") as well as rotate towards you. When it gets in to a certain range, it starts doing damage in regular time intervals and then when within a portion of that "hit range" it'll stop moving towards you, but will continue to rotate towards you and keeps damaging you. Code (csharp): var player : GameObject; var speed : float=6f; var range : float=15f; var hitRange : float=6f; var enemyDamage : float=10f; var rotationSpeed : float=5f; var damageTimer : float=0f; var delta : Vector3; var distance; function Start() { player = GameObject.FindGameObjectWithTag("1Player"); } function Update() { //calculate the enemy's distance from player and do a check to see if we should //progress then call the necessary methods distance = Vector3.Distance(transform.position, player.transform.position); if(distance<=range) { MoveTowards(); RotateTowards(); AttackPlayer(); } } function MoveTowards() { delta = player.transform.position - transform.position; delta.Normalize(); delta.y = 0; if(distance<=(hitRange/1.5)) { return; } var moveSpeed = speed * Time.deltaTime; transform.position = transform.position + (delta * moveSpeed); } function RotateTowards() { transform.rotation = Quaternion.RotateTowards (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed); transform.rotation = Quaternion.Euler(0, transform.eulerAngles.y, 0); } function AttackPlayer() { damageTimer+=Time.deltaTime; if (distance < hitRange damageTimer>=1.5) { damageTimer=0f; player.SendMessageUpwards ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver); } }
This is my Ai in my game im making actualy my first AI Script ive made Its In Javascript //This is my code var Distance; var Target : Transform; var LookAtRange = 25.0; var AttackRange = 16.0; var MoveSpeed = 10; var chaserange = 16.0; var Damping = 10.0; var Damage : int = 45; //Attack Timer Vars var art = 1; private var attackTime : float; var damage : int = 45; var controller : CharacterController; var gravity : float = 99.90; private var moveDirection : Vector3 = Vector3.zero; function Start () { attackTime = Time.time; } function Update () { Distance = Vector3.Distance(Target.position, transform.position); if (Distance < LookAtRange) { renderer.material.color = Color.yellow; LookAt(); } if (Distance > LookAtRange) { renderer.material.color = Color.blue; } if (Distance < AttackRange) { attack(); } else if (Distance < chaserange) { renderer.material.color = Color.red; chase(); } } function LookAt() { var rotation = Quaternion.LookRotation(Target.position - transform.position); transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * Damping); } function chase() { moveDirection = transform.forward; moveDirection *= MoveSpeed; moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * Time.deltaTime); } function attack() { { if (Time.time > attackTime) { Target.SendMessage("Applypdmg", Damage, SendMessageOptions.DontRequireReceiver); attackTime = Time.time + art; } } }