How do I get my left-facing and left-moving Enemy to recognize a wall and turn around?

S14: TileVania, L336: Making Enemies: How do I get my left-facing and left-moving Enemy to recognize a wall and turn around?

Unlike Rick, I wanted my first enemy to be facing Left and moving Left, so I created a left-facing sprite and animation. The problem is, it doesn’t work with the script the way his is. The only solution I found that works for an enemy walking on a platform left, then right at the edge, BUT the problem is for my enemy below who walks Left, collides with a wall (rather than a ledge) and gets stuck in an infinite one-step Left-Right, Right-Left motion.

The bottom enemy (one the left) is stuck in a perpetual Left-Right, Left-Right.

Here’s my Player.cs code, (The enemy script is another file is exactly as Rick has it, this player code being modified):

[You can ignore the added jumping animation part which works fine]


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

public class Player : MonoBehaviour

{
    // config parameters
    [SerializeField] float runSpeed = 8f;
    [SerializeField] float jumpHeight = 5f;
    [SerializeField] float climbSpeed = 5f;
    [SerializeField] Vector2 deathKick = new Vector2(25f, 25f);

    // State variables
    bool isAlive = true;

    //cached component references
    Rigidbody2D myRigidBody2D;
    Animator myAnimator;
    CapsuleCollider2D myCollider2D;
    float gravityScaleAtStart;
    BoxCollider2D playerFeet;

    // state variables

    // Use this for initialization
    void Start()
    {
        myRigidBody2D = GetComponent<Rigidbody2D>();
        myAnimator = GetComponent<Animator>();
        myCollider2D = GetComponent<CapsuleCollider2D>();
        gravityScaleAtStart = myRigidBody2D.gravityScale;
        playerFeet = GetComponent<BoxCollider2D>();
    }

    // Update is called once per frame
    void Update()
    {
        if(!isAlive) { return;  }
        // if dead then skip the remaining statements in this update function.
        // otherwise you can call these functions.

        Run();
        LookLeftOrRight();
        Jump();
        ClimbLadder();
        Die();
    }

    private void LookLeftOrRight()
    { // if the player is moving horizontally...
        bool playerHasHorizontalSpeed = Mathf.Abs(myRigidBody2D.velocity.x) > Mathf.Epsilon;
        // mathf.epsilon gives an almost zero value.

        if (playerHasHorizontalSpeed)
        {
            transform.localScale = new Vector2(Mathf.Sign(myRigidBody2D.velocity.x), 1f);
            //localScale is simply the scale parameter in inspector under transform.
            // reverse the current scaling for x axis
            // use mathf.abs to get a positive number.
            // use mathf.sign to give a negative sign or positive.
        }
    }

    private void Jump()
    {
        if (!playerFeet.IsTouchingLayers(LayerMask.GetMask("Ground")))
        { return; }

        if (CrossPlatformInputManager.GetButtonDown("Jump"))
        { // give ourselves a new y velocity:
            Vector2 jumpVelocityToAdd = new Vector2(0f, jumpHeight);
            myRigidBody2D.velocity += jumpVelocityToAdd;
        }

        // My code that gets jump animation working and stopping when it should:
        bool playerIsJumping = Mathf.Abs(myRigidBody2D.velocity.y) > Mathf.Epsilon;

        if (playerIsJumping)
        {
            myAnimator.SetBool("Jumping", true);
        } else if (!playerIsJumping)
        {
            myAnimator.SetBool("Jumping", false);
        }
    }

    private void Run()

    {
        float controlHorizontal = CrossPlatformInputManager.GetAxis("Horizontal");
        // value is between -1 (left) and 1 (right)
        Vector2 playerVelocity = new Vector2(controlHorizontal * runSpeed, myRigidBody2D.velocity.y);
        // controlHoriz * runSpeed makes it from -8 to +8
        // seems it HAS to be set manually in unity. so i matched it to 8.
        myRigidBody2D.velocity = playerVelocity;
        bool playerHasHorizontalSpeed = Mathf.Abs(myRigidBody2D.velocity.x) > Mathf.Epsilon;
        myAnimator.SetBool("Walking", playerHasHorizontalSpeed);
        // instead of this if, you could also replace the bool variable name where it says true
        // which equates to the same thing. Done this one.
        // original code: if (playerHasHorizontalSpeed) { myAnimator.SetBool("Walking", true); }
        // the new line that includes playerHas...in the SetBool has the added benefit
        // of stopping the player from having the run animation when horizontal speed stops.
    }

    private void ClimbLadder()
    {

        if (!playerFeet.IsTouchingLayers(LayerMask.GetMask("Climbing")))
        {
            myAnimator.SetBool("Climbing", false);
            // this above line ensures climbing animation is off when were not touching the ladder.
            myRigidBody2D.gravityScale = gravityScaleAtStart;
            // anytime you're not on the ladder set gravity scale to what it is normally.
            return;
        }
        myAnimator.SetBool("Jumping", false);
        // this above line sets jumping animation to false when we ARE touching the ladder.

        float controlClimbing = CrossPlatformInputManager.GetAxis("Vertical");
        // get up/down input and assign to controlClimbing variables.
        Vector2 climbVelocity = new Vector2(myRigidBody2D.velocity.x, controlClimbing * climbSpeed);
        // set climb veolcity to what it already is on x-axis, and on the y-axis, get vertical input
        // and multiply by climbSpeed which we've set to 5 for now but is serialized (editable in unity).
        myRigidBody2D.velocity = climbVelocity;
        myRigidBody2D.gravityScale = 0f;
        // set gravity of rigidbody to zero whilst on the ladder.
        bool playerIsClimbing = Mathf.Abs(myRigidBody2D.velocity.y) > Mathf.Epsilon;
        myAnimator.SetBool("Climbing", playerIsClimbing);
    }

    private void Die()
    {
        if(myCollider2D.IsTouchingLayers(LayerMask.GetMask("Enemy", "Hazards")))
        {
            isAlive = false;
            myAnimator.SetTrigger("Dying");
            GetComponent<Rigidbody2D>().velocity = deathKick;
//            playerFeet.enabled = false;
        }
    }
}

Here’s the project as it currently stands (using Unity 2018.2.14f1)

Any help would be much appreciated.

Anyone?

It’s okay I managed to fix it successfully: I redid my enemies completely, copying the tutor’s instructions exactly. Then I simply set the transform Scale’s x component to -1 in unity, keeping moveSpeed at 1. And in this way the enemy moves left and faces left first until he hits a wall or ledge and turns around correctly.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms