You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让foreach循环内第二个if语句中的代码仅执行一次?

问题解决:碰撞检测时重复打开窗体的问题

问题根源

你的代码在定时器触发的moveTimerEvent方法中,遍历所有控件时每遇到一个与pictureBox1碰撞的portal标签PictureBox,就会创建并打开一次Form2。如果界面中有多个portal控件,或者单次遍历中多次触发碰撞判断,就会导致重复打开。另外,即使添加break,如果没有先停止定时器,后续定时器触发还会再次执行这段逻辑,且break位置不对也无法立即终止循环。

修复方案

方案1:优化遍历逻辑,找到碰撞后立即终止循环并停止定时器

修改后的代码:

private void moveTimerEvent(object sender, EventArgs e)
{
    // 移动逻辑保持不变
    if (moveLeft == true && pictureBox1.Left > 10)
    {
        pictureBox1.Left -= speed;
    }
    if (moveRight == true && pictureBox1.Left < 1850)
    {
        pictureBox1.Left += speed;
    }
    if (moveUp == true && pictureBox1.Top > 10)
    {
        pictureBox1.Top -= speed;
    }
    if (moveDown == true && pictureBox1.Top < 962)
    {
        pictureBox1.Top += speed;
    }

    // 碰撞检测逻辑优化
    bool portalHit = false;
    foreach (Control x in this.Controls)
    {
        if (x is PictureBox pb)
        {
            if (pb.Tag == "wall")
            {
                if (pictureBox1.Bounds.IntersectsWith(pb.Bounds))
                {
                    pictureBox1.Location = new Point(123, 962);
                }
            }
            else if (pb.Tag == "portal")
            {
                if (pictureBox1.Bounds.IntersectsWith(pb.Bounds))
                {
                    portalHit = true;
                    break; // 找到第一个碰撞的portal就终止遍历
                }
            }
        }
    }

    // 只在检测到碰撞时执行一次窗体切换
    if (portalHit)
    {
        ((Timer)sender).Stop(); // 停止定时器,防止后续再次触发
        Form2 f2 = new Form2();
        f2.Show();
        this.Hide();
    }
}

方案2:使用LINQ简化碰撞检测(更简洁)

利用LINQ直接查询第一个符合条件的portal控件,避免遍历整个控件集合:

private void moveTimerEvent(object sender, EventArgs e)
{
    // 移动逻辑保持不变
    if (moveLeft == true && pictureBox1.Left > 10)
    {
        pictureBox1.Left -= speed;
    }
    if (moveRight == true && pictureBox1.Left < 1850)
    {
        pictureBox1.Left += speed;
    }
    if (moveUp == true && pictureBox1.Top > 10)
    {
        pictureBox1.Top -= speed;
    }
    if (moveDown == true && pictureBox1.Top < 962)
    {
        pictureBox1.Top += speed;
    }

    // 查询第一个碰撞的portal
    var hitPortal = this.Controls.OfType<PictureBox>()
        .FirstOrDefault(p => p.Tag?.ToString() == "portal" && pictureBox1.Bounds.IntersectsWith(p.Bounds));

    if (hitPortal != null)
    {
        ((Timer)sender).Stop();
        Form2 f2 = new Form2();
        f2.Show();
        this.Hide();
    }
}

关键修改点

  • 停止定时器:在打开新窗体前停止定时器,避免后续定时器触发再次执行碰撞检测逻辑。
  • 单次判断:将窗体切换逻辑从遍历循环中移出,只在确认碰撞后执行一次。
  • 终止遍历:找到第一个碰撞的portal后立即终止循环,避免重复判断。

内容的提问来源于stack exchange,提问作者Alexios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:25:52