题4答案 -CameraAreaManager 场景物件管理

//题目:假定一个2D场景中有数量众多且分布不均匀的(10w+)gameobject,摄像机在场景中自由移动,请按照您对场景管理的理解,自定设计目标,设计一个管理机制来管理这些gameobject,可用伪代码表达,并辅以必要的文字说明。

//设计思路
//1:区域划分:将整个 Unity 2D 场景均匀地分割成 N 块区域,每个区域可以用一个矩形来表示其范围。
//2:摄像机视口区域:确定摄像机的视口所在的区域,该区域作为中心区域。
//3:渲染区域选择:除了摄像机视口所在的区域外,还选择其周围的 8 块区域,总共渲染 9 块区域,以保证画面的连贯性。
//4:GameObject 管理:为每个 GameObject 记录其所属的区域,当需要渲染时,只处理这 9 块区域内的 GameObject,上次区域的 GameObject 进行隐藏或暂停相关处理。

using UnityEngine;
using System.Collections.Generic;

// 定义区域类
public class SceneRegion
{
    public Rect regionBounds; // 区域的范围
    public Dictionary<int, GameObject> objectsInRegion; // 区域内的 GameObject 列表

    public SceneRegion(Rect bounds)
    {
        regionBounds = bounds;
        objectsInRegion = new Dictionary<int, GameObject>();
    }

    // 将 GameObject 添加到区域中
    public void AddObject(GameObject obj)
    {
        objectsInRegion.Add(obj.GetHashCode(), obj);
    }

    // 判断 GameObject 是否在区域内
    public bool ContainsObject(GameObject obj)
    {
        return objectsInRegion.ContainsKey(obj.GetHashCode());
    }
}

// 场景管理类
public class CameraAreaManager : MonoBehaviour
{
    public Camera mainCamera;
    public int numRegionsX; // X 轴方向划分的区域数量
    public int numRegionsY; // Y 轴方向划分的区域数量
    private SceneRegion[,] regions; // 存储所有区域的二维数组
    private SceneRegion cameraRegion; // 摄像机视口所在的区域
    private List<SceneRegion> regionsToRender; // 需要渲染的 9 块区域
    private List<SceneRegion> unRegionsToRender = new List<SceneRegion>();// 需要移除渲染的区域
    private int _oldXIndex = -999;
    private int _oldYIndex = -999;
    private int _intenalPace = 10000;
    private Dictionary<long, SceneRegion> _oldIndexDic = new Dictionary<long, SceneRegion>();

    private void Start()
    {
        // 初始化区域划分
        InitializeRegions();

        // 将所有 GameObject 分配到对应的区域中
        AssignObjectsToRegions();

        // 初始更新需要渲染的区域
        UpdateRegionsToRender();
    }

    private void Update()
    {
        // 摄像机移动时更新需要渲染的区域
        if (mainCamera.transform.hasChanged)
        {
            UpdateRegionsToRender();
            mainCamera.transform.hasChanged = false;
        }
    }

    private void InitializeRegions()
    {
        float sceneWidth = 1000; // 假设场景宽度
        float sceneHeight = 1000; // 假设场景高度

        float regionWidth = sceneWidth / numRegionsX;
        float regionHeight = sceneHeight / numRegionsY;

        regions = new SceneRegion[numRegionsX, numRegionsY];

        for (int x = 0; x < numRegionsX; x++)
        {
            for (int y = 0; y < numRegionsY; y++)
            {
                Rect regionBounds = new Rect(x * regionWidth, y * regionHeight, regionWidth, regionHeight);
                regions[x, y] = new SceneRegion(regionBounds);
            }
        }
    }

    private void AssignObjectsToRegions()
    {
        GameObject[] allObjects = UnityEngine.Object.FindObjectsOfType<GameObject>();

        foreach (GameObject obj in allObjects)
        {
            Vector2 position = obj.transform.position;
            int xIndex = Mathf.FloorToInt(position.x / (1000 / numRegionsX));
            int yIndex = Mathf.FloorToInt(position.y / (1000 / numRegionsY));

            if (xIndex >= 0 && xIndex < numRegionsX && yIndex >= 0 && yIndex < numRegionsY)
            {
                regions[xIndex, yIndex].AddObject(obj);
            }
        }
    }

    private void UpdateRegionsToRender()
    {
        // 获取摄像机视口所在的区域
        cameraRegion = GetCameraRegion();

        //获取上次渲染的区域
        if (_oldXIndex >= 0)
        {
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    int oldX = _oldXIndex + i;
                    int oldY = _oldYIndex + j;

                    if (oldX >= 0 && oldX < numRegionsX && oldY >= 0 && oldY < numRegionsY)
                    {
                        if (i != 0 || j != 0)
                        {
                            _oldIndexDic.Add(oldX* _intenalPace + oldY, regions[oldX, oldY]);
                        }
                    }
                }
            }
        }

        // 确定需要渲染的 9 块区域
        regionsToRender = new List<SceneRegion>();
        regionsToRender.Add(cameraRegion);

        int xIndex = GetRegionIndexX(cameraRegion.regionBounds.x);
        int yIndex = GetRegionIndexY(cameraRegion.regionBounds.y);

        _oldXIndex = xIndex;
        _oldYIndex = yIndex;
        unRegionsToRender.Clear();
        for (int i = -1; i <= 1; i++)
        {
            for (int j = -1; j <= 1; j++)
            {
                int newX = xIndex + i;
                int newY = yIndex + j;

                if (newX >= 0 && newX < numRegionsX && newY >= 0 && newY < numRegionsY)
                {
                    if (i != 0 || j != 0)
                    {
                        regionsToRender.Add(regions[newX, newY]);
                    }
                }
                if (_oldIndexDic.ContainsKey(newX * _intenalPace + newY) == true)
                {
                    _oldIndexDic.Remove(newX * _intenalPace + newY);
                }
            }
        }

        foreach (var item in _oldIndexDic)
        {
            // 隐藏或者销毁区域内和外的 GameObject
        }

        // 处理渲染区域内和外的 GameObject
        foreach (SceneRegion region in regionsToRender)
        {
            // 显示或者加载区域内 GameObject
        }
    }

    private SceneRegion GetCameraRegion()
    {
        Rect cameraBounds = GetCameraBounds();
        int xIndex = GetRegionIndexX(cameraBounds.x);
        int yIndex = GetRegionIndexY(cameraBounds.y);

        return regions[xIndex, yIndex];
    }

    private Rect GetCameraBounds()
    {
        float cameraHeight = 2f * mainCamera.orthographicSize;
        float cameraWidth = cameraHeight * mainCamera.aspect;
        Vector3 cameraPosition = mainCamera.transform.position;

        return new Rect(cameraPosition.x - cameraWidth / 2, cameraPosition.y - cameraHeight / 2, cameraWidth, cameraHeight);
    }

    private int GetRegionIndexX(float x)
    {
        return Mathf.FloorToInt(x / (1000 / numRegionsX));
    }

    private int GetRegionIndexY(float y)
    {
        return Mathf.FloorToInt(y / (1000 / numRegionsY));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值