Unity 2D: Scaling by the Y on a game object that has animation

52 Views Asked by At

So, i'm rather new to unity and I have a problem. I have a game object that has a movement/animation script and I want the character to get smaller while it moves on Pos Y. I tried using a parent/child configuration where the script for scaling is on the parent and the sprite renderer, animator, rigid body, movement, basically everything else is on the child. It animates it but it doesn't scale it, how can I fix this?

Here are my scripts:

Scaling player:

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

public class ScalingCamera : MonoBehaviour
{
    // Start is called before the first frame update
    public float minY = 290f;
    public float maxY = 320f;
    public float minScale = 0.5f;
    public float maxScale = 2.0f;

    private Transform childTransform;
    private SpriteRenderer childSpriteRenderer;

    private void Start()
    {
        childTransform = transform.GetChild(0);

        // Check if the child exists
        if (childTransform != null)
        {
            // Check if the child has a SpriteRenderer component
            childSpriteRenderer = childTransform.GetComponent<SpriteRenderer>();

            if (childSpriteRenderer == null)
            {
                Debug.LogError("Child does not have a SpriteRenderer component.");
            }
        }
        else
        {
            Debug.LogError("No child found for scaling.");
        }
    }

    private void LateUpdate()
    {
        // Get the Y position of the character
        float yPos = transform.position.y;

        // Clamp the Y position within the specified range
        yPos = Mathf.Clamp(yPos, minY, maxY);

        // Calculate the scale based on the clamped Y position
        float scale = Mathf.Lerp(minScale, maxScale, Mathf.InverseLerp(minY, maxY, yPos));

        // Apply the scale to the child GameObject
        childTransform.localScale = new Vector3(scale, scale, 1f);


        // Optionally, apply the scale to the child's SpriteRenderer
        if (childSpriteRenderer != null)
        {
            childSpriteRenderer.size = new Vector2(childSpriteRenderer.size.x * scale, childSpriteRenderer.size.y * scale);

        }
    }
}

Movement/Animation on player

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

[DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
public class movement : MonoBehaviour
{
    [SerializeField] private int speed = 50;
    private Vector2 move;
    [SerializeField] private Animator animator;
    private Rigidbody2D rb;
    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();

    }
    private void OnMovement(InputValue value)
    {

        move = value.Get<Vector2>();
        if (move.x != 0 || move.y != 0)
        {
            animator.SetFloat("X", move.x);
            animator.SetFloat("Y", move.y);

            animator.SetBool("IsWalking", true);

        }
        else
            animator.SetBool("IsWalking", false);
    }
    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + move * speed * Time.fixedDeltaTime);
    }

    private string GetDebuggerDisplay()
    {
        return ToString();
    }
}

And a ss of my unity hierarchy:

Unity Editor

I've tried switching them around, one time the animator works, the other the scaling but never both. I checked the Script execution order, the scaling is after the animation. It has all the right tags, it doesnt have any colliders (it used to but that wasn't the problem). I also added debuggers all around and it says that it's scaling it on all steps but i don't see any difference (no, the object is big enough to see clear difference when it moves).

Any help would be appreciated !!

1

There are 1 best solutions below

1
Jens Steenmetz On

Like you already found out, you have the Rigidbody2D on the child GameObject, so only the child will move. You said you already tried putting the movement script and the Rigidbody2D onto the parent. That should work. Try to make sure that...

  1. Your ScalingCamera script is changing the localScale of the parent (not of the child, as you are doing now). So you can remove the childTransform and childSpriteRenderer variables entirely and can just use transform (you do not need the SpriteRenderer).
  2. You are referencing the Animator correctly in your movement script. I would move all components from your child to the parent (so that you do not have a child object anymore). Then you do not have to change anything in your movement script, since in your movement script, you are referencing the Animator that is on the EXACT SAME GameObject as the movement script.

Also, on a side note, for learning purposes:

  1. If you want to ensure that your ScalingCamera script has a SpriteRenderer (I think you shouldn't in this case, though, as you don't need the SpriteRenderer for the logic to work), you can add the attribute [RequireComponent(typeof(SpriteRenderer))] above your class name, like so:

    [RequireComponent(typeof(SpriteRenderer))]
    public class ScalingCamera : MonoBehaviour 
    
  2. The scaling does not have to happen after updating the Animator per se. So you do not need to use LateUpdate and can use a regular Update method instead.

  3. Changing the SpriteRenderer.size does not do anything for regular sprites. It only affects the sprite if the sprite has a Tiled or Sliced draw mode. So you can remove that code.

  4. It seems like you are creating your game entirely in the UI. This is not good practice. Don't worry about it now, but something to keep in mind for your next game :)