Object instantiation doesn't work the way intended

I’m working on an infinite scroller where the player and the camera are static while the platform and the background move towards them. Once an object enters the camera for the first time, it creates a copy of itself at the right edge of the BoxCollider2D, and once it exists it, it gets destroyed.

Each of the Floor, Ceiling, Sky, Clouds and Foreground have the following script attached to them:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InfiniteScroller : MonoBehaviour
{

    // Variables to control the parallax effect
    // A value of 1 means the object will move at the same speed as the camera
    // A value of 0 means the object will not move at all
    public float parallaxCoefficient = 1;

    // Variable to store the player controller script where the speed is stored
    PlayerController playerController;

    // Collider and its properties
    BoxCollider2D col;
    float colPositionX;
    float colHalfWidth;

    // Camera and its properties
    Camera cam;
    float camPositionX;
    float camHalfWidth;

    // Variables to control the state of the object
    bool hasCreatedNewObject;
    bool visibleFirstTime;

    // Start is called before the first frame update
    void Start()
    {
        // Fetch the collider and its properties
        col = GetComponent<BoxCollider2D>();
        colPositionX = col.transform.position.x;
        colHalfWidth = col.size.x/2;

        // Fetch the camera and its properties
        cam = Camera.main;
        camPositionX = cam.transform.position.x;
        camHalfWidth = cam.aspect * cam.orthographicSize;

        // fetch the player controller, we do it in start() because fetching the player controller in update() in every frame is expensive
        playerController = GameObject.Find("Player").GetComponent<PlayerController>();

        // set the state of the object to its initial state
        hasCreatedNewObject = false;
        visibleFirstTime = CheckIsVisible();
    }

    // Update is called once per frame
    void Update()
    {
        // determine whether the object is visible
        bool visible = CheckIsVisible();

        // if the object is visible for the first time, create a new object
        if (visible)
        {
            if (!hasCreatedNewObject) {
                // create a new object
                GameObject newObject = Instantiate(gameObject, new Vector2(colPositionX + colHalfWidth, transform.position.y), Quaternion.identity);

                // set the state of the object to its initial state
                hasCreatedNewObject = true;
            }

            if (!visibleFirstTime) visibleFirstTime = true;
        }
        else
        {
            // if the object is not visible, destroy it
            if (visibleFirstTime) Destroy(gameObject);
        }
    }

    // FixedUpdate is called once per physics update
    void FixedUpdate()
    {

        // get the speed from the player controller
        float speed = playerController.speed;

        // // Move the object to the left
        transform.Translate(Vector2.left * speed * parallaxCoefficient * Time.deltaTime);
    }

    // check if the object is visible by the camera
    bool CheckIsVisible()
    {
        Plane[] planes = GeometryUtility.CalculateFrustumPlanes(cam);
        return GeometryUtility.TestPlanesAABB(planes, col.bounds);
    }
}

The result is not really what i had in mind, since the spawned objects get inside each other. Here’s the result (you can see the collider boxes overlap):

Here’s how my project hierarchy looks like:

I do see some issues in your script that could be causing these issues, you’re checking for object visibility in the Update() method, which might not be the most efficient way to handle it. Instead, you can use OnBecameVisible() and OnBecameInvisible() methods provided by Unity.

It also seems you’re instantiating a new object at the exact position of the original one. Instead, try instantiating the new object just outside the collider of the original one.

Something like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InfiniteScroller : MonoBehaviour
{
    public float parallaxCoefficient = 1;
    PlayerController playerController;
    BoxCollider2D col;
    float colHalfWidth;
    Camera cam;

    void Start()
    {
        col = GetComponent<BoxCollider2D>();
        colHalfWidth = col.size.x / 2;
        cam = Camera.main;
        playerController = GameObject.Find("Player").GetComponent<PlayerController>();
    }

    void Update()
    {
        float speed = playerController.speed;
        transform.Translate(Vector2.left * speed * parallaxCoefficient * Time.deltaTime);
    }

    void OnBecameVisible()
    {
        Vector2 spawnPosition = new Vector2(transform.position.x + colHalfWidth * 2, transform.position.y);
        Instantiate(gameObject, spawnPosition, Quaternion.identity);
    }

    void OnBecameInvisible()
    {
        Destroy(gameObject);
    }
}

Let me know if this gets your closer to what you want.