0
\$\begingroup\$

the scaling and rotating both are working.

if the automatic flag bool is false and i press the G key each time i can see that the cube is scaling and rotating to the end for example if it's rotating down then the cube scale to the minSize 0.1,0.1,0.1 and rotation 0,180 or -180,0 same for maxSize.

the problem is when the automatic flag. bool variable is set to true. then the cube is scaling down/up nonstop and i can see that the cube whether scaling down or up is never finish the scaling and rotating to each direction. near the end it's starting scaling and rotating back to the other direction.

why when it's automatically scaling and rotating it's not reach exactly to the end each cycle?

using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
 
public class Scaling : MonoBehaviour
{
    public GameObject objectToScale;
    public float duration = 1f;
    public Vector3 minSize;
    public Vector3 maxSize;
    public bool scaleUp = false;
    public Coroutine scaleCoroutine;
 
    public bool automatic = false;
    public bool coroutineIsRunning = false;
 
    private void Start()
    {
 
    }
 
    private void Update()
    {
        if (automatic)
        {
            if (!coroutineIsRunning)
            {
                Scale();
            }
        }
        else
        {
            if (Input.GetKeyDown(KeyCode.G))
            {
                Scale();
            }
        }
    }
 
    private void Scale()
    {
        scaleUp = !scaleUp;
 
        if (scaleCoroutine != null)
        {
            StopCoroutine(scaleCoroutine);
        }
 
        scaleCoroutine = StartCoroutine(ScaleOverTime(objectToScale, scaleUp ? maxSize : minSize, duration, scaleUp));
    }
 
    int c = 0;
    private IEnumerator ScaleOverTime(GameObject targetObj, Vector3 toScale, float duration, bool isScalingUp)
    {
        float counter = 0;
        Vector3 startScaleSize = targetObj.transform.localScale;
        Quaternion startRotation = targetObj.transform.rotation;
 
        // Generate a random angle (0 or 1)
        int randomAngle = Random.Range(0, 2);
        // Set the rotation angle based on the random value
        float t = (randomAngle == 0) ? 180f : -180f;
 
        // Choose the end rotation based on the scaling direction and apply randomization for both up and down scaling
        Quaternion endRotation = isScalingUp ? Quaternion.Euler(0, 0, 0) : Quaternion.Euler(0, t, 0);
 
        coroutineIsRunning = true;
 
        while (counter <= duration)
        {
            counter += Time.deltaTime;
            float lerpFactor = Mathf.Clamp01(counter / duration); // Ensure lerp factor is clamped.
 
            targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, lerpFactor);
            targetObj.transform.rotation = Quaternion.Lerp(startRotation, endRotation, lerpFactor);
 
            // Just before the loop finishes, ensure we reach the exact final values
            if (counter >= duration - Time.deltaTime)
            {
                targetObj.transform.localScale = toScale;
                targetObj.transform.rotation = endRotation;
            }
 
            yield return null;
        }
 
        coroutineIsRunning = false;
 
        // Signal end of animation for pause, etc.
        c++;
        Debug.Log("Finished! " + c);
        if (c == 2)
        {
            //Time.timeScale = 0; // Consider using a pause method that doesn't affect Time.timeScale for more complex games
        }
    }
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I'm not well-versed in Unity C# scripting, but I'm guessing your Scale() function starts a process that changes your scale over time. Thus, if you were to call this function each frame, it would start scaling, get to a certain point and start again on the next frame. Now, if you set automatic = true, this is essentially what you would get.

My guess on the reason you are confused is because you don't get this behavior in the other branch (if automatic = false) but you think it should have the same behaviour. The reason it doesn't behave the same is because Input.GetKeyDown() is not constant the way automatic is.

From Unity's Documentation :

Returns true during the frame the user starts pressing down the key identified by name. Call this function from the Update function, since the state gets reset each frame. It will not return true until the user has released the key and pressed it again.

So it only is true on the first frame of you pressing the key down. To test this, you click the key quickly and see that the process continues even when you release it. If you clicked it multiple times quickly, it should replicate the buggy behaviour you see when àutomatic = true.

To fix this, you either need to replicate the behaviour of Input.GetKeyDown() by setting automatic = false once you call Scale() or rework your code to get another behavior.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Just to add there's an Input.GetKey() which returns true if currently pressed, not only on the first frame. \$\endgroup\$
    – Basic
    Commented Apr 7 at 22:37
  • \$\begingroup\$ i found that if i add a waitforseconds(0.5f) after the line targetObj.transform.rotation = endRotation; then it will work fine when it's in automatic mode but then also it will looks and be less natural smooth because there is a slight waiting time 0.5 at each direction. so it's not optimal solution. \$\endgroup\$
    – Daniel Lip
    Commented Apr 7 at 23:03
  • \$\begingroup\$ Unfortunatly, explaining this specific behaviour is getting out of my capacities. \$\endgroup\$
    – Gyoo
    Commented Apr 7 at 23:19

You must log in to answer this question.

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