天天看点

Unity3D+moba+小地图视野

1功能描述

敌方出现在我方视野中,小地图显示敌方icon。丢失敌方时,icon消失。类似moba游戏,要满足以下要点:

1.所有己方单位自身都要在小地图上显示。

2.所有己方单位共享视野,当有敌方出现在某个己方单位的视野中时,小地图上显示这个敌方icon。

3.敌方一旦丢失在所有己方单位视野中,小地图上icon消失。

2 详细设计

总体思路是对地形分成二维数组int[N][[N],作为己方的视野权值打分。每个单位所在的世界坐标转化为在地形数组中坐标x,y,每个己方单位的视野以自身为中心探测到格子。每帧检测,上一帧的该单位探测到所有小方块权值-1,当前帧该单位探测到小方块权值+1。当敌人的x,y落在在权值>0的小方块中,说明被探测到了(被谁探测到了不管,己方单位共性视野)。

Unity3D+moba+小地图视野

某一帧,我的视野包括的小方块(绿色框内包含N个小方块)权值为1,队友视野包块的小方块权值为1,两人重叠的部分为2.只要敌人的x,y在权值>0的小方块,说明要出现在视野中了。

2.1 数据初始化

void viewDataInit()
    {
        m_gridLen = (int)(m_mapSize / m_gridSize);
        m_gridCampUnitCnt = new int[m_gridLen, m_gridLen];
        m_gridUnitInView = new List<UnitCtrl>();

        for (int i = 0; i < m_gridLen; i++)
        {
            for (int j = 0; j < m_gridLen; j++)
            {
                m_gridCampUnitCnt[i, j] = 0;
            }
        }
}      

m_mapSize:地形尺寸。m_gridSize:每个格子的世界坐标大小。m_gridCampUnitCnt:权值二维数组。m_gridUnitInView:所有需要显示在小地图上的单位(包含敌方和我方)。

2.2单位出生时

public void Respawn(UnitCtrl unitCtrl)
    {
        m_unitCtrl = unitCtrl;

        m_gridSize = MainMgr.self.m_gridSize;//每一格所占的尺寸(世界坐标)
        m_gridViewXLen = (int) (m_unitCtrl.m_viewXLen/m_gridSize);//我x方向上能看到的格子数量
        m_gridViewYLen = (int) (m_unitCtrl.m_viewYLen/m_gridSize);

        m_gridX = (int)(m_unitCtrl.transform.position.x/m_gridSize);
        m_gridY = (int) (m_unitCtrl.transform.position.z/m_gridSize);

        if (MainMgr.self.isInRange(m_gridX) && MainMgr.self.isInRange(m_gridY))
        {(MainMgr.self.m_gridAllUnit[m_gridX,m_gridY]).Add(m_unitCtrl);}

        m_maxLen = MainMgr.self.m_gridLen - 1;
        if (m_unitCtrl.m_camp == MainMgr.self.m_camp)//如果是同一阵营的,unit视野下的方块权值+1
        {
            for (int x = m_gridX - m_gridViewXLen; x <= m_gridX + m_gridViewXLen; x++)
            {
                if (x >= 0 && x <= m_maxLen)
                {
                    for (int y = m_gridY - m_gridViewYLen; y <= m_gridY + m_gridViewYLen; y++)
                    {
                        if (y >= 0 && y <= m_maxLen)
                        {
                            MainMgr.self.m_gridCampUnitCnt[x, y]++;//权值加1
                        }
                    }
                }
            }
            unitShowInMiniMap();
        }
        StartCoroutine("yieldUpdataGrid");
}      

单位出生时,如果是我方阵营时,他包含的所有小格子权值+1,并且自身要显示在小地图上。出生后开启yieldUpdataGrid的协同函数.

2.3单位移动时

所有处理在yieldUpdataGrid中。

当单位为我方阵营时,每个小格子权值的要做改变。

//当前所在格子
        int gridX = (int)(m_unitCtrl.transform.position.x / m_gridSize);
        int gridY = (int)(m_unitCtrl.transform.position.z / m_gridSize);

        //与上一帧所在格子做比较
        int offsetX = gridX - m_gridX;
        int offsetY = gridY - m_gridY;


        if (m_unitCtrl.m_camp == MainMgr.self.m_camp) //跟我是同一阵营的,更新地图小格子的权值
        {
            if (offsetX > 0) //向右走
            {
                int left = m_gridX - m_gridViewXLen;
                int right = m_gridX + m_gridViewXLen + 1;
                for (int x = 0; x < offsetX; x++)
                {
                    for (int y = m_gridY - m_gridViewYLen; y <= m_gridY + m_gridViewYLen; y++)
                    {
                        if (MainMgr.self.isInRange(y))
                        {
                            if (MainMgr.self.isInRange(left + x))
                                MainMgr.self.m_gridCampUnitCnt[left + x, y]--;
                            if (MainMgr.self.isInRange(right + x))
                                MainMgr.self.m_gridCampUnitCnt[right + x, y]++;
                        }
                    }
                }
            }
            else if (offsetX < 0) //向左走
            {
                int left = m_gridX - m_gridViewXLen - 1;
                int right = m_gridX + m_gridViewXLen;
                for (int x = 0; x > offsetX; x--)
                {
                    for (int y = m_gridY - m_gridViewYLen; y <= m_gridY + m_gridViewYLen; y++)
                    {
                        if (MainMgr.self.isInRange(y))
                        {
                            if (MainMgr.self.isInRange(right + x))
                                MainMgr.self.m_gridCampUnitCnt[right + x, y]--;
                            if (MainMgr.self.isInRange(left + x))
                                MainMgr.self.m_gridCampUnitCnt[left + x, y]++;
                        }
                    }
                }
            }

            if (offsetY > 0) //向上走
            {
                int top = m_gridY + m_gridViewYLen + 1;
                int bottom = m_gridY - m_gridViewYLen;
                for (int y = 0; y < offsetY; y++)
                {
                    for (int x = gridX - m_gridViewXLen; x <= gridX + m_gridViewXLen; x++)
                    {
                        if (MainMgr.self.isInRange(x))
                        {
                            if (MainMgr.self.isInRange(bottom + y))
                                MainMgr.self.m_gridCampUnitCnt[x, bottom + y]--;
                            if (MainMgr.self.isInRange(top + y))
                                MainMgr.self.m_gridCampUnitCnt[x, top + y]++;
                        }
                    }
                }
            }
            else if (offsetY < 0) //向下走
            {
                int top = m_gridY + m_gridViewYLen;
                int bottom = m_gridY - m_gridViewYLen - 1;
                for (int y = 0; y > offsetY; y--)
                {
                    for (int x = gridX - m_gridViewXLen; x <= gridX + m_gridViewXLen; x++)
                    {
                        if (MainMgr.self.isInRange(x))
                        {
                            if (MainMgr.self.isInRange(top + y))
                                MainMgr.self.m_gridCampUnitCnt[x, top + y]--;
                            if (MainMgr.self.isInRange(bottom + y))
                                MainMgr.self.m_gridCampUnitCnt[x, bottom + y]++;
                        }
                    }
                }
            }
        }      

主要处理为上一帧的包含的所有小格子权值-1,当前帧包含的所有小格子权值-1.MainMgr.self.isInRange是判断游标有没越界。

当单位为敌方单位时:

if (m_unitCtrl.m_camp != MainMgr.self.m_camp)//如果单位和我是不同阵营的
        {
            if (MainMgr.self.isInRange(gridX) && MainMgr.self.isInRange(gridY))
            {
                if (MainMgr.self.m_gridCampUnitCnt[gridX, gridY] > 0)
                {
                    unitShowInMiniMap();
                }
                else
                {
                    unitHideInMinimap();
                }
            }
        }      

3 运行情况

Unity3D+moba+小地图视野

我没探测到敌方A,敌方B,但队友探测到敌方A了,所以小地图上显示3个点(我,队友,敌方B)。

Unity3D+moba+小地图视野

我移动了探测到了敌方B,所以小地图上显示4个点(我,队友,敌方A,B)。

继续阅读