【Unity2D】循环滚动背景实现

        在2d游戏中地图通常需要有一个较大且循环的背景,通过手动一个个拼接是非常消耗性能且费工作量的,为了解决这个问题通过代码实现如下:

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

public class BackgroundLoop : MonoBehaviour
{
    private void Start()
    {
        if(_mainCamera == null)
        {
            _mainCamera = Camera.main;
        }
        _cam = _mainCamera.transform;
        _screenBounds = _mainCamera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, _cam.position.z));
        for(int i = 0; i < _levels.Length; ++i)
        {
            LoadChildObjects(_levels[i]);
        }
        _bInit = true;
    }

    private void LoadChildObjects(GameObject go)
    {
        float objWidth = go.GetComponent<SpriteRenderer>().bounds.size.x - _choke;
        int childNeeded = (int)Mathf.Ceil(_screenBounds.x * 2 / objWidth) + 2;
        GameObject clone = Instantiate(go) as GameObject;
        for(int i = 0; i <= childNeeded; ++i)
        {
            GameObject c = Instantiate(clone) as GameObject;
            var targetPos = go.transform.position;
            targetPos.x += objWidth * (i - 1);
            c.transform.position = targetPos;
            c.name = go.name + i;
            c.transform.SetParent(go.transform);
        }
        Destroy(clone);
        Destroy(go.GetComponent<SpriteRenderer>());
    }

    private void LateUpdate()
    {
        if (!_bInit) return;
        foreach (GameObject go in _levels)
        {
            RepositionChildObjects(go);
        }
    }

    private void RepositionChildObjects(GameObject go)
    {
        if(!_spritesDic.ContainsKey(go))
        {
            _spritesDic.Add(go, new List<Transform>());
            var sprites = go.GetComponentsInChildren<Transform>();
            for(int i = 1; i < sprites.Length; ++i)
            {
                _spritesDic[go].Add(sprites[i]);
            }
        }

        var children = _spritesDic[go];
        if(children.Count > 2)
        {
            Transform firstChild = children[0];
            Transform secondChild = children[1];
            Transform lastSecondChild = children[children.Count - 2];
            Transform lastChild = children[children.Count - 1];
            if (!_halfWidthDic.ContainsKey(go))
            {
                _halfWidthDic.Add(go, firstChild.GetComponent<SpriteRenderer>().bounds.extents.x - _choke);
            }
            float halfObjectWidth = _halfWidthDic[go];
            if (_cam.position.x + _screenBounds.x > lastSecondChild.transform.position.x +halfObjectWidth)
            {
                children.Remove(firstChild.transform);
                children.Insert(children.Count, firstChild.transform);
                var targetPos = firstChild.transform.position;
                targetPos.x = lastChild.transform.position.x + halfObjectWidth * 2;
                firstChild.transform.position = targetPos;
            }
            else if(_cam.position.x - _screenBounds.x < secondChild.transform.position.x - halfObjectWidth)
            {
                children.Remove(lastChild.transform);
                children.Insert(0, lastChild.transform);
                var targetPos = lastChild.transform.position;
                targetPos.x = firstChild.transform.position.x - halfObjectWidth * 2;
                lastChild.transform.position = targetPos;
            }
        }
    }

    public GameObject[] _levels; // 需要循环的背景层
    public Camera _mainCamera; // 主相机(不设置就自动获取场景中的相机)
    public float _choke = 0f; // 当背景之间出现明显的分隔线时增大此值

    Dictionary<GameObject, float> _halfWidthDic = new Dictionary<GameObject, float>();
    Dictionary<GameObject, List<Transform>> _spritesDic = new Dictionary<GameObject, List<Transform>>();
    Transform _cam;
    Vector2 _screenBounds;
    bool _bInit = false; // 是否完成初始化
}

效果图:

不运行状态

 运行状态

猜你喜欢

转载自blog.csdn.net/qq_42608732/article/details/127808100