[英]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” )。 檢查C和A的AABB。 現在,以相反的順序執行相同的操作(在B的坐標系中A的AABB(我們將此新AABB稱為“ D” ),並檢查與B的AABB的碰撞)。
如果兩個支票發生碰撞,則OBB處於碰撞中。 看圖片:
我還沒有看過您的代碼,但這是一個很好的教程 ,其中用示例代碼解釋了SAT。 它不是C#,但是很容易轉換;)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.