0
\$\begingroup\$

I'm making a 2D platformer with Unity. I have an enemy patrol that shoots bullet. The enemy is working fine until it reaches to a point that should be turn around. (when collides with an obstacle or is near the ledges) The problem is that the enemy flips rapidly in this situation. Also it only shoots to the right despite its facing direction. I'm pretty sure that the problem is from either the bullet or the pistol script because the enemy completely works when the pistol game object is disabled. My goal is to make the enemy flip at those points like before while it shoots the bullets in its facing direction.

Enemy script:

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

public class Enemy : PhysicsObject
{
    [Header("Attributes")]
    private int direction = 1;
    [SerializeField] private float maxSpeed;
    [SerializeField] private LayerMask rayCastLayerMask; //Which layer do we want the raycast to interact with?
    [SerializeField] private Vector2 rayCastOffset; //Offset from the center of the raycast origin
    [SerializeField] private float rayCastLength = 2;
    bool isFacingLeft;

    [Header("References")]
    private RaycastHit2D rightLedgeRaycastHit;
    private RaycastHit2D leftLedgeRaycastHit;
    private RaycastHit2D rightWallRaycastHit;
    private RaycastHit2D leftWallRaycastHit;

    void Update()
    {
        targetVelocity = new Vector2(maxSpeed * direction, 0);

        if (targetVelocity.x < -.01)
        {
            transform.localScale = new Vector2(-1, 1);
            isFacingLeft = true;
        }
        else if (targetVelocity.x > .01)
        {
            transform.localScale = new Vector2(1, 1);
            isFacingLeft = false;
        }

        //Check for right ledge!
        rightLedgeRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x + rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down, rayCastLength);
        Debug.DrawRay(new Vector2(transform.position.x + rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down * rayCastLength, Color.blue);
        if (rightLedgeRaycastHit.collider == null) direction = -1;

        //Check for left ledge!
        leftLedgeRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x - rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down, rayCastLength);
        Debug.DrawRay(new Vector2(transform.position.x - rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down * rayCastLength, Color.green);
        if (leftLedgeRaycastHit.collider == null) direction = 1;

        //Check for right wall!
        rightWallRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.right, rayCastLength, rayCastLayerMask);
        Debug.DrawRay(new Vector2(transform.position.x, transform.position.y), Vector2.right * rayCastLength, Color.red);
        if (rightWallRaycastHit.collider != null) direction = -1;

        //Check for left wall!
        leftWallRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.left, rayCastLength, rayCastLayerMask);
        Debug.DrawRay(new Vector2(transform.position.x, transform.position.y), Vector2.left * rayCastLength, Color.magenta);
        if (leftWallRaycastHit.collider != null) direction = 1;
    }
}

Pistol script:

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

public class Pistol : MonoBehaviour
{
    [SerializeField] GameObject bullet;
    [SerializeField] Transform bulletSpawnPos;
    private bool IsShooting;

   [SerializeField] private float shootDelay = .5f;
    private bool isFacingLeft;

    void Start()
    {
        InvokeRepeating("Shoot",4f, shootDelay);
        Rigidbody2D rb = GetComponent<Rigidbody2D>();
      
    }

    void Update()
    {
       if (IsShooting) return;
        IsShooting = true;
        GameObject b = Instantiate(bullet);
        b.GetComponent<Bullet>().StartShoot(isFacingLeft);
        b.transform.position = bulletSpawnPos.transform.position;
       

        Invoke("ResetShoot", shootDelay);
    }

   void ResetShoot()
   {
      IsShooting = false;    
    }
}

Bullet script:

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

public class Bullet : MonoBehaviour
{
    [SerializeField] float speed;
    [SerializeField] int damage;
    float timeToDestroy = 3;

    public void StartShoot(bool isFacingLeft)
    {
        Rigidbody2D rb = GetComponent<Rigidbody2D>();

        if (isFacingLeft)
        {
            rb.velocity = new Vector2(-speed, 0);
        }
        else
        {
            rb.velocity = new Vector2(speed, 0);
        }

        Destroy(gameObject, timeToDestroy);
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Which way is it flipping exactly? Is it flipping on the Z axis? \$\endgroup\$ Jan 21 '21 at 14:18
0
\$\begingroup\$

Your pistol and your enemy each have their own isFacingLeft bool currently. Pistol gets never updated with the value and just uses the default one. So you need to be able to get the isFacingLeft from your Enemy script in the Pistol script. You could either

  • Have a getter for it
  • Make it public

A getter is better since the logic on when it is true or false is handled in Enemy already and we do not want other scripts be able to change the value.

Add this code to your Enemy script

public bool IsFacingLeft() {
    return isFacingLeft;
}

Updated pistol script

private Enemy _enemy;
void Start()
{
    //Getting once a reference to the enemy that is holding the pistol, you 
    //could as well assign this in the editor if you make it public
    _enemy = GetComponent<Enemy>();
    InvokeRepeating("Shoot", 4f, shootDelay);
}

void Shoot() {
    GameObject b = Instantiate(bullet);
    b.GetComponent<Bullet>().StartShoot(_enemy.IsFacingLeft());
    b.transform.position = bulletSpawnPos.transform.position;
}

The old Update code in Pistol is not needed anymore. There are no changes to the Bullet script.

\$\endgroup\$
7
  • \$\begingroup\$ Thank you for your answer! I know that there are two different isFacingLeft variables and I think this is the root of the problem. I wanted to reference this variable in the pistol script but wasn't sure what is the best way to do that. Do you have any recommendations for this? Also, I added that line of code but I don't see that much change in the enemy's behaviour. About the movement, I haven't seen any weird bugs so far. The movement works fine. As I mentioned in my question, I tested this by disabling the pistol. \$\endgroup\$
    – Ali
    Jan 17 '21 at 4:00
  • \$\begingroup\$ I'm a little confused. the start Shoot method is used in the bullet script not in the pistol script. Also, the pistol script is attached to the pistol game object which is a child of the enemy. By referencing I mean using something like GetComponent<>() in order to use the same isFacingLeft bool not another one. \$\endgroup\$
    – Ali
    Jan 17 '21 at 23:10
  • \$\begingroup\$ I updated the code. I tried to solve this problem but couldn't figure it out. I would appreciate it if you post the code that I need to write. \$\endgroup\$
    – Ali
    Jan 20 '21 at 23:38
  • \$\begingroup\$ Thank you. This solved my problem. I just have a quick question about shooting. The bullets are coming from somewhere in the middle of the scene not the from the bullet spawn pos. I dragged the spawn pos into the inspector but don't know why is this happening. \$\endgroup\$
    – Ali
    Jan 22 '21 at 4:33
  • \$\begingroup\$ @Ali that should be easy but please make a new question for that with an image as well from the setup of your objects. \$\endgroup\$
    – Zibelas
    Jan 22 '21 at 8:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .