0
\$\begingroup\$

I'm making a 2D game with Unity. Recently, I've implemented a shooting system. I wanted to change bullets direction based on the player's facing but since the flipping code was changing the local scale based on velocity (.01 and -.01), the bullets were suspended in the air when the player was not moving but was shooting. I ended up using local scale and a bool variable but there are still some problems. Since this code was changing the local scale to 1, the player size was getting so bigger at the start of the game. I wanted the player to have a float type scale which is smaller and more suitable for my game, so I parented an empty object to the player and this solved the problem but now it shakes weirdly at the start of the game . This is a GIF that shows the shaking problem. I thought it is definitely due to the scale change but after removing that line of code, I could see it again. So it might have another reason but I don't know what is that. Also, the previous code was using Input.GetAxis (which was helpful for supporting gamepad) but now I can't seem to find a way to use it again without getting errors because the code has been changed.

In general, my goal is fixing these problems:

  • The player's shaking at the start of the game
  • A way to use Input.GetAxis to support the left analog stick and D-pad like the past
  • A flipping code that flips the player and its children but does not cause any problems for the bullets direction and shooting system

Here's my player script.

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

public class NewPlayer : PhysicsObject
{
    [Header("Attributes")]
    [SerializeField] private float jumpPower = 10;
    [SerializeField] private float maxSpeed = 1;

    [Header("References")]
    [HideInInspector] public bool isFacingLeft;

    //Singleton instantation
    private static NewPlayer instance;

    public static NewPlayer Instance
    {
        get
        {
            if (instance == null) instance = GameObject.FindObjectOfType<NewPlayer>();
            return instance;
        }
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            rb2d.velocity = new Vector2(maxSpeed, rb2d.velocity.y);

            GetComponent<SpriteRenderer>().flipX = true;

            isFacingLeft = false;
        }
      
        else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            rb2d.velocity = new Vector2(-maxSpeed, rb2d.velocity.y);

            GetComponent<SpriteRenderer>().flipX = false;

            isFacingLeft = true;
        }

        else if (grounded)
        {
            rb2d.velocity = new Vector2(0, rb2d.velocity.y);
        }

        if (Input.GetButtonDown("Jump") && grounded)
        {
            rb2d.velocity = new Vector2(rb2d.velocity.x, jumpPower);
        }

    }
}

This is from the old script where I used both velocity and local scale for flipping. (this and my current script inherit from another script called Physics Object which handles the physics and has a definition for target velocity.

  void Update()
    {
        targetVelocity = new Vector2(Input.GetAxis("Horizontal") * maxSpeed, 0);
       
        if (Input.GetButtonDown("Jump") && grounded)
        {
            velocity.y = jumpPower;
        }
        //Flip the player's localScale.x if the move speed is greater than .01 or less than -.01
        if (targetVelocity.x < -.01)
        {
            transform.localScale = new Vector2(-1, 1);
        }
        else if (targetVelocity.x > .01)
        {
            transform.localScale = new Vector2(1, 1);
        }
}
}

And this is the weapon script. Here, I used isFacingLeft parameter to change the bullets direction.

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

public class Weapon : MonoBehaviour
{
    public GameObject bullet;
    public Transform firePoint;
    private bool isShooting;
    [SerializeField]
    private float shootDelay = .5f;
    
    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            isShooting = true;
            GameObject b = Instantiate(bullet);
            b.GetComponent<Bullet>().StartShoot(NewPlayer.Instance.isFacingLeft);
            b.transform.position = firePoint.transform.position;

            Invoke("ResetShoot", shootDelay);
        }
        void ResetShoot()
        {
           
        }
    }
} 
\$\endgroup\$
2
  • \$\begingroup\$ Myself, I always put the visual representation of an object in a child object, separate from the rigidbody or colliders. That way I can do any funky transforms I want on the visual sprite or mesh, leaving the physics behaviour completely unchanged. \$\endgroup\$ – DMGregory Dec 31 '20 at 17:01
  • \$\begingroup\$ That is a very good idea, I always do this myself. I parent an empty object and then add all the parts as children. I'm aware that my problem is a little confusing because it contains several issues that are connected together. But I think I can somehow write the code in a way that solves all of these. \$\endgroup\$ – Ali Dec 31 '20 at 17:39
0
\$\begingroup\$

For flipping the player character you can use the SpriteRenderer component directly to flip the character without changing the scale.

private SpriteRenderer spriteRenderer;
void Awake()
{
    spriteRenderer = GetComponent<SpriteRenderer>();
    if (!spriteRenderer) Debug.LogError("Can't Find the Sprite Renderer");
}

void Update()
{
    if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
    {
        spriteRenderer.flipX = false;
    }
  
    else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
    {
        spriteRenderer.flipX = true;
    }
}

this will flip your character on the X axis and setting in to false will flip your character to the default side.

Alternatively, you can shoot the bullets in world space, you can read more about it here.

Basically by moving your bullets in world space they will move relative to the original (0,0,0) coordinates of unity and your bullets will not be effected by the scale or the position of the player.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for your answer. I tried this method but it didn't work for me. First, I have to say that I still see that weird shaking (although I'm not using local scale anymore) which may have another reason other than scaling. Second, my player is made of 3 parts (body and two eyes). I even deleted that empty parent and parented the body but it didn't flip. Maybe because the sprite renderer can only flip the parent not the children so this way the flipping cannot be seen. I also updated the code so you can tell me if I wrote something wrong. \$\endgroup\$ – Ali Dec 31 '20 at 16:30
  • \$\begingroup\$ @Ali So I rewrote the code a little bit, hope this might be more helpful. other than that I added a check so you can make sure you catch the SpriteRenderer correctly. This code does not change anything about the children of the object so you either need to use scale again or flip them manually. About the shaking, I don't think it is related to the object's scale but try to tell me how to recreate it, that might help. \$\endgroup\$ – Alireza Zamani Jan 1 at 16:07
  • \$\begingroup\$ Thank you for your help. If it doesn't change anything about the children, it is not the best option for me because I want to flip them as well. Actually, I don't know the reason of the shaking, so I can't tell you how to recreate it but I updated my question and shared a GIF with a simple player character with the same settings. The shaking may not be completely visible but it's there. \$\endgroup\$ – Ali Jan 1 at 20:30
0
\$\begingroup\$

Instead of setting the localScale, you can use rotation to achieve a similar effect:

transform.Rotate(Vector3.up * 180);

This will "flip" your object by rotating 180 degress around the up axis. This should help to avoid some of your scale difficulties.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for your answer. I tried this instead of the local scale, but the shaking increased sharply. That's why I think this is not the best option. I also tried transform.Rotate(Vector3.right* 180); and transform.Rotate(Vector3.left* 180); and I still had the shaking problem beside the fact that these didn't even flip the player. \$\endgroup\$ – Ali Dec 31 '20 at 16:37
  • \$\begingroup\$ Are you really sure the shaking is due to the scale change? Just guessing, but it sounds more like it might be related to those control changes you made at the same time? \$\endgroup\$ – Chris Trott Jan 1 at 14:06
  • \$\begingroup\$ No, I'm not really sure about that. But actually, just for testing, I deleted the scale change line but I was able to see the shaking again. The shaking just lasts for less than a second whenever the game starts but still it is kind of a bug. What do you mean by control changes? like removing Input.GetAxis? I would appreciate it if you could explain more. \$\endgroup\$ – Ali Jan 1 at 16:08

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.