如何让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
相关产品推荐
相关产品推荐

