space-pew/SpacePew/Models/EntityBase.cs
Magnus von Wachenfeldt 2a9d8ce416 move to github
2015-12-04 10:23:49 +01:00

198 lines
4.9 KiB
C#

using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace SpacePew.Models
{
public abstract class EntityBase : IEntity
{
public const float OneRound = (float)Math.PI * 2;
public const float VelocityModifier = .1f;
public const float GravityModifier = 100f;
public Rectangle BoundingRectangle
{
get
{
return new Rectangle((int)this.Position.X - (int)this.Origin.X, (int)this.Position.Y - (int)this.Origin.Y, this.Texture.Width, this.Texture.Height);
}
}
private Color[] _textureData;
public Color[] GetTextureData()
{
if (_textureData == null)
{
this._textureData = new Color[this.Texture.Width * this.Texture.Height];
this.Texture.GetData(this._textureData);
}
return _textureData;
}
// These should be settings in the start menu GUI later on
public bool IsCollisionWith(IEntity entity)
{
// never collide with oneself
if (ReferenceEquals(entity, this))
return false;
return entity.Collide(this);
}
public virtual bool Collide(IEntity entity)
{
Matrix transform = Matrix.CreateTranslation(new Vector3(this.Position - this.Origin, 0.0f));
Matrix entityTransform =
Matrix.CreateTranslation(new Vector3(-entity.Origin, 0.0f)) *
Matrix.CreateRotationZ(entity.Angle) *
Matrix.CreateTranslation(new Vector3(entity.Position, 0.0f));
Rectangle entityRectangle = CalculateBoundingRectangle(
new Rectangle(0, 0, entity.Texture.Width, entity.Texture.Height),
entityTransform);
if (entityRectangle.Intersects(this.BoundingRectangle))
{
if (IntersectPixels(transform, this.Texture.Width,
this.Texture.Height, this.GetTextureData(),
entityTransform, entity.Texture.Width,
entity.Texture.Height, entity.GetTextureData()))
{
return true;
}
}
return false;
}
private static bool IntersectPixels(Matrix transformA, int widthA, int heightA, Color[] dataA,
Matrix transformB, int widthB, int heightB, Color[] dataB)
{
Matrix transformAtoB = transformA * Matrix.Invert(transformB);
Vector2 stepX = Vector2.TransformNormal(Vector2.UnitX, transformAtoB);
Vector2 stepY = Vector2.TransformNormal(Vector2.UnitY, transformAtoB);
Vector2 yPosInB = Vector2.Transform(Vector2.Zero, transformAtoB);
for (int yA = 0; yA < heightA; yA++)
{
Vector2 posInB = yPosInB;
for (int xA = 0; xA < widthA; xA++)
{
var xB = (int)Math.Round(posInB.X);
var yB = (int)Math.Round(posInB.Y);
if (0 <= xB && xB < widthB &&
0 <= yB && yB < heightB)
{
Color colorA = dataA[xA + yA * widthA];
Color colorB = dataB[xB + yB * widthB];
if (colorA.A != 0 && colorB.A != 0)
{
return true;
}
}
posInB += stepX;
}
yPosInB += stepY;
}
return false;
}
private static Rectangle CalculateBoundingRectangle(Rectangle rectangle, Matrix transform)
{
var leftTop = new Vector2(rectangle.Left, rectangle.Top);
var rightTop = new Vector2(rectangle.Right, rectangle.Top);
var leftBottom = new Vector2(rectangle.Left, rectangle.Bottom);
var rightBottom = new Vector2(rectangle.Right, rectangle.Bottom);
Vector2.Transform(ref leftTop, ref transform, out leftTop);
Vector2.Transform(ref rightTop, ref transform, out rightTop);
Vector2.Transform(ref leftBottom, ref transform, out leftBottom);
Vector2.Transform(ref rightBottom, ref transform, out rightBottom);
Vector2 min = Vector2.Min(Vector2.Min(leftTop, rightTop), Vector2.Min(leftBottom, rightBottom));
Vector2 max = Vector2.Max(Vector2.Max(leftTop, rightTop), Vector2.Max(leftBottom, rightBottom));
return new Rectangle((int)min.X, (int)min.Y, (int)(max.X - min.X), (int)(max.Y - min.Y));
}
#region IEntity Members
public virtual string Owner
{
get;
set;
}
public abstract int Health { get; set; }
public abstract string TextureName { get; }
public virtual void CollideWithLevel(Level level) { }
public Texture2D Texture { get; set; }
public virtual Color Color { get; set; }
public Vector2 Position { get; set; }
public Vector2 Velocity { get; set; }
public virtual Vector2 Origin
{
get
{
return new Vector2(this.Texture.Width / 2, this.Texture.Height / 2);
}
}
private float _angle;
public float Angle
{
get
{
return _angle;
}
set
{
_angle = value;
if (_angle > OneRound)
{
_angle -= OneRound;
}
else if (_angle < 0)
{
_angle += OneRound;
}
}
}
public virtual void Created() { }
public virtual void ApplyGravity(GameTime time)
{
float timeSeconds = time.ElapsedGameTime.Milliseconds * .001f;
Velocity = new Vector2(
Velocity.X,
Velocity.Y + (timeSeconds * GravityModifier));
}
public virtual void Update(GameTime time)
{
ApplyGravity(time);
float timeSeconds = time.ElapsedGameTime.Milliseconds * .001f;
Position += Velocity * timeSeconds;
}
#endregion
}
}