I am making my 2D platformer game at the moment, and I am still a beginner. I saw this tutorial on youtube in which he showed how to make an enemy a.i move. He manages to move it but he didn't show how to flip the enemy once it hits the wall because when it does, it doesn't move. How do I fix this?

Ps: He used a gameObject to flip the enemy.

Here is an example of the error I am facing enter image description here

Enemy Script

public float speed;
public float distance;
private bool movingRight = true;
private Rigidbody2D myBody;
public Transform groundDetection;
public LayerMask ground;

private void Start()
    groundDetection = this.transform;
    myBody = GetComponent<Rigidbody2D>();

void Update()
    transform.Translate(Vector2.right * speed * Time.deltaTime);

    RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, 2f, ground);

    if (groundInfo.collider == false)
        if(movingRight == true)
            transform.eulerAngles = new Vector3(0, -180, 0);
            movingRight = false;
            transform.eulerAngles = new Vector3(0, 0, 0);
            movingRight = true;
  • \$\begingroup\$ Can you try doing the transform every 30 frames instead of every frame? This seems like it would be doing transforms way too fast. \$\endgroup\$ – John Hamilton Nov 21 '19 at 9:20
  • \$\begingroup\$ How do I do that? \$\endgroup\$ – Saidus Nov 21 '19 at 11:44
  • \$\begingroup\$ Use a counter, or do it on input or some other way instead of just doing it all the time. Docs for one key press and holding a key down can be found in Unity's documents. \$\endgroup\$ – John Hamilton Nov 21 '19 at 11:49
  • \$\begingroup\$ I am not sure what you're trying to say but I just edited my post, made it understandable for you. \$\endgroup\$ – Saidus Nov 22 '19 at 13:14
  • \$\begingroup\$ Is this question still alive? It seems like the question has already been answered correctly, but no answer was accepted. Are you waiting for a more detailed answer? As @Yorik pointed out, the raycast is checking if it hits the ground, direction is Vector2(0f, -1f). It will always return true when it hits the ground. If you want to detect if it hits the wall, in your case the ground and walls are the same, then you have to make another raycast on the same layer, and this raycast should have a direction of where the player is facing, basically their transform.right vector in this case. \$\endgroup\$ – Candid Moon _Max_ Dec 22 '19 at 17:54

The Cause

There are two possible issues here:

  • The first is that if your 'if' statement is never being reached (groundInfo.Collider == true) then of course your enemy just keeps walking in the direction they're going and never turns around. I highly suspect this is the case. Your ground collision logic should have no bearing on your 'turning around' logic.

  • The second is that if your 'if' statement is always being reached (groundInfo.Collider == false) then since Update is called rapidly in succession, on the first call your code says "Oh, you're moving right? Well.. turn around!" and on the second call your code says "Oh! You're moving left? Turn around!" So every time you update you are just having them turn around. I would expect this to result in them "jiggling" rather than being just stuck to the wall, but I don't see the code here that actually modifies their position.

How to get more responses

We have no context as to what class is holding this Update function. Is this "transform" you're modifying the enemies' vector? Is this vector a member of the enemies' class?

Also, I can guarantee you haven't run your code in a debugger (or at least, with breakpoints) and as such I should be loathe to assist you. Run your code in a debugger so you can see which lines of code you're actually hitting. It's a good possibility that your whole if-statement is being skipped and if you're going to be writing software much in your life you need debugging as one of your top skills (if not the top skill!)

The Solution:

To fix this you need to test something more robust like "If I'm touching the wall AND I'm facing the wall, turn around instead"; because currently it's an infinite loop that says "If I'm touching the wall, turn around."

Additionally you need to disassociate your ground-collision logic from your 'turn around' logic.

Finally, I'd also get rid of the extraneous if statement altogether as you are doing the same thing in each case. Something more like:

movingRight = !movingRight;
transform.eulerAngles.Y += 180;

You want as few if-statements in code as you can possibly manage. Every if statement is a case you have to test for and thus more difficult to validate is working properly. It's also harder to validate by eye.

What's more? Every if-statement you have in your code is a possible bad-branch prediction which can cause immense slowdown in your problem; as if a bad-branch is predicted it can result in invalidating the cache lines that were associated with that branch. See here for some information on bad prediction. All you really need to know is that you should be in the habit of questioning if/how to remove any 'if' statement you write. Some are required, but the less the better.

  • \$\begingroup\$ I just edited my post, made it understandable for you. \$\endgroup\$ – Saidus Nov 22 '19 at 13:11
  • \$\begingroup\$ movingRight = !movingRight; transform.eulerAngles.Y += 180; doesn't work. The "Y" gives an error. \$\endgroup\$ – Saidus Nov 22 '19 at 13:11
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, 2f, ground);

It looks like you are casting a ray straight down and filtering for "ground," and if this returns false (e.g. there is no ground) then turn around. This works when the game piece gets to the edge, but not when it hits the wall (there is ground, the result is true, do nothing)

  • \$\begingroup\$ What should I do to fix it? \$\endgroup\$ – Saidus Nov 24 '19 at 3:56
  • \$\begingroup\$ Given that the game piece stops moving further to the left when striking the wall, it is obvious that you are detecting that collision somewhere else in the code beside this update loop you have shown us. Aside from extending that method, you might create a flag or message for "turn around behavior" and then set it true anywhere that turning around behavior is required, and in your game piece update, you'd take action on the flag whenever it is true. \$\endgroup\$ – Yorik Nov 26 '19 at 16:41
  • \$\begingroup\$ This is perhaps what @blurry means by "Additionally you need to disassociate your ground-collision logic from your 'turn around' logic." There are many possible locations (in the code) that would cause "turn around behavior," but you only want to actually turn around in one location in the code. \$\endgroup\$ – Yorik Nov 26 '19 at 16:41

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.