簡體   English   中英

C#XNA 4.0矩形旋轉碰撞

[英]C# XNA 4.0 Rectangle Rotation Collision

我可以輕松地旋轉精靈,但是如何為碰撞而旋轉矩形(考慮使用“分離軸定理”,但我不知道如何應用它)不勝感激的幫助或示例:)

Game1類:

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 CombatTank
{

public class Game1 : Microsoft.Xna.Framework.Game
{
    //Declare Graphic Manager & Spritebatch
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //Declare Player 1
    theBody player1TankBody;

    //Declare Player 2
    theBody player2TankBody;

    //Save Player 1 Position
    Vector2 savedPlayer1TankBodyPosition;

    //Save Player 2 Position
    Vector2 savedPlayer2TankBodyPosition;

    //Declare Keyboard States
    KeyboardState currentkeyboardState;
    KeyboardState previousKeyboardState;


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

    protected override void Initialize()
    {
        //TankBody Position Player 1
        Vector2 player1TankBodyPosition = new Vector2(200, 200);
        Vector2 player2TankBodyPosition = new Vector2(400, 200);

        //TankBody Scale 
        float player1TankBodyScale = 1.0F;
        float player2TankBodyScale = 1.0F;

        //TankBody Rotation
        float player1TankBodyRotation = 0.0F;
        float player2TankBodyRotation = 0.0F;

        //TankBody Color
        Color player1TankBodyColor = Color.Red;
        Color player2TankBodyColor = Color.Blue;

        //Create Tank
        player1TankBody = new theBody(player1TankBodyPosition,player1TankBodyScale, player1TankBodyRotation, player1TankBodyColor);
        player2TankBody = new theBody(player2TankBodyPosition, player2TankBodyScale, player2TankBodyRotation, player2TankBodyColor);

        base.Initialize();
    }

    protected override void LoadContent()
    {
        //Create New SpriteBatch
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //Load The Player 1 TankBody Texture
        Texture2D player1SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player1TankBody.LoadContent(Content,"TankBody");

        //Extract Collision Data For Player 1
        player1TankBody.TankBodyTextureData = new Color[player1TankBody.Texture.Width * player1TankBody.Texture.Height];
        player1TankBody.Texture.GetData(player1TankBody.TankBodyTextureData);

        //Load The Player 2 TankBody Texture
        Texture2D player2SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player2TankBody.LoadContent(Content, "TankBody");

        //Extract Collision Data For Player 2
        player2TankBody.TankBodyTextureData = new Color[player2TankBody.Texture.Width * player2TankBody.Texture.Height];
        player2TankBody.Texture.GetData(player2TankBody.TankBodyTextureData);

    }

    protected override void UnloadContent()
    {

    }


    protected override void Update(GameTime gameTime)
    {
        //Save Player 1 Postion
        savedPlayer1TankBodyPosition.X = player1TankBody.Position.X;
        savedPlayer1TankBodyPosition.Y = player1TankBody.Position.Y;

        //Save Player 2 Position
        savedPlayer2TankBodyPosition.X = player2TankBody.Position.X;
        savedPlayer2TankBodyPosition.Y = player2TankBody.Position.Y;

        //Updates Player 1
        UpdatePlayer1(gameTime);

        //Update Player 2
        UpdatePlayer2(gameTime);

        //Collision Player 1
        CollisionPlayer1(gameTime);

        //Collision Player 2
        CollisionPlayer2(gameTime);

        base.Update(gameTime);
    }

    private void UpdatePlayer1(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.W))
        {
            //Move Tank Forward
            player1TankBody.Position.X -= 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y -= 5 * (float)Math.Sin(player1TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.S))
        {
            //Move Tank Backwards
            player1TankBody.Position.X += 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y += 5 * (float)Math.Sin(player1TankBody.Rotation);

        }
        if (currentkeyboardState.IsKeyDown(Keys.A))
        {
            player1TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.D))
        {
            player1TankBody.Rotation += 0.03f;
        }

    }

    private void UpdatePlayer2(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.Up))
        {
            //Move Tank Forward
            player2TankBody.Position.X -= 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y -= 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Down))
        {
            //Move Tank Backward
            player2TankBody.Position.X += 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y += 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Left))
        {
            player2TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.Right))
        {
            player2TankBody.Rotation += 0.03f;
        }

    }

    private void CollisionPlayer1(GameTime gameTime)
    {


        if (IntersectPixels(player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData, player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData))
        {
            player1TankBody.Position.X = savedPlayer1TankBodyPosition.X;
            player1TankBody.Position.Y = savedPlayer1TankBodyPosition.Y;

        }



    }

    private void CollisionPlayer2(GameTime gameTime)
    {
        if (IntersectPixels(player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData, player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData))
        {
            player2TankBody.Position.X = savedPlayer2TankBodyPosition.X;
            player2TankBody.Position.Y = savedPlayer2TankBodyPosition.Y;

        }
    }


    static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
    {
        //Find top Bound of the Rectangle
        int top = Math.Max(rectangleA.Top, rectangleB.Top);
        int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
        int left = Math.Max(rectangleA.Left, rectangleB.Left);
        int right = Math.Min(rectangleA.Right, rectangleB.Right);

        for (int y = top; y < bottom; y++)
        {
            for (int x = left; x < right; x++)
            {
                //Get Color of both Pixels
                Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
                Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];

                //Both pixel are not completely Transparent
                if (colorA.A != 0 && colorB.B != 0)
                {
                    //Then an intersection is found 
                    return true;
                }

            }

        }


        //No Intersection
        return false;
    }





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

        spriteBatch.Begin();

        player1TankBody.Draw(spriteBatch);
        player2TankBody.Draw(spriteBatch);

        spriteBatch.End();

        base.Draw(gameTime);
    }
}
}

theBody類:

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

namespace CombatTank
{
class theBody
{
    //TankBody Texture
    private Texture2D texture;
    public Texture2D Texture
    {
        get
        { 
            return texture; 
        }
    }

    //TankBody Height
    private float height;
    public float Height
    {
        get
        {
            return height;
        }
    }

    //TankBody Width
    private float width;
    private float Width
    {
        get
        {
            return width;
        }

    }

    //TankBody Position
    public Vector2 Position;

    //TankBody Origin
    public Vector2 Origin;

    //TankBody Rotation
    public float Rotation = 0.0F;

    //TankBody Color
    public Color Color = Color.White;

    //TankBody Scale
    public float Scale = 1F;

    //TankBody BoundingBox
    public Rectangle BoundingBox
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, (int)texture.Width, (int)texture.Height);
        }
    }

    //TankBody color Data(Used For Pixel Collision)
    public Color[] TankBodyTextureData;

    //TankBody Constructor
    public theBody(Vector2 position,float scale,float rotation, Color color)
    {
        Position = position;
        Scale = scale;
        Rotation = rotation;
        Color = color;
    }

    //LoadContent
    public void LoadContent(ContentManager contentManager, string assetname)
    {
        texture = contentManager.Load<Texture2D>(assetname);
        Origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
    }

    //Draw
    public virtual void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, Position, null, Color, Rotation, Origin, Scale, SpriteEffects.None, 0);
    }

    //Update
    public void Update(GameTime gameTime)
    {

    }
}
}

除非這是學習如何對物理引擎進行編碼的實踐,否則我建議使用免費的2D碰撞/物理庫,而不是重新發明輪子。 Box2D浮現在腦海。

剛剛注意到,您正在嘗試基於透明度在它們的紋理之間進行逐像素碰撞。 現代游戲(甚至很小的游戲)都基於凸面進行碰撞和物理處理,這使您可以獲得更復雜的碰撞效果(如果擊中了兩個像素,那是正常現象嗎?)。

我在您的問題中了解到您正在使用AABB,而現在您正在嘗試旋轉精靈,因此現在您需要旋轉AABB(即OBB)。

如果我沒記錯,那就是您的情況,那么您建議使用一種方法:SAT。 但是另一種方法是使用AABB:

請注意,OBB只是在其自己的坐標系中定義的AABB(使AABB更適合對象的最佳坐標系)。 您有兩個OOBB(A和B),因此在兩個坐標系中有兩個AABB。

獲得B的AABB,並在A的坐標系中計算其AABB(我們可以將這個新的AABB稱為“ C” )。 檢查CA的AABB。 現在,以相反的順序執行相同的操作(在B的坐標系中A的AABB(我們將此新AABB稱為“ D” ),並檢查與B的AABB的碰撞)。

如果兩個支票發生碰撞,則OBB處於碰撞中。 看圖片:

在此處輸入圖片說明

我還沒有看過您的代碼,但這是一個很好的教程 ,其中用示例代碼解釋了SAT。 它不是C#,但是很容易轉換;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM