1
\$\begingroup\$

I am trying to get an AI sprite to randomly shoot a SINGLE bullet while walking around. This is a 2D Top-down perspective. The sprite can move up, down, left and right. It randomly changes directions.

When I call the ShootBullet() function, the bullet just sits at were it is instantiated.

enter image description here

The Sprite has a WalkingController attached to it that calls a bullet prefab. The bullet prefab has a script that just handles the movement.

How do I get the bullet to know which direction it should travel when it is created?

I am trying to AVOID the use of the FindObjectWithTag methods. As I have been learning, it seems that - that specific tag is slow.

I really appreciate any help while I am learning!

WALKING SCRIPT This script is also generic so I could attach different enemies with the same setup.

public class WalkingController : MonoBehaviour {


    public Animator    anim;
    public Rigidbody2D body;
    public float moveSpeed  = 0.75f; //HOW FAST THE ENEMY WALKS


    //DEALS WITH SHOOTING BULLET 
    public GameObject   objectToSpawn; //WHICH BULLET TO SHOOT
    public float        shootDamage     = 1.0f;
    public float        timeToSpawn     = 1.0f;
    private float       internalTimer   = 2.0f;

    //Holds the direction the enemy should move
    public Vector2 enemyMovement;


    void Awake() {
        anim = GetComponent<Animator> ();
        body = GetComponent <Rigidbody2D> ();
    }

    void Start () {
        StartCoroutine ("ChangeDirection");
    }

    void Update() {

        //WHEN TO SHOOT A BULLET
        this.internalTimer += Time.deltaTime;

        if (this.internalTimer > this.timeToSpawn) {
            this.ShootBullet();
            this.internalTimer = 0.0f;
        }
    }

    void FixedUpdate () {
        //THIS MOVES THE ENEMY
        body.MovePosition (body.position + enemyMovement * moveSpeed * Time.deltaTime);
    }

    private void ShootBullet() {
        //THIS FIRES THE BULLET
        Instantiate(objectToSpawn, this.transform.position, Quaternion.identity);

        //HOW DO I MAKE THE BULLET MOVE?????
         gameObject.Direction(enemyDirection);

        //HOW DO I PASS HOW MUCH DAMAGE BULLET HAS??

    }


    public Vector2 getEnemyMovement() {
        //TRIED MAKING A PUBLIC ACCESSOR FOR THE BULLET TO ACCESS, BUT DIDN'T WORK
        return enemyMovement;
    }

    IEnumerator ChangeDirection() {
        //RANDOMLY CHANGE THE ENEMY DIRECTION
        while(true){
            yield return new WaitForSeconds(Random.Range (0.3f, 1.5f));
            randomDirection();
        }
    }

    void randomDirection() {
        switch(Random.Range (0,3)){
            case 0:
                //Debug.Log ("Moving enemy Up");
                 enemyMovement = new Vector2 (0,1);
                break;
            case 1:
                //Debug.Log ("Moving enemy Right");
                 enemyMovement = new Vector2 (1,0);
                break;
            case 2: 
                //Debug.Log ("Moving enemy Down");
                 enemyMovement = new Vector2 (0,-1);
                break;
            case 3:
                //Debug.Log ("Moving enemy Left");
                 enemyMovement = new Vector2 (-1,0);
                break;
            default:
                 enemyMovement = new Vector2 (0,0);
                break;
        }
        anim.SetBool ("Walking", true);
        DefineFacingDirection (enemyMovement);

    }

    void DefineFacingDirection (Vector2 vec){
        //THIS IS FOR THE ANIMATOR TO PLAY THE CORRECT ANIMATION
        anim.SetFloat ("InputX", vec.x);
        anim.SetFloat ("InputY", vec.y);
    }
}

PROJECTILE SCRIPT I wanted this script to be pretty generic, so I could attached any animation or prefab to it so i could have different bullets. ie rocks, arrows, throwing stars etc...

public class Projectile : MonoBehaviour {

    public float        moveSpeed = 4.0f;

    //Tried to make the direction public so we could set it on creation, didn't work.
    public Vector2  Direction { get; set; }

    private Rigidbody2D body;

    void Awake() {
        body = gameObject.GetComponent<Rigidbody2D> ();
    }

    void FixedUpdate(){

        body.MovePosition (transform.position + Direction * moveSpeed * Time.deltaTime);
    }

}

UPDATE I tried just making the bullet move by placing it on the scene. Using the below code. It doesn't move when I add body.MovePosition (transform.position + transform.forward * moveSpeed * Time.deltaTime); but if I remove transform.forward the bullet moves to the center of the screen. There are no other scripts attached to the bullet.

enter image description here

public float     moveSpeed = 4.0f;
    public Rigidbody2D body;

    void FixedUpdate(){
        body.MovePosition (transform.position * moveSpeed * Time.deltaTime);
    }
\$\endgroup\$
  • \$\begingroup\$ So you want straight movement or something like projectile? \$\endgroup\$ – Hamza Hasan Mar 2 '16 at 16:20
  • \$\begingroup\$ @HamzaHasan yes, see the update question. \$\endgroup\$ – user-44651 Mar 2 '16 at 16:25
  • \$\begingroup\$ I answered the question "How do I get the bullet to know which direction it should travel when it is created?" But are you now asking a new question on how to actually move a bullet, rather than setting the Direction property of an Instantiated GameObject with the Projectile Component? \$\endgroup\$ – Martin H Hollstein Mar 2 '16 at 17:49
3
\$\begingroup\$

Couple of things you are using in wrong way. Basically it is just the matter of concept.

  • Instantiate will give you an Object in return. So whatever you want to do with instantiated object, you have to keep reference of that.
  • gameObject.Direction, actually gameObject always represents the GameObject on which that very script is attached.

So what you have to do is simply

  • Instantiate your bullet
  • Keep reference of that Object
  • Get the script attached to your bullet prefab

Change your ShootBullet method as,

        GameObject bullet = Instantiate(objectToSpawn, this.transform.position, Quaternion.identity) as GameObject;
        bullet.GetComponent<Projectile>()._direction = enemyDirection;

Now on other hand, your Projectile script should look like,

public class Projectile : MonoBehaviour {

    public float _moveSpeed = 4.0f;

    public Vector2  _direction = Vector2.zero;

    private Rigidbody2D _body;

    void Awake() {
        _body = gameObject.GetComponent<Rigidbody2D> ();
    }

    void FixedUpdate(){
        _body.position = _body.position + _direction.normalized * _moveSpeed * Time.deltaTime;
    }

}

Now it should work if you provide proper direction.

\$\endgroup\$
  • \$\begingroup\$ I think I started crying. THANK YOU! You have been so helpful! This worked! \$\endgroup\$ – user-44651 Mar 2 '16 at 19:38
0
\$\begingroup\$

They have an example of this in the Unity API docs actually.

 Rigidbody clone;
 clone = Instantiate(projectile, transform.position, transform.rotation) as Rigidbody;
 clone.velocity = transform.TransformDirection(Vector3.forward * 10);

Instantiate returns an Object reference then you can cast to the desired type using the as statement. In your case you would just do as GameObject, then call GetComponent<Projectile>().Direction = enemyDirection; on the returned and casted GameObject variable.

\$\endgroup\$
  • \$\begingroup\$ It's 2D bro, Vector3.forawrd is not gonna be work probably \$\endgroup\$ – Hamza Hasan Mar 2 '16 at 16:19
  • \$\begingroup\$ Yes... that is the code from the API. If you read on further, you will see that I call the GetComponent for the actual MonoBehavior he wants to add his Direction Vector... The answer is not always the code in the box to be copied and pasted. Also answer was posted before his update. \$\endgroup\$ – Martin H Hollstein Mar 2 '16 at 17:44
  • 2
    \$\begingroup\$ Why wouldn't you just instantiate the projectile as a Projectile? You would then eliminate the call to GetComponent. \$\endgroup\$ – Mike Hunt Mar 2 '16 at 18:36
  • \$\begingroup\$ I agree with @MikeHunt; however, the current implementation for the code has a prefab GameObject for the Projectile. I was answering based on his current code. \$\endgroup\$ – Martin H Hollstein Mar 2 '16 at 19:17
  • \$\begingroup\$ @Mike Hunt, actually it is not projectile but only class name :) otherwise he did want to move object in straight line. \$\endgroup\$ – Hamza Hasan Mar 3 '16 at 4:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.