Search Unity

Odd behaviour from parallax

Discussion in 'Scripting' started by liveswithoutfear, Jan 6, 2022.

  1. liveswithoutfear

    liveswithoutfear

    Joined:
    Sep 4, 2018
    Posts:
    11
    Hey guys. First of all I'm going to say that I'm not trying to blow my own trumpet or anything but usually I'm able to figure this stuff out on my own. But as for now I'm fully stumped. Maybe I'm having a mind melt but I cannot figure out what's causing this issue...

    The problem is with this Parallax script I've written. I want the parallax effect to be dynamic so I've written some code to adjust the value over distance, the value increases at a steady pace and never goes over the value of 1 (when 1 means the parallax effect will be in sync with the camera movement, and therefore the background will appear not to be moving by the camera viewpoint, and anything over 1 will mean the background will begin moving in the opposite direction to the camera viewpoint) feel free to whack this script onto a gameobject in your scene with a sprite renderer component on it, a lot of the code in the script deals with duplicating the sprite to ensure its wider than the camera viewport, repeatable sprites will obviously look better but try it with anything, the script also deals with repeating the sprites on the X to give an infinite background type of effect, if anyone wishes to use this code feel free, the only issue I'm having is when the camera is moving upwards and gets to around the 300 on the Y mark (if the max is set to 500) if you pause the editor you can clearly see the parallaxEffect is never more than 1, but at around 300 the background begins to move up rather than down with regards to the camera viewpoint. Here's the code:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. /*
    4. If you want a background to scroll automatically (such as clouds might) then simply add the word "scroll" in any way shape or form to the name of the gameobject"
    5. */
    6.  
    7. public class ParallaxSpriteDynamic : MonoBehaviour
    8. {
    9.     public Transform background;
    10.     Transform m_rightSideOfBackground, m_leftSideOfBackground;
    11.     float length, startPosX, startPosY;
    12.     Transform cam;
    13.     float x, y, aspect, worldHeight, worldWidth, var1, var2;
    14.     [MinMaxSlider(-1, 1)]
    15.     public Vector2 minMaxParallaxValues;
    16.     public float maxHeight = 500, scrollSpeed, parallaxEffect;
    17.     public bool setupOnlyOnEnable = false, useBackgroundCam = false;
    18.     bool scrollingBackground = false;
    19.     public bool freeze = false;
    20.     public float temp;
    21.  
    22.     void Start()
    23.     {
    24.         parallaxEffect = minMaxParallaxValues.x;
    25.         Setup();
    26.     }
    27.  
    28.     void Setup()
    29.     {
    30.         Camera main_Cam = cam.GetComponent<Camera>();
    31.         if (background == null)
    32.             background = transform;
    33.  
    34.         length = background.GetComponent<SpriteRenderer>().bounds.size.x;
    35.  
    36.         aspect = (float)Screen.width / Screen.height;
    37.         worldHeight = main_Cam.orthographicSize * 2;
    38.         worldWidth = worldHeight * aspect;
    39.  
    40.         var1 = (minMaxParallaxValues.y - minMaxParallaxValues.x) / maxHeight;
    41.  
    42.         float swdsw = Mathf.Ceil((worldWidth / length) + 1); //swdsw = screen width divided by sprite width
    43.  
    44.         bool toTheLeft = false;
    45.         float rightLength = length;
    46.         float leftLength = length;
    47.         bool flipX = background.GetComponent<SpriteRenderer>().flipX;
    48.         bool flipY = background.GetComponent<SpriteRenderer>().flipY;
    49.         Sprite sprite = background.GetComponent<SpriteRenderer>().sprite;
    50.         Color spriteColour = background.GetComponent<SpriteRenderer>().color;
    51.         int spriteSortOrder = background.GetComponent<SpriteRenderer>().sortingOrder;
    52.         int layer = background.transform.gameObject.layer;
    53.         for (int a = 1; a < swdsw; a++)
    54.         {
    55.             GameObject extraBackground = new GameObject(background.name + " " + a);
    56.  
    57.             SpriteRenderer newSpriteRend = extraBackground.AddComponent<SpriteRenderer>();
    58.             newSpriteRend.sprite = sprite;
    59.             newSpriteRend.flipX = flipX;
    60.             newSpriteRend.flipY = flipY;
    61.             newSpriteRend.color = spriteColour;
    62.             newSpriteRend.sortingOrder = spriteSortOrder;
    63.             extraBackground.transform.SetParent(background.transform);
    64.             extraBackground.transform.localScale = Vector3.one;
    65.             extraBackground.transform.localRotation = new Quaternion(0, 0, 0, 0);
    66.             extraBackground.layer = layer;
    67.             if (toTheLeft == false)
    68.             {
    69.                 extraBackground.transform.position = new Vector3(background.transform.position.x + (rightLength), background.transform.position.y, background.transform.position.z);
    70.                 rightLength += length;
    71.                 toTheLeft = true;
    72.             }
    73.             else
    74.             {
    75.                 extraBackground.transform.position = new Vector3(background.transform.position.x - (leftLength), background.transform.position.y, background.transform.position.z);
    76.                 leftLength -= length * -1;
    77.                 toTheLeft = false;
    78.             }
    79.         }
    80.  
    81.         GameObject rightSideOfBackground = new GameObject(background.name + "(Right)");
    82.         m_rightSideOfBackground = rightSideOfBackground.transform;
    83.         m_rightSideOfBackground.transform.SetParent(background.transform);
    84.         GameObject leftSideOfBackground = new GameObject(background.name + "(Left)");
    85.         m_leftSideOfBackground = leftSideOfBackground.transform;
    86.         m_leftSideOfBackground.transform.SetParent(background.transform);
    87.  
    88.         if (swdsw % 2 == 1) // Is odd
    89.         {
    90.             m_rightSideOfBackground.position = new Vector3(background.transform.position.x + (length / 2), background.transform.position.y, background.transform.position.z);
    91.             m_leftSideOfBackground.position = new Vector3(background.transform.position.x - (length / 2), background.transform.position.y, background.transform.position.z);
    92.         }
    93.         else if (swdsw % 2 == 0) // Is even
    94.         {
    95.             m_rightSideOfBackground.position = new Vector3(background.transform.position.x + length, background.transform.position.y, background.transform.position.z);
    96.             m_leftSideOfBackground.position = new Vector3(background.transform.position.x, background.transform.position.y, background.transform.position.z);
    97.         }
    98.  
    99.         if (background.name.Contains("Scroll") || background.name.Contains("scroll"))
    100.             scrollingBackground = true;
    101.  
    102.         var2 = var1 * cam.position.y;
    103.         parallaxEffect = minMaxParallaxValues.x + var2;
    104.  
    105.         startPosX = background.position.x;
    106.         startPosY = background.position.y;
    107.     }
    108.  
    109.     void LateUpdate()
    110.     {
    111.         if (freeze == false)
    112.         {
    113.             if (cam.position.y <= maxHeight && cam.position.y >= 0)
    114.             {
    115.                 var2 = var1 * cam.position.y;
    116.                 parallaxEffect = minMaxParallaxValues.x + var2;
    117.             }
    118.             else if (cam.position.y < 0)
    119.                 parallaxEffect = minMaxParallaxValues.x;
    120.             else if (cam.position.y > maxHeight)
    121.                 parallaxEffect = minMaxParallaxValues.y;
    122.         }
    123.  
    124.         x = cam.position.x * parallaxEffect + startPosX;
    125.         y = cam.position.y * parallaxEffect + startPosY;
    126.         temp = cam.position.y - y;
    127.         background.position = new Vector3(x, y, background.position.z);
    128.  
    129.         if (m_rightSideOfBackground.position.x < cam.position.x)
    130.             startPosX += length;
    131.         else if (m_leftSideOfBackground.position.x > cam.position.x)
    132.             startPosX -= length;
    133.  
    134.         if (scrollingBackground == true)
    135.             startPosX += scrollSpeed;
    136.     }
    137. }
    138.  
    Both the camera and the background sprite object start at 0 on the x and y. the "temp" float in there was simply so I could check the distance between the camera and the background on the y.
    Under minMaxParallaxValues.x I have 0.97 and minMaxParallaxValues.y I have 0.993
    Max height set to 500, what this does is starts the parallaxEffect at the the min value (0.97) and gradually increases to the max (0.993) by the time it reaches the max height (500 in this case).
    Scroll speed can be ignored, this is just if you want the background moving automatically on the X.
    The issue is happening in LateUpdate but happens in any type of update, and the reason I've added the "freeze" variable was to test freezing the parallaxEffect currently being input. However if you do this after 300 when the sprite appears to start moving up rather than down, then the sprite immediately begins going back down, I'm pulling my hair out over this. For example by the time the camera is at around 400, the parallaxEffect is about 0.9884244. If you freeze the script at the start and put this into the parallaxEffect manually, at no point will the background ever move upwards from the camera viewpoint as the camera is going up. I have a simple auto move script on my camera just to make testing easier, this is what I'm using:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class AutoMove : MonoBehaviour
    4. {
    5.     public Vector3 direction;
    6.     public float speed;
    7.     public bool useUpdate = false;
    8.     public bool useFixedUpdate = false;
    9.     public bool useLateUpdate = false;
    10.     [Space]
    11.     public bool reset = false;
    12.  
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.  
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.         if (useUpdate == true)
    23.             transform.position += direction * Time.deltaTime * speed;
    24.         if (reset == true)
    25.             ResetVars();
    26.     }
    27.  
    28.     // Update is called once per frame
    29.     void FixedUpdate()
    30.     {
    31.         if (useFixedUpdate == true)
    32.             transform.position += direction * Time.deltaTime * speed;
    33.     }
    34.  
    35.     // Update is called once per frame
    36.     void LateUpdate()
    37.     {
    38.         if (useLateUpdate == true)
    39.             transform.position += direction * Time.deltaTime * speed;
    40.     }
    41.  
    42.     void ResetVars()
    43.     {
    44.         direction = Vector3.zero;
    45.         speed = 0;
    46.         reset = false;
    47.     }
    48. }
    49.  
    I just put a 1 in the Y in Direction, and 30 in speed and tick the update bool when I'm ready to go.
    My camera is obviously set to Orthographic with a size of 10 in the camera component.

    If anyone wants a crack at this and manages to figure it out then I'll be very grateful.
    Unity version is 2020.3.20f1
     
    Last edited: Jan 7, 2022
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    First off, use code tags. Code is hard to read and harder to talk about without them, and we generally won't do more than the most cursory glance at forum code without tags.

    Second, trying to control whether something scrolls by the name of the object? Just put a checkbox on the component.

    It's probably some interaction between the scrolling code and the boundary logic
     
  3. liveswithoutfear

    liveswithoutfear

    Joined:
    Sep 4, 2018
    Posts:
    11
    Yeah my bad, I'm a bit of a novice in regards to posting on here, should be updated now. And having the scrolling background with the name was because this script was initially dealing with an array of backgrounds and only some I wanted to scroll, so the name thing made it easier. As for the parallax issue I dunno, I just can't figure it out, the code seems fine.