【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; // 是否完成初始化
}
效果图:
不运行状态
运行状态
本文作者:香菇0_0
本文链接:https://www.cnblogs.com/Xiang-gu/p/16900598.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步