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

这种操作是危险操作,如无必要尽量避免。
解决方法:把要删除的元素设置为null,在合适的轮询中清除。

非轮询清除(危险)

但是当需求出现的时候,如何处理?
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;
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Python实现: ``` class Solution: def removeElement(self, n...
    raito4阅读 1,911评论 0 0
  • 20180928-摘抄自27. 移除元素 给定一个数组 nums 和一个值 val,你需要原地**移除所有数值等于...
    moralok阅读 1,319评论 0 0
  • 题目描述:给定一个数组 nums 和一个值 val,你需要原地**移除所有数值等于 *val *的元素,返回移除后...
    bocsoft阅读 1,189评论 0 0
  • 大家都知道,不能在ArrayList的For-Each循环中删除元素。在Java的入门教程中都会写上这条。 可是为...
    南山伐木阅读 7,573评论 1 10
  • 题目:给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度...
    衣锦昼行阅读 923评论 0 0