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

C#游戏开发:左键射击子弹无法持续向上移动问题排查

问题根因

你的代码存在两个核心逻辑错误:

  • 子弹位置更新代码被完全包裹在「鼠标左键刚按下」的单次触发判断分支内,该分支仅在点击发生的单帧执行一次,后续无点击操作的帧完全不会运行子弹位移逻辑,因此子弹只会在点击瞬间移动极小一段距离,必须反复点击才能逐帧推进。
  • 没有拆分「发射子弹的一次性触发逻辑」和「子弹飞行的逐帧更新逻辑」,把仅需要执行一次的初始化操作,和需要每帧运行的位移逻辑耦合在了一起,同时速度计算逻辑错误,仅在点击时计算一次速度值,无法支持持续移动。
修复方案

将功能拆分为两个完全独立的逻辑模块实现:

  1. 点击触发模块:仅在检测到左键刚按下时执行,完成子弹初始化(设置初始位置为玩家炮口坐标、标记子弹为激活状态、设置固定飞行速度),该模块仅在点击瞬间运行一次。
  2. 飞行更新模块:每帧全局执行,只要子弹处于激活飞行状态,就按照固定速度更新子弹坐标,直到子弹飞出屏幕上边界、或者碰撞到敌方单位时,将子弹重置为未激活状态等待下一次发射。

修正后的参考代码如下:

// 提前定义类成员变量
private bool isBulletActive = false;
// Y轴设为负值代表向上飞行,数值可根据需要调整移动速度
private readonly Vector2 bulletConstSpeed = new Vector2(0, -450f);
private Vector2 bulletPos;
private Rectangle bulletRec;
// 替换为你代码里实际的玩家坦克碰撞矩形变量名即可
private Rectangle playerTankRec;

private void tankShoot(GameTime gameTime)
{
    float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

    // 第一部分:点击触发发射,仅点击瞬间执行一次
    if (mouse.LeftButton == ButtonState.Pressed 
        && prevMouse.LeftButton != ButtonState.Pressed 
        && !isBulletActive)
    {
        // 初始化子弹位置到玩家坦克炮口位置
        bulletPos.X = playerTankRec.Center.X - bulletRec.Width / 2;
        bulletPos.Y = playerTankRec.Top - bulletRec.Height;
        isBulletActive = true;
    }

    // 第二部分:子弹激活状态下逐帧更新位置,和鼠标点击逻辑无关
    if (isBulletActive)
    {
        bulletPos.Y += bulletConstSpeed.Y * deltaTime;
        bulletRec.Y = (int)bulletPos.Y;

        // 子弹飞出屏幕上边界则回收
        if (bulletPos.Y + bulletRec.Height < 0)
        {
            isBulletActive = false;
        }

        // 此处可追加碰撞检测逻辑:碰撞到敌方坦克时结算伤害,同时将isBulletActive设为false回收子弹
    }

    // 更新上一帧鼠标状态
    prevMouse = mouse;
}

补充说明:如果需要支持屏幕上同时存在多颗子弹,不要用单个变量存储子弹信息,改用List<Bullet>类型的集合存储所有子弹实例:每次点击就往集合中新增一个初始化完成的子弹对象,每帧遍历集合更新所有子弹的位移,将飞出边界、碰撞到目标的子弹从集合中移除即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 04:01:23