我的球和我的矩形不会正确碰撞(Monogame)

Posted

技术标签:

【中文标题】我的球和我的矩形不会正确碰撞(Monogame)【英文标题】:My ball and my rectangle wont collide properly (Monogame) 【发布时间】:2021-12-23 21:16:13 【问题描述】:

我目前正在为我的学校项目编写一个打砖块类型的游戏,并且刚刚开始使用 monogame。我在大红色矩形和球上遇到了碰撞问题。我只是无法弄清楚我的代码有什么问题我提前感谢您的所有帮助。

碰撞视频:https://youtu.be/HOuUS8bUKn4

Game1.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;

namespace TSA3

    public class Game1 : Game
    
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;

        // Platform
        Platform platform;
        Texture2D platformTexture;
        Rectangle platformRectangle;
        Color platformColor;

        // Ball
        Ball ball;
        Texture2D ballTexture;
        Rectangle ballRectangle;
        Color ballColor;
        bool ballDirectionX = true, ballDirectionY = true;

        // Enemy
        Enemy enemy;
        Texture2D enemyTexture;
        Rectangle enemyRectangle;
        Color enemyColor;

        Random random = new Random();

        public const int ScreenW = 1200, ScreenH = 720;

        public Game1()
        
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;

        

        protected override void Initialize()
        
            graphics.PreferredBackBufferWidth = ScreenW;
            graphics.PreferredBackBufferHeight = ScreenH;
            graphics.ApplyChanges();

            Window.AllowUserResizing = false;
            Window.AllowAltF4 = true;
            Window.Title = "Arkanoid";

            // Platform
            platformTexture = Content.Load<Texture2D>("platform");
            platformRectangle = new Rectangle(0, Window.ClientBounds.Height - 50, 100, 30);
            platformColor = Color.White;

            // Ball
            ballTexture = Content.Load<Texture2D>("ball");
            ballRectangle = new Rectangle(0, 0, 20, 20);
            ballColor = Color.DarkBlue;

            // Enemy
            enemyTexture = Content.Load<Texture2D>("enemyPiece");
            enemyRectangle = new Rectangle(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2, 200, 200);
            enemyColor = Color.White;

            base.Initialize();
        

        protected override void LoadContent()
        
            // Player
            platform = new Platform(platformTexture, platformRectangle, platformColor, Window.ClientBounds.Width - 100);

            // Ball
            ball = new Ball(ballTexture, ballRectangle, ballColor, Window.ClientBounds.Width - 20, Window.ClientBounds.Height - 20, ballDirectionX, ballDirectionY);

            // Enemy
            enemy = new Enemy(enemyTexture, enemyRectangle, enemyColor);

            spriteBatch = new SpriteBatch(GraphicsDevice);

        

        float spawn = 0;

        protected override void Update(GameTime gameTime)
        
            spawn += (float)gameTime.ElapsedGameTime.TotalSeconds;

            ball.ballBounce(platform.PlatformRectangle);

            Keys[] k = Keyboard.GetState().GetPressedKeys();
            foreach (Keys key in k)
            
                platform.platformMovement(key);
                break;
            

            if (Keyboard.GetState().IsKeyDown(Keys.Space) && !ball.StartGame)
                ball.StartGame = true;

            ball.ballCollision(platform.PlatformRectangle);
            ball.enemyCollision(enemy.enemyRectangle);

            base.Update(gameTime);
        


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

            spriteBatch.Begin();
            spriteBatch.Draw(ball.BallTexture, ball.BallRectangle, ball.BallColor);
            spriteBatch.Draw(platform.PlatformTexture, platform.PlatformRectangle, platform.PlatformColor);
            spriteBatch.Draw(enemy.enemyTexture, enemy.enemyRectangle, enemy.enemyColor);
            spriteBatch.End();


            base.Draw(gameTime);
        
    


Ball.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;

namespace TSA3

    public class Ball
    
        Texture2D ballTexture;
        Rectangle ballRectangle;
        Color ballColor;

        int boundaryX, boundaryY;
        bool ballDirectionX, ballDirectionY;
        bool startGame;

        public const int BALL_SPEED = 7;

        public Ball(Texture2D ballTexture, Rectangle ballRectangle, Color ballColor, int boundaryX, int boundaryY, bool ballDirectionX, bool ballDirectionY)
        
            this.ballTexture = ballTexture;
            this.ballRectangle = ballRectangle;
            this.ballColor = ballColor;
            this.boundaryX = boundaryX;
            this.boundaryY = boundaryY;
            this.ballDirectionX = ballDirectionX;
            this.ballDirectionY = ballDirectionY;

            startGame = false;
        

        public Texture2D BallTexture  get => ballTexture; 
        public Rectangle BallRectangle  get => ballRectangle; 
        public Color BallColor  get => ballColor; 
        public bool StartGame  get => startGame; set => startGame = value; 

        public void ballBounce(Rectangle platformRectangle)
        
            if (startGame)
            
                if (ballRectangle.X <= 0)
                    ballDirectionX = true;
                else if (ballRectangle.X >= boundaryX)
                    ballDirectionX = false;

                if (ballRectangle.Y <= 0)
                
                    ballDirectionY = true;
                
                else if (ballRectangle.Y >= boundaryY)
                
                    startGame = false;
                

                if (ballDirectionX)
                    ballRectangle.X += BALL_SPEED;
                else
                    ballRectangle.X -= BALL_SPEED;

                if (ballDirectionY)
                    ballRectangle.Y += BALL_SPEED;
                else
                    ballRectangle.Y -= BALL_SPEED;
            
            else
            
                ballRectangle.Location = new Point(platformRectangle.X + (platformRectangle.Width / 2) - 10, platformRectangle.Y - (ballRectangle.Height - 5));
            
        

        public void ballCollision(Rectangle platform)
        
            if (ballRectangle.Intersects(platform))
                ballDirectionY = false;    
        

        public void enemyCollision(Rectangle enemyRectangle)
        
            if (ballRectangle.Intersects(enemyRectangle))
                ballDirectionY = false;
        


    

Enemy.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;

namespace TSA3

    public class Enemy
    
        public Texture2D enemyTexture;
        public Rectangle enemyRectangle;
        public Color enemyColor;

        public bool isVisible = true;

        Random random = new Random();

        public Enemy(Texture2D enemyTexture, Rectangle enemyRectangle, Color enemyColor)
        
            this.enemyTexture = enemyTexture;
            this.enemyRectangle = enemyRectangle;
            this.enemyColor = enemyColor;
        

        public Texture2D EnemyTexture  get => enemyTexture; 
        public Rectangle EnemyRectangle  get => enemyRectangle; 
        public Color EnemyColor  get => enemyColor; 
    

Platform.cs

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

namespace TSA3

    public class Platform
    
        Texture2D platformTexture;
        Rectangle platformRectangle;
        Color platformColor;

        int boundaryX;

        public const int PLATFORM_SPEED = 10;

        public Platform(Texture2D platformTexture, Rectangle platformRectangle, Color platformColor, int boundaryX)
        
            this.platformTexture = platformTexture;
            this.platformRectangle = platformRectangle;
            this.platformColor = platformColor;
            this.boundaryX = boundaryX;
        

        public Texture2D PlatformTexture  get => platformTexture; 
        public Rectangle PlatformRectangle  get => platformRectangle; 
        public Color PlatformColor  get => platformColor; 

        public void platformMovement(Keys controls)
        
            if (controls == Keys.A && platformRectangle.X > 0)
                platformRectangle.X -= PLATFORM_SPEED;

            if (controls == Keys.D && platformRectangle.X < boundaryX)
                platformRectangle.X += PLATFORM_SPEED;
        

    

提前感谢任何愿意提供帮助的人!

【问题讨论】:

【参考方案1】:

此方法缺少必要的代码来正常运行以从任何一侧接近块:

public void enemyCollision(Rectangle enemyRectangle)

    if (ballRectangle.Intersects(enemyRectangle))
        ballDirectionY = false;

目前它的工作原理与您的平台相同:在碰撞时将 Y 方向向上设置。 这对平台很有效,因为它很薄并且靠近屏幕边缘,因此不需要其他碰撞检查。

尝试改进此方法,类似于您对屏幕边缘的球碰撞所做的操作。

这里重要的是知道红色矩形角的位置,这样你就可以计算出球在哪个位置击中矩形。

据我所知,你不可能有确切的边界,但你可以通过计算角的位置来测量相同的边界。例如,您可以使用EnemyRectangle 并获取它们的 x/y 位置,即它的左上角,而不是您可以添加矩形的宽度,并且您将拥有右上角(同样适用于高度底角)。如果根据矩形角计算球的位置,您就会知道球在哪一侧与屏幕发生碰撞。

顶部碰撞示例:

public void enemyCollision(Rectangle enemyRectangle)

    if (ballRectangle.Intersects(enemyRectangle))
    
        if (ballRectangle.x > enemyRectangle.x && 
            ballRectangle.x < enemyRectangle.x + enemyRectangle.Width && 
            ballRectangle.y > enemyRectangle.y)
             ballDirectionY = false;
    

【讨论】:

嗨。我尝试使用 ballRectangle.Right >enemyRectangle.Left 它确实发生了碰撞,但我的问题是它在我的屏幕的整个左侧而不是我的矩形上发生了碰撞。有什么办法可以得到我的矩形的确切边框? 这就是我所说的“知道红色矩形角的位置”。我已更新我的答案以添加有关矩形位置的更多信息。

以上是关于我的球和我的矩形不会正确碰撞(Monogame)的主要内容,如果未能解决你的问题,请参考以下文章

如何防止碰撞中的两个物体同时交叉

Monogame碰撞检测无法正常工作

XNA(Monogame)我需要一种简短的碰撞方式

当我的球碰到篮筐时如何加分?如何判断球与篮的触感?

SDL 中的每像素 2D 圆形碰撞检测

如何在monogame中缩小和增长一个矩形?