MIke
MIke

Reputation: 293

Unity 3D How to setup Turret Auto Aim? C#

what i't trying to achieve is have my turrent rotate and follow an "Enemy".

At the moment it detects the enemy but it is not rotating and I don't know why.

The bullet it a prefab i drag in, there has to be a better way to do this? Anyone have any suggestions please?

At the moment the bullet never triggers, but the log Shoot and does...and the rotate doesn't work.

Here is what i have

using UnityEngine;
using System.Collections;

public class TurretController : MonoBehaviour {

    public Rigidbody bulletPrefab;
    private Transform target;
    private GameObject bullet;
    private float nextFire;
    private Quaternion targetPos;

    void OnTriggerEnter(Collider otherCollider) {
        if (otherCollider.CompareTag("Enemy"))
        {
            Debug.Log ("in");
            target = otherCollider.transform;
            StartCoroutine ("Fire");
        }
    }

    void  OnTriggerExit(Collider otherCollider) {
        if (otherCollider.CompareTag("Enemy"))
        {
            Debug.Log ("out");
            target = null;
            StopCoroutine("Fire"); // aborts the currently running Fire() coroutine
        }
    }

    IEnumerator Fire()
    {
        while (target != null)
        {
            nextFire = Time.time + 0.5f;
            while (Time.time < nextFire)
            {
                // smooth the moving of the turret
                targetPos = Quaternion.LookRotation (target.position);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetPos, Time.deltaTime * 5);
                yield return new WaitForEndOfFrame();
            }
            // fire!
            Debug.Log ("shoot");
            bullet = Instantiate(bulletPrefab, transform.position, transform.rotation) as GameObject;
            //bullet.rigidbody.velocity = transform.forward * bulletSpeed;
        }
    }
}

I tried to change the instantiate part by using this instead

bullet = (GameObject)Instantiate(bulletPrefab, transform.position, transform.rotation);
            bullet.GetComponent<Bullet>().target = target.transform;

But then i just get errors like "InvalidCastException: Cannot cast from source type to destination type. TurretController+c__Iterator0.MoveNext () (at Assets/Scripts/TurretController.cs:44)"

Upvotes: 0

Views: 12735

Answers (2)

piojo
piojo

Reputation: 6723

BTW, here's the turret rotation code I used in my project (shared with permission):

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Turret : MonoBehaviour
{
    [SerializeField]
    private float turnRateRadians = 2 * Mathf.PI;

    [SerializeField]
    private Transform turretTop; // the gun part that rotates

    [SerializeField]
    private Transform bulletSpawnPoint;

    private Enemy target;

    void Update()
    {
        TargetEnemy();
    }

    void TargetEnemy()
    {
        if (target == null || target.health <= 0)
            target = Enemy.GetClosestEnemy(turretTop, filter: enemy => enemy.health > 0);

        if (target != null)
        {
            Vector3 targetDir = target.transform.position - transform.position;
            // Rotating in 2D Plane...
            targetDir.y = 0.0f;
            targetDir = targetDir.normalized;

            Vector3 currentDir = turretTop.forward;

            currentDir = Vector3.RotateTowards(currentDir, targetDir, turnRateRadians*Time.deltaTime, 1.0f);

            Quaternion qDir = new Quaternion();
            qDir.SetLookRotation(currentDir, Vector3.up);
            turretTop.rotation = qDir;
        }
    }
}

class Enemy : MonoBehaviour
{
    public float health = 0;

    private static HashSet<Enemy> allEnemies = new HashSet<Enemy>();

    void Awake()
    {
        allEnemies.Add(this);
    }

    void OnDestroy()
    {
        allEnemies.Remove(this);
    }

    /// <summary>
    /// Get the closest enemy to some transform, optionally filtering
    /// (for example, enemies that aren't dead, or enemies of a certain type).
    /// </summary>
    public static Enemy GetClosestEnemy(Transform referenceTransform, System.Predicate<Enemy> filter=null)
    {
        // Left as an exercise for the reader.
        // Remember not to use Vector3.Distance in a loop if you don't need it. ;-)
//      return allEnemies[0];
    }
}

Upvotes: 2

piojo
piojo

Reputation: 6723

First problem: the bullet prefab. The variable type is RigidBody. If you want to treat it as a game object, the variable must be a game object. Or you can instantiate it, cast to RigidBody, then use the .gameObject accessor. Like this:

((RigidBody)Instantiate(theRigidbody)).gameObject

Second problem: start simple with the rotation. If it's not working, don't get fancy yet. Start with something like this (an instant rotation toward the target):

Vector3 targetDirection = target.transform.position - transform.position;
targetDirection.y = 0; // optional: don't look up
transform.forward = targetDirection;

If it works, then add small pieces of additional complexity until it does exactly what you want. And if you don't get things figured out, give me a shout (a comment) on Monday. I've written turret-aiming code (including a maximum rotation speed), and I don't think my boss would mind if I upload it.

Upvotes: 1

Related Questions