Unity空间划分 CellSpacePartition(单元空间划分)

一个空间中个体数量大的时候就需要做一些结构进行分区以减少计算量。空间划分有很多种,本片介绍一个简单的划分方式:单元空间划分。
简单来说就是将一个空间划分成很多格子,格子中有存着个体的集合。个体运动过程中,更新所有格子的集合。
下面图片演示运动过程中格子的变化,绿色格子标识其个体集合中有>0数量的个体。
在这里插入图片描述
核心代码如下:
SpacePartition.cs

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

namespace CellSpacePartition
{
    public class Cell {
        public int id;
        public Bounds bounds;
        public List<Agent> agentList;
        public Cell(int id, Vector3 center, Vector3 size) {
            this.id = id;
            this.agentList = new List<Agent>();
            this.bounds = new Bounds(center, size);
        }
        public void RemoveAgent(Agent agent) {
            if (agentList.Contains(agent)) {
                agentList.Remove(agent);
            }
        }
        public void AddAgent(Agent agent) {
            if (!agentList.Contains(agent))
            {
                agentList.Add(agent);
            }
        }
    }
    public static class SpacePartition
    {
        static float spaceX;
        static float spaceZ;
        static int cellCountX;
        static int cellCountZ;
        static List<Cell> cellList;
        static Vector3 cellSize;
        static Vector3 cellStartPos;
        public static void Init(float spaceX, float spaceZ, Vector3 cellSize) {
            cellList = new List<Cell>();
            SpacePartition.spaceX = spaceX;
            SpacePartition.spaceZ = spaceZ;
            SpacePartition.cellSize = cellSize;
            GenerateCell();
        }

        static void GenerateCell() {
            cellCountX = (int)(spaceX / cellSize.x);
            cellCountZ = (int)(spaceZ / cellSize.z);
            cellStartPos = new Vector3(-spaceX * 0.5f + cellSize.x * 0.5f, 0, -spaceZ * 0.5f + cellSize.z * 0.5f);
            int index = 0;
            for (int i = 0; i < cellCountX; i++)
            {
                for (int j = 0; j < cellCountZ; j++)
                {
                    Vector3 center = cellStartPos + new Vector3(cellSize.x * i, 0, cellSize.z * j);
                    Cell cell = new Cell(index, center, cellSize);
                    cellList.Add(cell);
                }
            }
        }

        static int PositionIntoIndex(Vector3 pos) {
            float dx = pos.x - (spaceX * -1 * 0.5f);
            float dz = pos.z - (spaceZ * -1 * 0.5f);
            int x = (int)(dx / cellSize.x);
            int z = (int)(dz / cellSize.z);
            return x * cellCountX + z;
        }

        public static void UpdateAgentCell(Agent agent) {
            int index = PositionIntoIndex(agent.transform.position);
            if (index >= cellList.Count) {
                return;
            }
            Cell tarCell = cellList[index];
            if (agent.beloneCell == null)
            {
                agent.beloneCell = tarCell;
                tarCell.AddAgent(agent);
            }
            else {
                if (agent.beloneCell != tarCell) {
                    agent.beloneCell.RemoveAgent(agent);
                    agent.beloneCell = tarCell;
                    tarCell.AddAgent(agent);
                }
            }
        }

        public static List<Cell> GetCellList() {
            return cellList;
        }
    }
}

Agent.cs

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

namespace CellSpacePartition
{
    public class Agent : MonoBehaviour
    {
        public Cell beloneCell;
        public Vector3 moveDir;
        public float speed;
        bool isMove = false;

        void Update()
        {
            if (Input.GetMouseButtonDown(1)) {
                isMove = true;
            }
            if (Input.GetMouseButtonUp(1))
            {
                isMove = false;
            }
            if (!isMove) {
                return;
            }
            MoveTarget();
            transform.forward = moveDir;
            transform.position += moveDir * speed * Time.deltaTime;
            SpacePartition.UpdateAgentCell(this);
        }

        void MoveTarget() {
            if (Input.GetMouseButton(1))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit)) { 
                    Vector3 tarPos = new Vector3(hit.point.x, 0, hit.point.z);
                    moveDir = (tarPos - transform.position).normalized;
                }
            }
        }
    }
}

GameMain.cs

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

namespace CellSpacePartition
{
    public class GameMain : MonoBehaviour
    {
        public GameObject agentPrefab;
        public Vector2 cellSize;
        float spaceX;
        float spaceZ;
        private void Awake()
        {
            Transform plane = GameObject.Find("Plane").transform;
            spaceX = plane.localScale.x * 10;
            spaceZ = plane.localScale.z * 10;
            SpacePartition.Init(spaceX, spaceZ, new Vector3(cellSize.x, 10, cellSize.y));
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0)) {
                CreateAgent();
            }
        }

        void CreateAgent() {
            GameObject agentGO = Instantiate(agentPrefab);
            agentGO.SetActive(true);
            agentGO.transform.position = new Vector3(Random.Range(-spaceX, spaceX) * 0.5f, 0, Random.Range(-spaceZ, spaceZ) * 0.5f);
            Agent agent = agentGO.GetComponent<Agent>();
        }

        private void OnDrawGizmos()
        {
	        // 绘制格子
            List<Cell> cellList = SpacePartition.GetCellList();
            if (cellList == null) {
                return;
            }
            for (int i = 0; i < cellList.Count; i++)
            {
                Cell cell = cellList[i];
                if (cell.agentList.Count > 0)
                {
                    Gizmos.color = new Color(0, 1f, 0, 0.2f);
                    Gizmos.DrawCube(cell.bounds.center, cell.bounds.size);
                }
                else {
                    Gizmos.color = Color.white;
                    Gizmos.DrawWireCube(cell.bounds.center, cell.bounds.size);
                }
            }
        }
    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值