Пересечение прямоугольника XNA - PullRequest
1 голос
/ 12 апреля 2011

Я недавно начал заниматься разработкой XNA и, имея некоторый (очень ограниченный) опыт работы с ним в прошлом, я решил попробовать создать клон Pong, чтобы узнать, сколько я могу вспомнить. Большая часть того, что я знал, вернулась ко мне, но у меня возникли проблемы с обнаружением столкновений между битами и мячом. У меня есть 3 прямоугольника, чтобы обновить положение вместе со спрайтами, которые я использую, и когда прямоугольник шара пересекается с прямоугольником летучей мыши, я умножаю скорость шара X на -1. Однако это приводит к необычному эффекту, благодаря которому мяч подпрыгивает вокруг летучей мыши, как показано в этом видео . Что я здесь не так делаю?

Вот код для этого проекта (бедный, я знаю):

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);
    }
}
}

Ответы [ 2 ]

9 голосов
/ 13 апреля 2011

Решение Lyise будет работать, но оно не атакует действительный источник проблемы. В более крупных играх вам потребуется более надежное решение, поэтому я объясню, как исправить это на высоком уровне.

Проблема в том, что вы изменяете скорость Х, пока мяч все еще находится внутри летучей мыши. В следующем кадре наиболее вероятным результатом является то, что мяч отодвинется, но недостаточно для выхода из биты, поэтому будет обнаружено новое столкновение. Скорость снова меняется, и цикл повторяется до тех пор, пока мяч не покинет летучую мышь, опустившись ниже или выше нее.

Точное решение требует перемещения шара из летучей мыши и затем изменения скорости вращения.
Опции:

  • Верните мяч туда, где он был в начале кадра. Мяч никогда не коснется летучих мышей. Если скорость мяча достаточно высока или частота кадров достаточно низкая, это будет заметно.
  • Подсчитайте, как далеко в летучую мышь ушел шарик, и вычтите это количество из положения мяча.
    // Colliding from the right<br> impactCorrection = bat.Right - ball.Left;<br> // Colliding from the left<br> impactCorrection = bat.Left - ball.Right;
    Для получения дополнительных очков вы можете отодвинуть мяч на 2 * impactCorrection по X, чтобы мяч всегда проходил одинаковое расстояние в каждом кадре.
1 голос
/ 12 апреля 2011

Одним из способов решения этой проблемы является внесение следующих изменений в ваши ballRect.Intersect(barXRect)) if заявления:

    if (ballRect.Intersects(bat1Rect))
    {
        ballVelo.X = Math.Abs(ballVelo.X) * -1;
    }

    if (ballRect.Intersects(bat2Rect))
    {
        ballVelo.X = Math.Abs(ballVelo.X);
    }

Таким образом, левая полоса будет отправлять только мяч вправо, а правая полоса будет только отправлять его влево. У меня может быть неправильное расположение баров, так что лучше проверить дважды, но это просто означает перемещение * -1 на другую летучую мышь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...