c# - XNA 矩形交叉口

标签 c# xna

我最近开始进行 XNA 开发,过去有一些(非常有限的)经验,我决定尝试制作一个 Pong 克隆,看看我能记住多少。我知道的大部分内容都回到了我的脑海,但我在 Racket 和球之间的碰撞检测方面遇到了问题。我设置了 3 个矩形来更新位置以及我正在使用的 Sprite ,当球矩形与 bat 矩形相交时,我将球的 X 速度乘以 -1。然而,这会产生一种不寻常的效果,即球在球棒周围反弹,如 this video 所示。 .我在这里做错了什么?

这是这个项目的代码(可怜,我知道):

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Pong
{

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    System.Random generator = new Random();

    Texture2D ball;
    Texture2D bat1;
    Texture2D bat2;
    Texture2D middle;

    Vector2 midPos;
    Vector2 bat1Pos;
    Vector2 bat2Pos;
    Vector2 ballPos;
    Vector2 ballVelo;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //Load sprites
        ball = Content.Load<Texture2D>(@"sprites/pongball");
        bat1 = Content.Load<Texture2D>(@"sprites/pongbat");
        bat2 = Content.Load<Texture2D>(@"sprites/pongbat");
        middle = Content.Load<Texture2D>(@"sprites/pongmiddle");

        //Set default sprite positions
        midPos.X = (Window.ClientBounds.Width / 2) - 5;
        midPos.Y = 0;

        bat1Pos.X = 10;
        bat1Pos.Y = (Window.ClientBounds.Height/2) - 50;

        bat2Pos.X = Window.ClientBounds.Width - 20;
        bat2Pos.Y = (Window.ClientBounds.Height/2) - 50;

        ballPos.X = (Window.ClientBounds.Width / 2) - 5;
        ballPos.Y = (Window.ClientBounds.Height / 2) - 5;

        //Generate random ball velocity
        ballVelo.X = generator.Next(5,10);
        ballVelo.Y = generator.Next(4, 7);
    }

    protected override void UnloadContent()
    {

    }

    protected override void Update(GameTime gameTime)
    {


        //Update rectangle values
        Rectangle bat1Rect = new Rectangle((int)bat1Pos.X, (int)bat1Pos.Y, 10, 100);
        Rectangle bat2Rect = new Rectangle((int)bat2Pos.X, (int)bat2Pos.Y, 10, 100);
        Rectangle ballRect = new Rectangle((int)ballPos.X, (int)ballPos.Y, 10, 100);

        //Move ball
        ballPos += ballVelo;

        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();
        if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            this.Exit();

        //Bat 1 movement and restriction
        if (Keyboard.GetState().IsKeyDown(Keys.Up))
            bat1Pos.Y -= 4;

        if (Keyboard.GetState().IsKeyDown(Keys.Down))
            bat1Pos.Y += 4;

        if (bat1Pos.Y <= 0)
            bat1Pos.Y = 0;

        if (bat1Pos.Y >= Window.ClientBounds.Height - 100)
            bat1Pos.Y = Window.ClientBounds.Height - 100;


        //Bat 2 movement and restriction
        if (Keyboard.GetState().IsKeyDown(Keys.W))
            bat2Pos.Y -= 4;

        if (Keyboard.GetState().IsKeyDown(Keys.S))
            bat2Pos.Y += 4;

        if (bat2Pos.Y <= 0)
            bat2Pos.Y = 0;

        if (bat2Pos.Y >= Window.ClientBounds.Height - 100)
            bat2Pos.Y = Window.ClientBounds.Height - 100;

        //Ball movement restrictions
        if (ballPos.X <= 0)
            ballVelo.X *= -1;

        if (ballPos.Y <= 0)
            ballVelo.Y *= -1;

        if (ballPos.X >= Window.ClientBounds.Width - 5)
            ballVelo.X *= -1;

        if (ballPos.Y >= Window.ClientBounds.Height - 5)
            ballVelo.Y *= -1;


        //Collision detection between bats and ball
        if (ballRect.Intersects(bat1Rect))
        {
            ballVelo.X *= -1;
        }

        if (ballRect.Intersects(bat2Rect))
        {
            ballVelo.X *= -1;
        }

        base.Update(gameTime);
    }

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

        spriteBatch.Begin();
        spriteBatch.Draw(middle, midPos, Color.White);
        spriteBatch.Draw(bat1, bat1Pos, Color.White);
        spriteBatch.Draw(bat2, bat2Pos, Color.White);
        spriteBatch.Draw(ball, ballPos, Color.White);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}
}

最佳答案

Lyise 的解决方案会起作用,但它不会攻击问题的实际根源。在大型游戏中,您将需要更强大的解决方案,因此我将解释高级修复。

问题是当球仍在球棒内时,您正在改变 X 速度。在下一帧中,最可能的结果是球会离开,但不足以退出球棒,因此检测到新的碰撞。速度再次改变,循环重复,直到球通过低于或高于球棒离开球棒。

精确的解决方案需要将球移出球棒,然后反转速度。
选项:

  • 将球返回到帧开始时的位置。球永远不会碰到球棒。如果球速足够高或帧速率足够低,这将是显而易见的。
  • 计算球进入球棒的距离,然后从球的位置中减去该数量。// Colliding from the right
    impactCorrection = bat.Right - ball.Left;
    // Colliding from the left
    impactCorrection = bat.Left - ball.Right;
    对于加分,您可以将球移开2 * impactCorrection在 X 中,所以球在每一帧中总是行进相同的距离。
  • 关于c# - XNA 矩形交叉口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5636607/

    相关文章:

    c# - 在 Debug模式下抛出异常,但是在哪里?

    c# - 我如何在 XNA 游戏工作室中旋转 Texture2D?

    c# - 由于...,DataSet 是否比 DataReader 慢?

    c# - Monogame 中 base.Update 和 base.Draw 的功能?

    c# - 如何使用 HTML Agility pack 解析 HTML

    c# - 如何在 wpf 对话框中选择默认按钮?

    c# - 循环遍历列表以有效地找到数量最多的对象!

    c# - xna 仅绘制一次 spritebatch

    c# - 关于 Appium 的问题

    c# - 在 ASP.NET 的上下文中,为什么 Task.Run(...).Result 在调用异步方法时不会死锁?