198 lines
4.9 KiB
C#
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
|
|||
|
}
|
|||
|
}
|