- Home /
Need Help Creating my Tank AI Controller!
Hi I am working on a more or less simple AI Controller.
There is the Enemy with a "AIController" script attached and a "Point" prefab. (Empty GameObject, might make attach a partical so I can see it's destination during testing)
The "Point" prefab has a Point script attatched to it. All this script does is on Awake() Set the "end" public transform(as in end of destination) of the AIController script to the "Point" prefabs transform.position.
The part of the AI Controller I am working on now is a Wondering AI. The idea is the AI will have a (int)points(as in points in 3d space.) and (int)destination(Starting at 0) variable.
If the AI's destination is equal to 0, Instantiate a "Point" prefab making the variable destinations to 1.
If the AI's destination is = 1, the AI will smoothly translate to the "Point" prefabs position.
I have tried Transform.Translate, and Vector3.Lerp but I get weird erros with bolth. When I used the Vector3.Lerp, even tho the end.transform was that of the "Point" prefab, the enemy would go to (0,0,0). When I tried Transform.Translate I thought it would just snapto the position. but no.. the enemy very quickly moves along the X axis to like -4000.. and just keeps going and going...
So this is where I am stuck. How can I make It to where the AI will throw out a "Point". Get the position of that point(Already have that set on the PointScript) and then smoothly look at the point and move towards it.
Stopping when it gets within a certain distance would be great kinda like a "Within shooting distance". But im not worried about that I can probably figure that out on my own.
Here is the scripts I have so far:
using UnityEngine;
using System.Collections;
/// <summary>
/// AI controller. This script governs the behavior of the AI Enemy.
/// If the AI does not have a destination, it will instantiate a "Point"
/// into 3D space within the Random.Range parameters, and then move to that
/// point.
/// </summary>
public class AIController : MonoBehaviour {
//----------Variables Start----------
public Transform end; //Our end position.
public Transform start; //Our starting position.
public GameObject points; //The "Point" prefab.
public float waitTime; //The time to wait before finding a new
//destination. I haven't got to this yet.
private Transform myTransform;
public bool weCanMove = false;
public int myDestinations = 0;
public bool thinkingWhereToMove = false;
private Vector3 pointPosition = new Vector3(Random.Range(-1.0f,5.0f),0,Random.Range(-1.0f,5.0f));
//----------Variables End------------
// Use this for initialization
void Start ()
{
//A Quick Reference of our transform.
myTransform = transform;
}
// Update is called once per frame
void Update ()
{
if(myDestinations <=0)
{
CreateADestination();
}
if(myDestinations == 1)
{
MoveToDestination();
}
//Creating our destination. I appologize for this part is poorly written.
if(thinkingWhereToMove)
{
weCanMove = true;
if(weCanMove)
{
//Instantiate points at mytransform + the value of "position" variable, with our rotation.
Instantiate(points, myTransform.position+pointPosition , Quaternion.identity);
}
//There is already a destination, prevent any extras being created.
thinkingWhereToMove = false;
weCanMove = false;
//Here is where I would add a waitTime.
//Now we need a new destination.
myDestinations = 1;
}
}
void CreateADestination()
{
thinkingWhereToMove = true;
}
void MoveToDestination()
{
//This is the translation towards the "Point" part.
//transform.position = Vector3.Lerp(start.position, end.position,Time.deltaTime);
transform.Translate(end.position);
}
}
Here is the PointScript:
using UnityEngine;
using System.Collections;
/// <summary>
/// Point script. This script only gets the AIController of it's target
/// and set the target's "end.position" to the point's position.
/// Allowing the AI to move towards it.
///
/// I know this is a bad way to go about this but since
/// for now there is only one enemy I am not worried about it.
/// </summary>
public class PointScript : MonoBehaviour {
//----------Variables Start----------
public GameObject target; //The point's Target.
private Transform pointTransform; //The point's Transform.
//----------Variables End------------
void Awake()
{
pointTransform = transform;
target = GameObject.FindWithTag("Target");
//Set the AIController's end.position to the point's position.
AIController aiController = target.GetComponent<AIController>();
aiController.end = pointTransform;
}
}
Sorry if it is hard to read due to the way I organize things. It was more "tidy" before I clicked the ask your question button.
Answer by schaddem · Jan 26, 2013 at 09:19 AM
Too much too read for my taste but your problem sounds like a pretty simple one.
okay so weve got our waypoint and our tankposition. waypoint.transform.position-tank.transform position
gives you a vector that goes FROM tank TO waypoint. We can use that to find out where the tank needs to rotate to to face the waypoint. Unity provides the function Quaternion.LookRotation for that. I name that qtarget for quaterniontarget.
var qtarget = Quaternion.LookRotation(waypoint.transform.position-transform.position);
Now that we know where we want to rotate the tank to we need to we need to affect its transform.rotation to actually rotate it. I use Quaternion.Slerp so he rotates smoothly and rspeed is rotationspeed.
transform.rotation = Quaternion.Slerp(transform.rotation,qtarget,rspeed*Time.deltaTime);
Just with this code the tank should look at the waypoint, don't continue if it doesn't.
Now if it does, for moving it, depends on what kind of object your tank is. If it's a rigidbody you'd have to apply a force in fixedupdate for example, but I guess you just want something more fundamental 100%code based. Just wanted to note that when you use the physics engine to move characters around you'll end up using a rigid body or charactercontroller and use them through the functionalities the physicsengine provides, so they behave as they should.
Anyways, now I'd just move the tank forward since it's already looking at it's target. From the top of my head so not mistake proof:
Update{
transform.position+=(Vector3.forward * speed * Time.deltaTime);
}
Next you want to check when it reaches its waypoint. I'd do a distance check here, the distance between the two points is the magnitude(length) of its vector.(see vector above)
var distance =Vector3.magnitude(waypoint.transform.position-transform.position);
if (distance<1)//we reached ourwaypoint
Note that we almost never reach a distance of 0. If you write if (distance<=0) the tank is likely to just drive by the waypoint, since we're moving in increments and once we overstep the waypoint distance increases again. So we cut the detection some slack, if you need the tank EXACTLY at the point youd have to check when he's close enough to overstep the point and then move him there.
Now when the tank reaches the waypoint we want to move it again (or so I understood), you'll need to use Random for that. I assume we just want to move the waypoint on x and z(no flying tank and just a plane).
if (distance<1) {waypoint.transform.position=Vector3(Random.Range(0,100),0,Random.Range(0,100));}
I followed everything you said and it all make sense and works great but the last bit of code is throwing errors:
Assets/$$anonymous$$yAssets/Enemy$$anonymous$$aterials/AIController.cs(101,39): error CS0120: An object reference is required to access non-static member UnityEngine.Vector3.magnitude' Assets/$$anonymous$$yAssets/Enemy$$anonymous$$aterials/AIController.cs(102,21): error CS0019: Operator
<' cannot be applied to operands of type object' and
int'
Assets/$$anonymous$$yAssets/Enemy$$anonymous$$aterials/AIController.cs(104,48): error CS0119: Expression denotes a type', where a
variable', value' or
method group' was expected
How do I fix that?
I just hacked some code out of memory so no guarantees. Could you please post the line that gives you the error? It sounds like a syntax error, like your not talking in the way the language expects you to.
One thing I see is that you code in C# and I wrote examples for unityscript, so there might be an error in translation.