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

MonoGame中Bullet对象无法渲染显示求助(无报错)

MonoGame中Bullet对象无法绘制显示的问题

我是编程新手,在MonoGame项目里遇到Bullet对象在屏幕上不显示的问题,代码无报错但此前可正常运行。已做以下排查:

  • 验证按键检测正常
  • 回溯代码定位到之前正常运行的环节
  • 使用在线工具辅助排查
  • 检查代码功能逻辑,按键状态与检测逻辑均无明显异常,无法确定问题根源

项目核心代码

Game1类代码

namespace BlobSurvival
{
    enum Dir
    {
        Down,
        Up,
        Left,
        Right
    }
    //enum  used for direction

    public class Game1 : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;

        Texture2D playerSprite;
        Texture2D walkDown;
        Texture2D walkUp;
        Texture2D walkRight;
        Texture2D walkLeft;

        Texture2D background;
        Texture2D bullet;
        Texture2D enemy;

        Player player = new Player();
        
        Camera camera;

        //intialises the camera to follow player from the actual package

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        protected override void Initialize()
        {
            _graphics.PreferredBackBufferWidth = 1280;
            _graphics.PreferredBackBufferHeight = 720;
            _graphics.ApplyChanges();
            //changes the screen size to 1280 x 720

            this.camera = new Camera(_graphics.GraphicsDevice);
            //camera initalised in game

            base.Initialize();
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            playerSprite = Content.Load<Texture2D>("player/player");
            walkDown = Content.Load<Texture2D>("player/walkDown");
            walkLeft = Content.Load<Texture2D>("player/walkLeft");
            walkRight = Content.Load<Texture2D>("player/walkRight");
            walkUp = Content.Load<Texture2D>("player/walkUp");
            //dash is used to specify that asset was in folder
            background = Content.Load<Texture2D>("background");
            bullet = Content.Load<Texture2D>("bullet");
            enemy = Content.Load<Texture2D>("enemy");
            Enemy.Enemies.Add(new Enemy(new Vector2(100, 100), enemy));
            Enemy.Enemies.Add(new Enemy(new Vector2(700, 200), enemy));
            //spawns instance of enemy from the enemy class from list
            player.animations[0] = new SpriteAnimation(walkDown, 4, 12);
            player.animations[1] = new SpriteAnimation(walkUp, 4, 12);
            player.animations[2] = new SpriteAnimation(walkLeft, 4, 12);
            player.animations[3] = new SpriteAnimation(walkRight, 4, 12);
            // array of the different animations
            //stored in specific order so it matches with the DIR enum
            player.animation = player.animations[0];
            //initalises so the animation actually starts
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            player.Update(gameTime);
            //Updates player method every frame

            this.camera.Position = player.Position;
            // camera is equal to player position, so camera follows player

            this.camera.Update(gameTime);
            //updates camera

            foreach (Bullets bullets in Bullets.bullets)
            {
                bullets.Update(gameTime);
            }
            // loop that goes through each projectile from list 

            foreach (Enemy enemY in Enemy.Enemies)
            {
                enemY.Update(gameTime, player.Position);
            }
            // player position passes through , so the enemy knows where the player is 
            base.Update(gameTime);

            foreach(Bullets bullets in Bullets.bullets)
            {
                foreach (Enemy enemy in Enemy.Enemies) 
                { 
                 int sum = bullets.radius + enemy.radius;
                    if (Vector2.Distance(bullets.Position, enemy.Position) > sum )
                    {
                        bullets.Collided = true;
                    }
                }
            }
            Bullets.bullets.RemoveAll(p => p.Collided);

            //bullets equal Collided
            // Remove all bullets from the collection where the 'Collided' property is true

            //iterates though each bullet in this bullet list
            // for every bullet it goes through the entire list of enemies
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            _spriteBatch.Begin(this.camera);
            _spriteBatch.Draw(background,new Vector2(-500, -500), Color.White);
            foreach (Enemy enemy in Enemy.Enemies)
            {
                enemy.anim.Draw(_spriteBatch);
            }
            //Draws the enemy animations in multiple instances
            foreach (Bullets bullets in Bullets.bullets)
            {
                _spriteBatch.Draw(bullet, new Vector2(bullets.Position.X - 48, bullets.Position.Y - 48), Color.White);
                //CENTERS THE BULLET SO IT COMES FROM the player not the side of it
            }
            player.animation.Draw(_spriteBatch);

            //draws bullet on screen, each instance of it

            //instead of drawing the player instead it draws the animation, the parameters can be changed such as "color" in spriteAnimation
            //player.position grabs the position value from player class
            _spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

Bullets类代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace BlobSurvival
{
    internal class Bullets
    {
        public static List<Bullets> bullets = new List<Bullets>();
        //list of type bullets , since static can be accessed outside class by Bullets.bullets
        private Vector2 position;
        private int speed = 900;
        public int radius = 18;
        //bullet circle size
        private Dir direction;
        //uses the dir enum from game1
        private bool collided = false;
        //keeps track if bullet has made collision with enemy

        public Bullets(Vector2 newPos, Dir newDir)
        {
            position = newPos;
            direction = newDir;
        }

        public Vector2 Position
        {
            get
            {
                return position;
            }
        }

        public bool Collided
        {
            get { return collided; }
            set { collided = value; }
        }

        // Property representing the collision state with getter (read) and setter (write) methods
        // Getter retrieves the current state of the collision, and setter allows code in the other places update it

        //makes the position public in other classess

        public void Update(GameTime gameTime)
        { 
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            switch (direction)
            {
                case Dir.Right:
                    position.X += speed * dt;
                    break;

                case Dir.Left:
                    position.X -= speed * dt;
                    break;

                case Dir.Up:
                    position.Y -= speed * dt;
                    break;

                case Dir.Down:
                    position.Y += speed * dt;
                    break;
                    //projectile has its own speed postion utilising previous code 
            }
        }
    }
}

问题排查方向

1. 碰撞逻辑完全反转

看Game1的Update方法里的碰撞检测代码:

if (Vector2.Distance(bullets.Position, enemy.Position) > sum )
{
    bullets.Collided = true;
}

这里逻辑错误——当子弹和敌人的距离大于两者半径之和时,判定为碰撞,这会导致子弹刚创建就被标记为碰撞,随后被RemoveAll移除。正确逻辑应该是当距离小于半径和时才判定碰撞,修改为:

if (Vector2.Distance(bullets.Position, enemy.Position) < sum )
{
    bullets.Collided = true;
}

2. 子弹绘制偏移值过大

绘制子弹时使用了new Vector2(bullets.Position.X - 48, bullets.Position.Y - 48),如果bullet纹理的实际尺寸远小于96(48*2),会导致子弹被绘制到屏幕外或视野外。可以先去掉偏移,直接用bullets.Position测试是否显示,再根据纹理实际尺寸调整偏移值。

3. 子弹未被添加到列表

检查Player类的Update方法,确认按键触发时是否正确创建Bullets实例并添加到Bullets.bullets列表。比如是否有类似Bullets.bullets.Add(new Bullets(player.Position, currentDir))的代码,若缺失则列表为空,自然不会绘制子弹。

4. 重复调用base.Update(gameTime)

Game1的Update方法里调用了两次base.Update(gameTime),这会导致游戏循环逻辑异常,比如子弹更新、碰撞检测被重复执行,引发意外问题,建议移除其中一次。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:42:03