2020-12-04【tips】在循环中动态添加移除元素

2020-12-17  本文已影响0人  持刀的要迟到了

这种操作是危险操作,如无必要尽量避免。

但是当需求出现的时候,如何处理?
1.使用数组而不是列表。(涉及到大量的增加移除,数组性能好一点)
2.增加:向数组的最后面添加,更新活跃数量。
3.移除:移除元素,把后面的所有元素前移一位,更新活跃数量。
4.遍历操作:
由于c#是单线程,所以在遍历的时候增添移除了元素,那么只能是在遍历的代码中进行了增添和移除。
因此在更新前后比较激活元素数量。如果元素减少了,那么说明元素被移除了。更新for循环的id。
5.例子如下,注意事项及可能问题也在代码中

    private int m_ActiveBulletCount;
    private Bullet[] m_FrameBulletList;

    private int m_MaxBulletCount = 200;

    public void FrameUpdate()
    {
        var count = m_ActiveBulletCount;

        for (int i = 0; i < count; ++i)
        {
            var prevCount = m_ActiveBulletCount;
            if (m_FrameBulletList[i].Enabled)
            {
                m_FrameBulletList[i].FixedUpdate();     //i=5
            }

            // 执行一次后,数量可能发生变化。
            // 如果移除了后面的,包括自己本身,那不会出bug。
            // 如果要移除前面的,那就会出bug:因为数组整体前移,会导致有的子弹不会被帧推。
            // 所以不要连锁销毁子弹,子弹的销毁必须在自己的FixedUpdate中执行。
            // 如果有类似需求:给子弹加一个toDelete标志,在被帧推的下一帧自我销毁。
            if (m_ActiveBulletCount < prevCount)
            {
                var diff = prevCount - m_ActiveBulletCount; //10-9=1
                count -= diff;  //9
                i = Mathf.Max(i - diff, 0); //i=4  ++4=5
            }
        }
    }


    // 添加,向数组最后一个地方添加
    public void Regist(Bullet bullet)
    {
        if (bullet == null) return;

        if (m_ActiveBulletCount >= m_MaxBulletCount)
        {
            Debug.LogError("Error: 子弹数量超过数组大小,增大数组容量或者进行其他优化");
            return;
        }

        // 异常判断,todo:删掉,比较占用资源
        for (int i = 0; i < m_ActiveBulletCount; i++)
        {
            if(m_FrameBulletList[i] == bullet)
            {
                Debug.LogError("注册了重复子弹,检查bug。"); 
                return;
            }
        }

        m_FrameBulletList[m_ActiveBulletCount] = bullet;
        m_ActiveBulletCount++;
    }

    // 移除,把后面的数组挪到前面位置来。更新当前活跃数量
    public void UnRegist(Bullet bullet)
    {
        if (bullet == null) return;

        var removeIndex = -1;
        for (int i = m_ActiveBulletCount - 1; i >= 0; --i)
        {
            if (m_FrameBulletList[i] == bullet)
            {
                removeIndex = i;
                break;
            }
        }

        if(removeIndex != -1)
        {
            // 数组元素整体前移
            for (int j = removeIndex + 1; j < m_ActiveBulletCount; ++j)
            {
                m_FrameBulletList[j - 1] = m_FrameBulletList[j];
            }
            m_ActiveBulletCount--;
            m_FrameBulletList[m_ActiveBulletCount] = null;
        }
    }
上一篇下一篇

猜你喜欢

热点阅读