In my Unity 2D Game, I need to move some items in the background, including:
- Pavement
- Street Lights
- Buildings
Then it feels like the player is moving. But actually, the items are moving backward.
Have a look at this video:
It'd be great if we automatically spawn these items & move. That's where we can get some help from a C# script. Here's how to do that:
- Create a script called "InfiniteMovingBelt.cs" in your project
- Then add the following content
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class InfiniteMovingBelt : MonoBehaviour | |
{ | |
public GameObject item; | |
public float speed = -1f; | |
public float spawnOffsetFromScreen = 1f; | |
public float destroyOffsetFromScreen = 1f; | |
public float spawnDistance = 5f; | |
public float spawnProbability = 1f; | |
private readonly List<GameObject> instances = new List<GameObject>(); | |
void Start() | |
{ | |
// Create the instance | |
MakeInitialSpawning(); | |
} | |
void Update() | |
{ | |
foreach(GameObject instance in instances.ToArray()) | |
{ | |
if (CanDestroy(instance)) | |
{ | |
Destroy(instance); | |
instances.Remove(instance); | |
continue; | |
} | |
Vector3 originalPos = instance.transform.position; | |
float posX = originalPos.x + (speed * Time.deltaTime); | |
Vector3 newPosition = new Vector3(posX, originalPos.y, originalPos.z); | |
instance.transform.position = newPosition; | |
} | |
SpawnIfNeeded(); | |
} | |
private Vector3 GetScreenSize() | |
{ | |
var screenSizePixels = new Vector3(Screen.width, Screen.height, 0); | |
return Camera.main.ScreenToWorldPoint(screenSizePixels); | |
} | |
private bool CanDestroy(GameObject i) | |
{ | |
Vector3 screenSize = GetScreenSize(); | |
return i.transform.position.x < GetDestroyX(); | |
} | |
private void SpawnIfNeeded() | |
{ | |
GameObject last = instances[instances.Count - 1]; | |
float diff = GetSpawnX() - last.transform.position.x; | |
if (diff >= spawnDistance) | |
{ | |
SpawnWithProbability(GetDefaultStartPos()); | |
} | |
} | |
private float GetSpawnX() | |
{ | |
return GetScreenSize().x + spawnOffsetFromScreen; | |
} | |
private float GetDestroyX() | |
{ | |
return -(GetScreenSize().x + destroyOffsetFromScreen); | |
} | |
private GameObject SpawnWithProbability(Vector3 startPos) | |
{ | |
bool canSpawn = Random.Range(0f, 1f) < spawnProbability; | |
if (canSpawn) | |
{ | |
return SpawnItem(startPos); | |
} | |
return SpawnItemAndHide(startPos); | |
} | |
private GameObject SpawnItem(Vector3 startPos, bool addToFront = false) | |
{ | |
GameObject instance = Instantiate<GameObject>(item, startPos, Quaternion.identity); | |
if (addToFront) | |
{ | |
instances.Insert(0, instance); | |
} else | |
{ | |
instances.Add(instance); | |
} | |
return instance; | |
} | |
private GameObject SpawnItemAndHide(Vector3 startPos) | |
{ | |
startPos.y = 10; | |
GameObject instance = Instantiate<GameObject>(item, startPos, Quaternion.identity); | |
instances.Add(instance); | |
return instance; | |
} | |
private Vector3 GetDefaultStartPos() | |
{ | |
return new Vector3( | |
GetSpawnX(), | |
gameObject.transform.position.y, | |
gameObject.transform.position.z | |
); | |
} | |
private void MakeInitialSpawning() | |
{ | |
Vector3 startPos = GetDefaultStartPos(); | |
while(startPos.x > GetDestroyX()) | |
{ | |
SpawnItem(startPos, addToFront:true); | |
startPos.x -= spawnDistance; | |
} | |
} | |
} |
- Then Create an "Empty Game Object" and add this script
After that, customize the parameters of this script as shown in the above video.
Better Solution
Since this might be a common task in 2D games, I think there is a much better solution than this. If you know a better solution, just let me know.
Top comments (0)