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

C# WPF平台游戏多平台碰撞检测异常问题求助

A Level平台游戏碰撞检测异常:仅单个平台可触发弹跳,其余平台穿模

问题描述

  • 为A Level编程项目制作平台游戏,设计逻辑为玩家触碰平台时自动跳跃
  • 碰撞检测存在问题:仅能在一个平台上正常弹跳,其余平台均会出现穿模现象
  • 所有平台标签均设为platform,可排除标签匹配问题
  • 代码逻辑是遍历GameScreen中所有标签为platform的Rectangle进行碰撞检测,但实际仅能检测到一个矩形生效

原始代码

public partial class MainWindow : Window
{
    private DispatcherTimer GameTimer = new DispatcherTimer();
    private bool LeftKeyPressed, RightKeyPressed, gravity; 
    double score;
    // 该值会增加到最高Y值的5倍,让角色位置越高分数越高
    private float SpeedX, SpeedY, FrictionX = 0.88f, Speed = 1, FrictionY = 0.80f;
    // SpeedX控制水平移动,SpeedY控制垂直移动

    private void Collide(string Dir)
    {
        foreach (var x in GameScreen.Children.OfType<Rectangle>())
        {
            if (x.Tag != null)
            {
                var platformID = (string)x.Tag;
                if (platformID == "platform")
                {
                    x.Stroke = Brushes.Black;
                    Rect MeekHB = new Rect(Canvas.GetLeft(Meek), Canvas.GetTop(Meek), Meek.Width, Meek.Height);
                    Rect PlatformHB = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);
                    int Jumpcount = 1;
                    if (MeekHB.IntersectsWith(PlatformHB))
                    {
                        if (Dir == "y")
                        {
                            while (Jumpcount != 700)
                            {
                                gravity = false;
                                Jumpcount = Jumpcount + 1;
                            }
                        }
                    }
                    else
                    {
                        gravity = true;
                    }
                }
            }
        }
    }

    private void KeyboardUp(object sender, KeyEventArgs e)
    {
        // 检测'A'键是否松开
        if (e.Key == Key.A)
        {
            LeftKeyPressed = false;
        }

        if (e.Key == Key.D)
        {
            RightKeyPressed = false;
        }
    }

    private void KeyboardDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.A)
        {
            LeftKeyPressed = true;
        }

        if (e.Key == Key.D)
        {
            RightKeyPressed = true;
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        GameScreen.Focus();

        GameTimer.Interval = TimeSpan.FromMilliseconds(16);
        GameTimer.Tick += GameTick;
        GameTimer.Start();
    }
    
    private void GameTick(Object Sender, EventArgs e)
    {
        txtScore.Content = "Score: " + score;

        if (LeftKeyPressed)
        {
            SpeedX -= Speed;
        }

        if (RightKeyPressed)
        {
            SpeedX += Speed;
        }

        if (gravity == true)
        {
           SpeedY += Speed;
        }
        else if (gravity == false)
        {
            SpeedY -= Speed+50;
        }

        SpeedX = SpeedX * FrictionX;
        SpeedY = SpeedY * FrictionY;

        Canvas.SetLeft(Meek, Canvas.GetLeft(Meek) + SpeedX);
        Collide("x");
        Canvas.SetTop(Meek, Canvas.GetTop(Meek) + SpeedY);
        Collide("y");

        double maxY = 0;
        if (Canvas.GetBottom(Meek) > maxY)
        {
            maxY = Canvas.GetBottom(Meek);
        }

        score = maxY;
    }
}

问题根源

  1. gravity变量被循环覆盖:遍历平台时,每检查一个平台就会重新赋值gravity。如果最后一个遍历到的平台没有碰撞,不管之前有没有平台触发碰撞,gravity都会被设为true,导致只有最后一个平台能生效。
  2. 无效的Jumpcount循环:这个while循环只是原地计数,会瞬间执行完毕,完全起不到控制跳跃时长的作用。
  3. 碰撞后未修正玩家位置:检测到碰撞时,没有将玩家的位置调整到平台上方,导致玩家可能卡在平台内部,后续碰撞检测失效。

修复方案

修改Collide方法

private void Collide(string Dir)
{
    // 默认重力生效,只有检测到碰撞才关闭重力
    bool hasCollision = false;
    foreach (var x in GameScreen.Children.OfType<Rectangle>())
    {
        if (x.Tag != null && (string)x.Tag == "platform")
        {
            x.Stroke = Brushes.Black;
            Rect MeekHB = new Rect(Canvas.GetLeft(Meek), Canvas.GetTop(Meek), Meek.Width, Meek.Height);
            Rect PlatformHB = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

            if (MeekHB.IntersectsWith(PlatformHB))
            {
                hasCollision = true;
                if (Dir == "y")
                {
                    // 将玩家推到平台顶部,避免穿模
                    Canvas.SetTop(Meek, PlatformHB.Top - Meek.Height);
                    // 设置向上的跳跃速度,替代无效的while循环
                    SpeedY = -15f;
                }
            }
        }
    }
    // 根据是否有碰撞设置重力状态
    gravity = !hasCollision;
}

调整GameTick中的重力逻辑

去掉原有的else if (gravity == false)分支,简化为:

if (gravity)
{
   SpeedY += Speed;
}
// 跳跃速度已经在Collide中设置,无需额外处理

修复说明

  • 用hasCollision变量记录是否有任何平台碰撞,避免gravity被后续平台覆盖
  • 碰撞时直接修正玩家Y坐标到平台顶部,彻底解决穿模问题
  • 用直接设置SpeedY的方式触发跳跃,替代原来无意义的计数循环,逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:50:37