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

