Humm i made a example to illustrate it may have made it a bit to big and typed it lazily with too little thought but.
Edited it to make it slightly cooler.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
namespace AbstractItemsAndContainers
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Collisions collisions = new Collisions();
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = Globals.Instantiate(GraphicsDevice);
// TODO: use this.Content to load your game content here
// meh
var specialPlayer = new Player(new Vector2(250, 250), new Vector2(.01f, .01f), new Vector2(50, 50), Color.Black);
collisions.AddItem(specialPlayer);
// Make some random players and bullets
Random rnd = new Random(234234);
for (int i =0; i < 100; i++)
{
var x = rnd.Next(10, 800);
var y = rnd.Next(10, 800);
var pos = new Vector2(x, y);
var vel = Vector2.Normalize(new Vector2(250, 250) - pos);
var p = new Player(pos, vel, new Vector2(20, 20), Color.Green);
collisions.AddItem(p);
if(i < 25)
{
x = rnd.Next(10, 800);
y = rnd.Next(10, 800);
pos = new Vector2(x, y);
vel = Vector2.Normalize(new Vector2(250, 250) - pos) *5f;
var b = new Bullet(pos, vel, new Vector2(5, 5));
collisions.AddItem(b);
}
}
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// TODO: Add your update logic here
collisions.Update(gameTime);
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
collisions.Draw(gameTime);
spriteBatch.End();
base.Draw(gameTime);
}
}
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@ Example classes @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
public static class Globals
{
public static SpriteBatch spriteBatch;
public static GraphicsDevice gd;
public static Texture2D dotTexture;
public static SpriteBatch Instantiate(GraphicsDevice device)
{
gd = device;
dotTexture = TextureDotCreate(device, Color.White);
spriteBatch = new SpriteBatch(gd);
return spriteBatch;
}
public static Texture2D TextureDotCreate(GraphicsDevice device, Color c)
{
Color[] data = new Color[1];
data[0] = c;
return TextureFromColorArray(device, data, 1, 1);
}
public static Texture2D TextureFromColorArray(GraphicsDevice device, Color[] data, int width, int height)
{
Texture2D tex = new Texture2D(device, width, height);
tex.SetData<Color>(data);
return tex;
}
}
public abstract class Iamhereigothere
{
public Vector2 position;
public Vector2 velocity;
public float speed;
public Vector2 size = new Vector2(50,50);
public Color color = Color.White;
public virtual void Update(GameTime gameTime)
{
position += velocity;
}
public virtual void Draw(GameTime gameTime)
{
var rect = new Rectangle(position.ToPoint(), size.ToPoint());
// should pass this but this is a dependancy anyway you look at it.
Globals.spriteBatch.Draw(Globals.dotTexture, rect, Color.Red);
}
}
public class Player : Iamhereigothere
{
public Player(Vector2 startingPosition, Vector2 startingVelocity, Vector2 startingSize, Color col)
{
position = startingPosition;
velocity = startingVelocity;
speed = Vector2.Distance(startingVelocity, Vector2.Zero);
size = startingSize;
color = col;
}
public Bullet Shoot()
{
return new Bullet(position, velocity *3f, new Vector2(10, 10));
}
// we can overidde default behavior.
public override void Draw(GameTime gameTime)
{
var rect = new Rectangle(position.ToPoint(), size.ToPoint());
// should pass this but this is a dependancy anyway you look at it.
Globals.spriteBatch.Draw(Globals.dotTexture, rect, color);
}
}
public class Bullet : Iamhereigothere
{
public Bullet(Vector2 startingPosition, Vector2 startingVelocity, Vector2 startingSize)
{
position = startingPosition;
velocity = startingVelocity;
speed = Vector2.Distance(startingVelocity, Vector2.Zero);
size = startingSize;
}
}
public class Collisions
{
public List<Iamhereigothere> items = new List<Iamhereigothere>();
public void AddItem(Iamhereigothere item)
{
items.Add(item);
}
public void RemoveItem(Iamhereigothere item)
{
items.Remove(item);
}
public void Update(GameTime gameTime)
{
BruteForceCheckCollision(gameTime);
foreach (var item in items)
{
item.Update(gameTime);
}
}
public void BruteForceCheckCollision(GameTime gameTime)
{
for (int i = 0; i < items.Count; i++)
{
var item = items[i];
for (int j = 0; j < items.Count; j++)
{
if (i != j)
{
var testedItem = items[j];
if (TestCollision(item, testedItem))
{
// collision
// increase color
var n = items[i].color.R + 50;
if (n > 255)
n = 255;
items[i].color.R = (byte)n;
n = items[j].color.R + 50;
if (n > 255)
n = 255;
items[j].color.R = (byte)n;
// change direction
var dif = items[i].position - items[j].position;
if (dif.X == 0 && dif.Y == 0)
{
// this just prevents nans
}
else
{
var unitLengthDirection = Vector2.Normalize(items[i].position - items[j].position);
items[i].velocity = unitLengthDirection * items[i].speed;
items[j].velocity = -unitLengthDirection * items[j].speed;
}
}
}
else
{
// no collision
// reduce color
var n = items[i].color.R - 1;
if (n < 0)
n = 0;
items[i].color.R = (byte)n;
n = items[j].color.R - 1;
if (n < 0)
n = 0;
items[j].color.R = (byte)n;
}
}
}
}
public bool TestCollision(Iamhereigothere a, Iamhereigothere b)
{
var recta = new Rectangle(a.position.ToPoint(), a.size.ToPoint());
var rectb = new Rectangle(b.position.ToPoint(), b.size.ToPoint());
if (recta.Intersects(rectb) || recta.Contains(rectb))
return true;
else
return false;
}
public void Draw(GameTime gameTime)
{
foreach(var item in items)
{
item.Draw(gameTime);
}
}
}
}