0
\$\begingroup\$

Trying to create a 2d Top down random movement. I have the blendtree setup so that it faces the sprite in the right direction. However, I can't get it move right. It just flips back and forth between directions never moving. Unless I use the RidgidBody2d apply force then it just slowly convulses to 0,0.

I guess I wanted it walk in one direction base cardinal direction (no angles) for 3 seconds then change direction.

What Am I doing wrong?

public float moveSpeed = 0.75f;
 public Animator anim;
 public Rigidbody2D body;

 private Vector2 enemyMovement;


 void Start () {
     anim = GetComponent<Animator> ();
 }


 void Update () {
     Invoke("randomDirection", 1);
     transform.position = new Vector3(enemyMovement.x,enemyMovement.y,0) * moveSpeed * Time.deltaTime;

     //TRIED THIS TOO
     //body.AddForce (enemyMovement);
 }

 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;
     }

 }
\$\endgroup\$
  • \$\begingroup\$ You are using enemyMovement as a postion, not a velocity. You add a velocity to current position for the position to change. \$\endgroup\$ – Almo Feb 19 '16 at 15:23
0
\$\begingroup\$

Although you did mark it as answer, but now this code will work 100% correct.

Couple of things are here.

First of all you are calling Invoke in Update. Which means Invoke is executing 60 times per second. That is weird. Instead of that make a Coroutine that will executes every second.

Try the below code,

 public float moveSpeed = 0.75f;
 public Animator anim;
 public Rigidbody2D body;

 private Vector2 enemyMovement;


 void Start () {
     anim = GetComponent<Animator> ();
     StartCoroutine("ChangeDirection");
 }


 void Update () {
     //Invoke("randomDirection", 1);


     transform.position += new Vector3(enemyMovement.x,enemyMovement.y,0) * moveSpeed * Time.deltaTime;

     //TRIED THIS TOO
     //body.AddForce (enemyMovement);
 }

 IEnumerator ChangeDirection()
 {
     while(true){
         yield return new WaitForSeconds(1.0f);
         RandomDirection();
     }
 }

 void RandomDirection() {
     // HAMZA's: Now I'm sure it will work :)
     switch(Random.Range (0,4)){
         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;
     }

 }
\$\endgroup\$
  • \$\begingroup\$ Do you mean 'StartCoroutine("ChangeDirection");' \$\endgroup\$ – user-44651 Feb 19 '16 at 15:29
  • 1
    \$\begingroup\$ it is ok to call randomDirection. If you call every frame changeDirection without waiting the enemy to reach final position the system goes through an umpredictable loop \$\endgroup\$ – Leggy7 Feb 19 '16 at 15:33
  • \$\begingroup\$ This slowed him down. But he never actually moves. He just jumps to 0,0 and faces the direction every second. So that's a step in the right direction! @hamza-hasan \$\endgroup\$ – user-44651 Feb 19 '16 at 15:33
  • \$\begingroup\$ change the update to transform.position += new Vector3(enemyMovement.x,enemyMovement.y,0) * moveSpeed * Time.deltaTime; \$\endgroup\$ – Leggy7 Feb 19 '16 at 15:51
  • \$\begingroup\$ Instead of putting IEnumerator in an infinite loop, i think one can simply put InvokeRepeating in the Start() method to do the job. It looks more elegant and you can stop the invoking instantly with CancelInvoke instead of waiting for the next yield instruction. \$\endgroup\$ – S. Tarık Çetin Feb 19 '16 at 15:51
0
\$\begingroup\$

Well, you change the movement vector every frame. Invoke just adds one second delay to the call, but you still call it every frame. You could do

 if(!IsInvoking("randomDirection"){
    Invoke("randomDirection",1);
 }

This way you only schedule a new change if the last one is done. But in my opinion you should not be using Invoke, it leads to very unreadable code. Make a timer yourself like this:

float remainingTime=0;
void Update(){
    remainingTime -= Time.deltaTime;
    if(remainingTime <0f){
       remainingTime=1f;
       randomDirection();
    }
    //Move code as you did.
}
\$\endgroup\$
  • \$\begingroup\$ Why are you putting this burden in Update? while you have invoke and coroutine? any reason for this extra calculations? \$\endgroup\$ – Hamza Hasan Feb 19 '16 at 20:38

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.