【问题标题】:How do I reference values in an List, excluding the current element如何引用列表中的值,不包括当前元素
【发布时间】:2017-04-01 08:07:27
【问题描述】:

所以这应该很容易解决,但我不太清楚。 (我在 Visual Studios 2015 中使用 XNA。我知道它有点过时了)

我拥有的是一个敌人列表(来自一个 Enemy 类)。每个敌人都被分配了一个碰撞矩形,如果一个敌人与另一个敌人的碰撞框相交,他们就会停止移动。 我想使用类似于 for 循环的东西。

for (int i = 0; i < spawnAmount; i++)
{
    if (enemies[i].collisionRect.Intersects(enemies[].collisionRect))
        enemies[i].allActive = false;
}

所以在空白处(敌人[]应该有一个值),有没有办法使用敌人列表中的所有值(即敌人[1、2、3、4、5])减去个敌人[i]?否则敌人会检测到自己的碰撞盒并停止。它不必局限于几行,但越不复杂越好。

【问题讨论】:

    标签: c# .net xna


    【解决方案1】:

    嵌套循环...

    for (int i = 0; i < spawnAmount - 1; i++)
    {
       for (int j = i + 1; j < spawnAmount; j++)
       {
           if (enemies[i].collisionRect.Intersects(enemies[j].collisionRect))
           {
               enemies[i].allActive = false;
           }
       }
    }
    

    所以你开始穿过敌人。假设 spawnAmount 是 5。

    所以对于i = 0,您可以比较0 -&gt; 10 -&gt; 20 -&gt; 30 -&gt; 4

    i = 1,你比较1 -&gt; 21 -&gt; 31 -&gt; 4

    i = 2,你比较2 -&gt; 32 -&gt; 4

    i = 3,你比较3 -&gt; 4

    您无需比较 i=4 的任何内容,因为无论如何您都已经涵盖了它们,而且因为对于每次迭代,您都从 j 开始于 i+1,它们无论如何都不会相同。

    【讨论】:

    • 另一个小的优化可能是忽略在第二个循环中已经处于非活动状态的敌人:if (!enemies[i].allActive) continue;
    • @RufusL - 如果你这样做了,你可能需要通过 j 从 0 -> 每个 i 的 spawnAmount - 取决于一个不活跃的敌人是否会导致另一个停止?没有看到更多的上下文很难知道......
    • 我的意思是在j 循环内部——如果我们已经阻止了这个人,它只会绕过检查是否有更多碰撞的需要。但是,如果缺少其他代码,那么我明白您的意思。我的意思是break 而不是continue。 :)
    • 等等,你只是在设置enemies[i].allActive,而不是enemies[j].allActive。假设只有 12 相交(在上面的示例中)。您拥有的代码只会停止1,但2 将保持活动状态...
    • 基本上,是的。如果他们都停下来,他们就再也不会继续了,所以最好停下来(把它想象成敌人有礼貌,让对方先走)。另外,在这个例子中,你不是只检查当前 Enemy 之后的元素吗?所有的敌人都同时出现在屏幕上,所以这是否仍然涵盖了敌人击中所有其他人?还是只是在它之后产生的那些?
    【解决方案2】:

    您想使用Except LINQ 扩展(来自System.Linq)。

    唯一的问题是您需要向它传递一个集合,因此您的代码将类似于:

    Enemy[] exclusionList = new Enemy[1]; //Construct outside of loop for efficiency
    for (int i = 0; i < spawnAmount; i++)
    {
        Enemy currentEnemy = enemies[i];
        exclusionList[0] = currentEnemy;
        if (enemies.Except(exclusionList).Any(e => e.collisionRect.Intersects(currentEnemy.collisionRect))
            enemies[i].allActive = false;
    }
    

    您也许可以用一些聪明的 LINQ 完全替换 for 循环,并且还应该考虑将远处的敌人添加到排除列表中,因为您显然没有与 他们发生冲突

    @MattWhitfields 的回答实际上更有效,因为此代码会将敌人 1 与敌人 0 进行比较反之亦然,这绝对不是必需的。你可以建立一个更聪明的排除列表来解决这个问题,或者使用他描述的 for 循环。

    【讨论】:

    • 只有一件事 - 对于 XNA,一般来说,您希望避免分配 - 这将在每次运行时分配一个新的枚举器对象。
    • @MattWhitfield 我知道分配限制,但从未遇到过枚举器/foreach 的问题。不过,这当然有可能成为一个问题。
    • 如果您关心分配,最好避免使用 LINQ。有关此问题的讨论,请参阅 Roslyn code base - performance lessons (part 2)Optimising LINQ
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2018-09-26
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    相关资源
    最近更新 更多