Reputation: 3
I can easily rotate my sprite, but how could I rotate my rectangle for my collision (Thinking of using the Separating Axis Theorem, But I have no clue how to apply it) Help or Example would be appreciated :)
Game1 Class:
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 Class:
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)
{
}
}
}
Upvotes: 0
Views: 4112
Reputation: 1
I haven't looked through your piece of code yet, but here is a good tutorial which explains the SAT with example Code. It's not C# but it's easy to convert ;)
Upvotes: 0
Reputation: 14184
I understand in your question that you are using AABBs, and now you are trying to rotate the sprites, so now you need to rotate the AABB (That is, a OBB).
If Im not wrong and that is your case, one approach is what you suggested: SAT. But another approach is to use AABBs:
Note that an OBB its only an AABB defined in its own coordinate system (The optimal coordinate system that fits the AABB better to the object). You have two OOBBs (A and B), so you have two AABBs in two coordinate systems.
Get the AABB of B, and compute its AABB in the coordinate system of A (We can call this new AABB "C"). Check C and the AABB of A collision. Now do the same in reverse order (A's AABB in coordinate system of B (We call this new AABB "D"), and check collision with B's AABB).
If the two checks gets collision, the OBBs are in collision. See the picture:
Upvotes: 0
Reputation: 2078
Unless this is practice for learning how to code physics engines I recommend using a free 2D collision/physics library rather than reinventing the wheel; Box2D comes to mind.
Just noticed that you are trying to do per-pixel collision between their textures based on transparency. Modern games (even really small ones) do collision and physics based on convexes, which allows you to have a more sophisticated impact result (if two pixels hit then what is the normal?).
Upvotes: 1