Created
June 27, 2019 09:48
-
-
Save Vanlalhriata/4b5004ab4746149a30126204fb5ee225 to your computer and use it in GitHub Desktop.
Parallax sprites. Infinite horizontal scrolling. Moving camera. Unity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
// Move background as the camera moves, the amount (moveFactor) depending on how far ([0,inf)) it is from the player. | |
// The sprite is repeated to the left and right to accomodate infinite horizontal scrolling. Infinite scrolling is achieved | |
// by moving the 3-sprite set by steps of the sprite width whenever the camera crosses the center of the left or right sprite. | |
// Since each instance of this component may have a different moveFactor, the absolute position at which this crossing of the | |
// left or right sprite's center also differs, and is therefore a calculated value (stepThreshold). For example, stepThreshold | |
// is sprite width when Distance is 0, since the background is stationary. For Distance of 1, stepThreshold is infinity since | |
// the background moves with the camera and thus the camera is always at the center of the sprite set, never crossing the left or right centers. | |
// Note: | |
// - Place sprite objects as children to this game object. This script will move this game object and its children (including the two generated sprites) | |
// as a whole. This also allows you to position the sprite how you want it. | |
// - This game object is assumed to be at (0,0). Children sprites can be moved around as desired. | |
// - Make sure you have a main camera in the scene. | |
public class BackgroundParallax : MonoBehaviour | |
{ | |
[Tooltip("Distance of the background ranging from 0 to infinity (value of 1). Cannot be changed during runtime.")] | |
[Range(0,1)] | |
public float Distance; | |
private Transform cameraTransform; | |
private float initialCameraY; | |
private float stepThreshold; // The absolute horizontal distance at which to step-move sprites. | |
private Vector3 lastCameraPosition; | |
// The factor by which backgrounds will move wrt camera movement | |
private float moveFactor; | |
internal void Awake() | |
{ | |
cameraTransform = Camera.main.transform; | |
initialCameraY = cameraTransform.position.y; | |
lastCameraPosition = Vector3.zero; // Assuming background x and camera start at 0; | |
// moveFactor = Mathf.Sin(Distance * Mathf.PI / 2f); | |
moveFactor = Distance; | |
var spriteRenderer = GetComponentInChildren<SpriteRenderer>(); | |
if (null == spriteRenderer) | |
{ | |
Debug.LogError("BackgroundParallax: Could not find SpriteRenderer component in children."); | |
} | |
stepThreshold = spriteRenderer.bounds.size.x / (1 - moveFactor); // Derived using brute force manual regression, not logic | |
Debug.Log(stepThreshold); | |
repeatSprites(spriteRenderer); | |
} | |
internal void FixedUpdate() | |
{ | |
if (!cameraTransform.position.Equals(lastCameraPosition)) | |
{ | |
var x = getX(); | |
var y = moveFactor * (cameraTransform.position.y - initialCameraY); | |
transform.position = new Vector3(x, y, transform.position.z); | |
lastCameraPosition = cameraTransform.position; | |
} | |
} | |
private void repeatSprites(SpriteRenderer spriteRenderer) | |
{ | |
var spriteObject = spriteRenderer.gameObject; | |
var displacement = spriteRenderer.bounds.size.x; | |
// Left | |
GameObject.Instantiate( | |
spriteObject, | |
spriteObject.transform.position - new Vector3(displacement,0), | |
spriteObject.transform.rotation, | |
transform | |
); | |
// Right | |
GameObject.Instantiate( | |
spriteObject, | |
spriteObject.transform.position + new Vector3(displacement, 0), | |
spriteObject.transform.rotation, | |
transform | |
); | |
} | |
private float getX() | |
{ | |
var cameraDistance = cameraTransform.position.x; | |
var distanceFromThreshold = cameraDistance % stepThreshold; | |
var thresholdCrossed = cameraDistance - distanceFromThreshold; | |
// Treat the threshold crossed point as the (new) center and move the background according to moveFactor. | |
// The effective cameraDistance to be considered with the new center is now the distance from the threshold crossed. | |
var x = thresholdCrossed + (distanceFromThreshold * moveFactor); | |
return x; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment