1
\$\begingroup\$

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:

using UnityEngine;

/*
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"
*/

public class ParallaxSpriteDynamic : MonoBehaviour
{
public Transform background;
Transform m_rightSideOfBackground, m_leftSideOfBackground;
float length, startPosX, startPosY;
public Transform cam;
float x, y, aspect, worldHeight, worldWidth, var1, var2;
public Vector2 minMaxParallaxValues;
public float maxHeight = 500, scrollSpeed, parallaxEffect;
bool scrollingBackground = false;
public bool freeze = false;
public float temp;

void Start()
{
    parallaxEffect = minMaxParallaxValues.x;
    Setup();
}

void Setup()
{
    Camera main_Cam = cam.GetComponent<Camera>();
    if (background == null)
        background = transform;

    length = background.GetComponent<SpriteRenderer>().bounds.size.x;

    aspect = (float)Screen.width / Screen.height;
    worldHeight = main_Cam.orthographicSize * 2;
    worldWidth = worldHeight * aspect;

    var1 = (minMaxParallaxValues.y - minMaxParallaxValues.x) / maxHeight;

    float swdsw = Mathf.Ceil((worldWidth / length) + 1); //swdsw = screen width divided by sprite width

    bool toTheLeft = false;
    float rightLength = length;
    float leftLength = length;
    bool flipX = background.GetComponent<SpriteRenderer>().flipX;
    bool flipY = background.GetComponent<SpriteRenderer>().flipY;
    Sprite sprite = background.GetComponent<SpriteRenderer>().sprite;
    Color spriteColour = background.GetComponent<SpriteRenderer>().color;
    int spriteSortOrder = background.GetComponent<SpriteRenderer>().sortingOrder;
    int layer = background.transform.gameObject.layer;
    for (int a = 1; a < swdsw; a++)
    {
        GameObject extraBackground = new GameObject(background.name + " " + a);

        SpriteRenderer newSpriteRend = extraBackground.AddComponent<SpriteRenderer>();
        newSpriteRend.sprite = sprite;
        newSpriteRend.flipX = flipX;
        newSpriteRend.flipY = flipY;
        newSpriteRend.color = spriteColour;
        newSpriteRend.sortingOrder = spriteSortOrder;
        extraBackground.transform.SetParent(background.transform);
        extraBackground.transform.localScale = Vector3.one;
        extraBackground.transform.localRotation = new Quaternion(0, 0, 0, 0);
        extraBackground.layer = layer;
        if (toTheLeft == false)
        {
            extraBackground.transform.position = new Vector3(background.transform.position.x + (rightLength), background.transform.position.y, background.transform.position.z);
            rightLength += length;
            toTheLeft = true;
        }
        else
        {
            extraBackground.transform.position = new Vector3(background.transform.position.x - (leftLength), background.transform.position.y, background.transform.position.z);
            leftLength -= length * -1;
            toTheLeft = false;
        }
    }

    GameObject rightSideOfBackground = new GameObject(background.name + "(Right)");
    m_rightSideOfBackground = rightSideOfBackground.transform;
    m_rightSideOfBackground.transform.SetParent(background.transform);
    GameObject leftSideOfBackground = new GameObject(background.name + "(Left)");
    m_leftSideOfBackground = leftSideOfBackground.transform;
    m_leftSideOfBackground.transform.SetParent(background.transform);

    if (swdsw % 2 == 1) // Is odd
    {
        m_rightSideOfBackground.position = new Vector3(background.transform.position.x + (length / 2), background.transform.position.y, background.transform.position.z);
        m_leftSideOfBackground.position = new Vector3(background.transform.position.x - (length / 2), background.transform.position.y, background.transform.position.z);
    }
    else if (swdsw % 2 == 0) // Is even
    {
        m_rightSideOfBackground.position = new Vector3(background.transform.position.x + length, background.transform.position.y, background.transform.position.z);
        m_leftSideOfBackground.position = new Vector3(background.transform.position.x, background.transform.position.y, background.transform.position.z);
    }

    if (background.name.Contains("Scroll") || background.name.Contains("scroll"))
        scrollingBackground = true;

    var2 = var1 * cam.position.y;
    parallaxEffect = minMaxParallaxValues.x + var2;

    startPosX = background.position.x;
    startPosY = background.position.y;
}

void LateUpdate()
{
    if (freeze == false)
    {
        if (cam.position.y <= maxHeight && cam.position.y >= 0)
        {
            var2 = var1 * cam.position.y;
            parallaxEffect = minMaxParallaxValues.x + var2;
        }
        else if (cam.position.y < 0)
            parallaxEffect = minMaxParallaxValues.x;
        else if (cam.position.y > maxHeight)
            parallaxEffect = minMaxParallaxValues.y;
    }

    x = cam.position.x * parallaxEffect + startPosX;
    y = cam.position.y * parallaxEffect + startPosY;
    temp = cam.position.y - y;
    background.position = new Vector3(x, y, background.position.z);

    if (m_rightSideOfBackground.position.x < cam.position.x)
        startPosX += length;
    else if (m_leftSideOfBackground.position.x > cam.position.x)
        startPosX -= length;

    if (scrollingBackground == true)
        startPosX += scrollSpeed;
}
}

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:

using UnityEngine;

public class AutoMove : MonoBehaviour
{
public Vector3 direction;
public float speed;
public bool useUpdate = false;
public bool useFixedUpdate = false;
public bool useLateUpdate = false;
[Space]
public bool reset = false;

// Start is called before the first frame update
void Start()
{
   
}

// Update is called once per frame
void Update()
{
    if (useUpdate == true)
        transform.position += direction * Time.deltaTime * speed;
    if (reset == true)
        ResetVars();
}

// Update is called once per frame
void FixedUpdate()
{
    if (useFixedUpdate == true)
        transform.position += direction * Time.deltaTime * speed;
}

// Update is called once per frame
void LateUpdate()
{
    if (useLateUpdate == true)
        transform.position += direction * Time.deltaTime * speed;
}

void ResetVars()
{
    direction = Vector3.zero;
    speed = 0;
    reset = false;
}
}

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

(this question is also posted on the Unity forum @ https://forum.unity.com/threads/odd-behaviour-from-parallax.1221147)

\$\endgroup\$

0

You must log in to answer this question.

Browse other questions tagged .