美文网首页
2020-12-04【tips】在循环中动态添加移除元素

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

作者: 持刀的要迟到了 | 来源:发表于2020-12-17 21: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;
            }
        }
    

    相关文章

      网友评论

          本文标题:2020-12-04【tips】在循环中动态添加移除元素

          本文链接:https://www.haomeiwen.com/subject/krciwktx.html