move to github

This commit is contained in:
Magnus von Wachenfeldt
2015-12-04 10:23:49 +01:00
commit 2a9d8ce416
252 changed files with 45041 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
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
}
}

View File

@@ -0,0 +1,28 @@
namespace SpacePew.Models
{
public class Explosion : EntityBase
{
public Explosion()
{
_health = 10;
}
private int _health;
public override int Health
{
get
{
return _health;
}
set
{
_health = value;
}
}
public override string TextureName
{
get { return "explosion_small"; }
}
}
}

View File

@@ -0,0 +1,28 @@
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace SpacePew.Models
{
public interface IEntity
{
string TextureName { get; }
Texture2D Texture { get; set; }
Color[] GetTextureData();
Color Color { get; set; }
string Owner { get; set; }
int Health { get; set; }
Vector2 Origin { get; }
Vector2 Position { get; set; }
Vector2 Velocity { get; set; }
float Angle { get; set; }
bool Collide(IEntity entity);
void CollideWithLevel(Level level);
void ApplyGravity(GameTime time);
void Update(GameTime time);
void Created();
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SpacePew.Models
{
public interface IKillable
{
void Kill();
}
}

301
SpacePew/Models/Level.cs Normal file
View File

@@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Collections;
using Microsoft.Xna.Framework.Media;
namespace SpacePew.Models
{
public class Tile
{
public Point Position { get; set; }
public Texture2D Texture { get; set; }
public Tile(Texture2D texure, Point position)
{
Texture = texure;
Position = position;
}
}
public class TiledTexture : List<Tile>
{
public int TileWidth { get; set; }
public int TileHeight { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int XTiles { get; set; }
public int YTiles { get; set; }
public Vector2 Position { get; set; }
public void GetData(Color[] textureData)
{
var buffer = new Color[TileWidth * TileHeight];
for (var j = 0; j < XTiles; j++)
{
for (var i = 0; i < YTiles; i++)
{
var tile = this[i * XTiles + j];
tile.Texture.GetData(buffer);
for (var x = 0; x < TileWidth; x++)
{
for (var y = 0; y < TileHeight; y++)
{
var xpos = tile.Position.X + x;
var ypos = tile.Position.Y + y;
textureData[ypos * Width + xpos] = buffer[y * TileWidth + x];
}
}
}
}
}
public void SetData(Color[] textureData)
{
var buffer = new Color[TileWidth * TileHeight];
for (var j = 0; j < XTiles; j++)
{
for (var i = 0; i < YTiles; i++)
{
var tile = this[i * XTiles + j];
for (var x = 0; x < TileWidth; x++)
{
for (var y = 0; y < TileHeight; y++)
{
var xpos = tile.Position.X + x;
var ypos = tile.Position.Y + y;
buffer[y * TileWidth + x] = textureData[ypos * Width + xpos];
}
}
tile.Texture.SetData(buffer);
}
}
}
public void SaveAsPng(Stream s, int width, int height)
{
throw new NotImplementedException("Har inte hunnit med.. borde gå att kopiera nån av Get/Set ovan och skapa upp en bild.");
}
}
public class Level
{
public string Name { get; set; }
public string Description { get; set; }
public string FilePath { get; set; }
public byte[] OggVorbisSong { get; set; }
public TiledTexture Texture { get; set; }
public TiledTexture IndestructibleTexture { get; set; }
public TiledTexture DeformedTexture { get; set; }
private Color[] _deformedTextureData;
public Queue<MapHit> Hits { get; set; }
public bool[] CollisionData
{
get;
set;
}
public bool[] IndestructibleCollisionData
{
get;
set;
}
private int _width;
private int _height;
public Level(GraphicsDevice device)
{
}
public Level()
{ }
public void Initialize()
{
_width = Texture.Width;
_height = Texture.Height;
Hits = new Queue<MapHit>();
var textureData = new Color[Texture.Width * Texture.Height];
Texture.GetData(textureData);
var indestructibleTextureData = new Color[IndestructibleTexture.Width * IndestructibleTexture.Height];
IndestructibleTexture.GetData(indestructibleTextureData);
CollisionData = new bool[Texture.Width * Texture.Height];
_deformedTextureData = new Color[DeformedTexture.Width * DeformedTexture.Height];
for (int i = _deformedTextureData.Length - 1; i >= 0; i--)
{
_deformedTextureData[i] = textureData[i].A > 0 ? textureData[i] : Color.Transparent;
}
DeformedTexture.SetData(_deformedTextureData);
IndestructibleCollisionData = new bool[IndestructibleTexture.Width * IndestructibleTexture.Height];
for (int i = 0; i < indestructibleTextureData.Length; i++)
{
if (indestructibleTextureData[i].A == 0)
{
IndestructibleCollisionData[i] = true;
}
}
}
public void BuildLevelFromCollisionData()
{
for (int i = 0; i < CollisionData.Length; i++)
{
if (CollisionData[i])
{
_deformedTextureData[i] = Color.Transparent;
}
}
DeformedTexture.SetData(_deformedTextureData);
}
public void BuildCollisionDataFromLevel()
{
for (int i = 0; i < _deformedTextureData.Length; i++)
{
if (_deformedTextureData[i] == Color.Transparent)
{
CollisionData[i] = true;
}
}
}
/// <summary>
/// Returns the number of pixels of the entity that collides with the background
/// </summary>
/// <param name="entity"></param>
/// <param name="centerX"></param>
/// <param name="centerY"></param>
/// <returns></returns>
public int Collide(IEntity entity, int centerX, int centerY)
{
int entityWidth = entity.Texture.Width;
int entityHeight = entity.Texture.Height;
int posX = (int)entity.Position.X - (int)entity.Origin.X + centerX;
int posY = (int)entity.Position.Y - (int)entity.Origin.Y + centerY;
if (posX < 1 || posY < 1 || posX > Texture.Width - entityWidth - 1 || posY > Texture.Height - entityHeight - 1)
return 1000000000;
int hit = 0;
Color[] data = entity.GetTextureData();
var player = entity as Player;
bool isLandingAngle = player != null && (MathHelper.ToDegrees(player.Angle) >= 345 || MathHelper.ToDegrees(player.Angle) <= 15) && player.Velocity.Y > 0;
for (int y = 0; y < entityHeight; y++)
{
for (int x = 0; x < entityWidth; x++)
{
Color colorInPixel = data[(x - entity.Texture.Bounds.X) + (y - entity.Texture.Bounds.Y) * entity.Texture.Bounds.Width];
if(colorInPixel.A != 0)
{
if (CollisionData[(posX + x) + (posY + y) * _width] == false)
{
if (isLandingAngle)
{
if (CollisionData[(posX + x) + (posY + y + 1) * _width] == false &&
CollisionData[(posX + x + player.Texture.Width) + (posY + y + 1) * _width] == false)
{
if (player.Velocity.Y > 200f)
{
var yVelocity = (int)player.Velocity.Y;
SoundManager.Play("Audio/Waves/thump", player.Position);
player.Velocity = new Vector2(player.Velocity.X / 3, -player.Velocity.Y / 3);
return (yVelocity - 200) / 50;
}
player.Land();
return 0;
}
}
entity.CollideWithLevel(this);
CollisionData[(posX + x) + (posY + y) * _width] = true;
Hits.Enqueue(new MapHit(entity));
hit++;
}
else if (IndestructibleCollisionData[(posX + x) + (posY + y) * _width] == false)
{
if (isLandingAngle)
{
if (IndestructibleCollisionData[(posX + x) + (posY + y + 1) * _width] == false &&
IndestructibleCollisionData[(posX + x + player.Texture.Width) + (posY + y + 1) * _width] == false)
{
if (player.Velocity.Y > 200f)
{
var yVelocity = (int)player.Velocity.Y;
SoundManager.Play("Audio/Waves/thump", player.Position);
player.Velocity = new Vector2(player.Velocity.X / 3, -player.Velocity.Y / 3);
return (yVelocity - 200) / 50;
}
player.Land();
return 0;
}
}
entity.CollideWithLevel(this);
hit++;
}
}
}
}
if (player != null)
{
return hit / 20;
}
return hit;
}
public void StopLevelSong()
{
_stopMusic = true;
}
private bool _stopMusic;
public void PlayLevelSong()
{
using (var ms = new MemoryStream(this.OggVorbisSong))
{
using (var vorbis = new NVorbis.NAudioSupport.VorbisWaveReader(ms))
{
using (var waveOut = new NAudio.Wave.WaveOut())
{
waveOut.Init(vorbis);
waveOut.Play();
while (!_stopMusic)
{
Thread.Sleep(100);
}
}
}
}
}
}
}

21
SpacePew/Models/MapHit.cs Normal file
View File

@@ -0,0 +1,21 @@
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace SpacePew.Models
{
public class MapHit
{
public Texture2D Texture { get; private set; }
public Vector2 Position { get; private set; }
public Vector2 Origin { get; private set; }
public float Angle { get; private set; }
public MapHit(IEntity entity)
{
Texture = entity.Texture;
Position = entity.Position;
Origin = entity.Origin;
Angle = entity.Angle;
}
}
}

295
SpacePew/Models/Player.cs Normal file
View File

@@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Audio;
using SpacePew.Networking;
using SpacePew.Camera;
using SpacePew.Models.Projectiles;
using SpacePew.Models.Weapons;
namespace SpacePew.Models
{
public class Player : EntityBase, IFocusable
{
#region Constructors
private SoundEffectInstance _thrustSound;
public Player()
{
_weapon = new Cannon();
_projectile = new Bullet();
_secondaryWeapon = new ClusterLauncher();
_secondaryProjectile = new ClusterBomb();
Health = 100;
Fuel = 50000;
_lastCollide = DateTime.Now;
_thrustSound = SoundManager.GetSoundEffectInstance("Audio/Waves/engine");
}
#endregion
private readonly Vector2 _up = new Vector2(0, -1);
private Matrix _rotationMatrix;
private Vector2 _direction;
private readonly IProjectile _projectile;
private readonly IProjectile _secondaryProjectile;
private IWeapon _secondaryWeapon;
public IWeapon SecondaryWeapon
{
get { return _secondaryWeapon; }
set { _secondaryWeapon = value; }
}
private IWeapon _weapon;
public IWeapon Weapon
{
get { return _weapon; }
set { _weapon = value; }
}
public bool IsRemotePlayer { get; set; }
public bool Landed { get; set; }
public double Fuel { get; private set; }
#region Input handling
private bool _isThrusting;
public void HandleKeyboard(KeyboardState state)
{
if (!MainGame.IsKeyboardInUse)
{
if (state.IsKeyDown(Keys.Right))
{
if (Landed)
{
Landed = false;
}
this.MoveRight();
}
if (state.IsKeyDown(Keys.Left))
{
if (Landed)
{
Landed = false;
}
this.MoveLeft();
}
if (state.IsKeyDown(Keys.Up))
{
if (Landed)
{
Landed = false;
}
_isThrusting = true;
this.Thrust();
}
else
{
_isThrusting = false;
}
if (state.IsKeyDown(Keys.Space))
{
this.Fire();
}
else
{
if (this.Weapon.Heat > 0)
{
this.Weapon.Heat -= 1;
}
}
if (state.IsKeyDown(Keys.LeftControl))
{
this._secondaryWeapon.Fire(this._secondaryProjectile, this);
}
else
{
if (this._secondaryWeapon.Heat > 0)
{
this._secondaryWeapon.Heat -= 1;
}
}
if (state.IsKeyDown(Keys.R))
{
this.Health = 0;
}
}
}
private void Fire()
{
this._weapon.Fire(_projectile, this);
}
private void MoveRight()
{
Angle += 0.1f;
}
private void MoveLeft()
{
Angle -= 0.1f;
}
private void Thrust()
{
Fuel -= 1;
_rotationMatrix = Matrix.CreateRotationZ(Angle);
_direction = Vector2.Transform(_up, _rotationMatrix);
Velocity += _direction / VelocityModifier;
}
#endregion
#region IEntity Members
public override string Owner { get; set; }
public override sealed int Health { get; set; }
public override void ApplyGravity(GameTime time)
{
if (!Landed)
{
base.ApplyGravity(time);
}
}
public override Vector2 Origin
{
get { return new Vector2(Texture.Width / 2, Texture.Height / 2); }
}
public override string TextureName
{
get { return "player"; }
}
#endregion
private DateTime _lastCollide;
public void CollideWith(IEntity entity)
{
var projectile = entity as IProjectile;
if (projectile != null)
{
this.Health -= projectile.Damage;
return;
}
var player = entity as Player;
if (player != null)
{
if (_lastCollide <= DateTime.Now.AddMilliseconds(-80))
{
_lastCollide = DateTime.Now;
if (Math.Abs(this.Velocity.Length()) > Math.Abs(entity.Velocity.Length()))
{
entity.Velocity += this.Velocity / 2;
this.Velocity /= 4;
}
else
{
this.Velocity += entity.Velocity / 2;
entity.Velocity /= 4;
}
}
this.Landed = false;
player.Landed = false;
}
}
public override void CollideWithLevel(Level level)
{
Velocity -= (Velocity / 300);
}
public static Player CreatePlayer(Vector2 startPosition)
{
return CreatePlayer(startPosition, string.Empty);
}
public static Player CreatePlayer(Vector2 startPosition, string name)
{
return EntityFactory.Instance.CreateEntity<Player>(
name,
startPosition,
new Vector2(),
0
);
}
public void Land()
{
if (!Landed)
{
this.Velocity = new Vector2(0, 0);
this.Position = new Vector2(this.Position.X, this.Position.Y - 1); // Need to adjust because per pixel collision
// sometimes can't catch up with frame rate
this.Angle = 0;
Landed = true;
}
}
public void Kill()
{
SoundManager.Play("Audio/Waves/explosion", this.Position);
this.Position = new Vector2(25, 25);
this.Velocity = new Vector2(0, 0);
this.Angle = 0;
this.Health = 100;
this.Landed = false;
}
public override void Update(GameTime time)
{
if (_isThrusting)
{
if (_thrustSound.State != SoundState.Playing)
{
_thrustSound.Play();
}
this.Texture = TextureManager.LoadTexture("player_thrusting");
}
else
{
_thrustSound.Pause();
this.Texture = TextureManager.LoadTexture("player");
}
base.Update(time);
}
#region IFocusable Members
Vector2 IFocusable.Position
{
get { return this.Position; }
}
#endregion
}
}

View File

@@ -0,0 +1,18 @@
namespace SpacePew.Models.Projectiles
{
public sealed class BouncingBullet : Bullet
{
public BouncingBullet()
{
Health = 30;
}
public override CollisionType CollisionType
{
get
{
return CollisionType.Bounce;
}
}
}
}

View File

@@ -0,0 +1,70 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew.Models.Projectiles
{
public class Bullet : ProjectileBase
{
#region Constructors
public Bullet()
{
this.Color = Color.White;
this.Velocity = new Vector2();
this.Angle = 0;
this.Health = 15;
}
public Bullet(Vector2 position)
: this()
{
this.Position = position;
}
#endregion
#region IEntity Members
public override sealed int Health
{
get;
set;
}
public override string TextureName
{
get { return "bullet"; }
}
#endregion
#region IProjectile Members
public override string FireSoundAssetName
{
get { return "Audio/Waves/bullet_sound"; }
}
public override string HitSoundAssetName
{
get { return "Audio/Waves/bullet_hit"; }
}
public override int Damage
{
get { return 5; }
}
public override float Speed
{
get { return 400f; }
}
public override CollisionType CollisionType
{
get { return CollisionType.Explode; }
}
#endregion
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using SpacePew.Models.Weapons;
namespace SpacePew.Models.Projectiles
{
class ClusterBomb : Bullet, IKillable
{
private const int FuseTime = 7000; //time in milliseconds before it explodes
private double _elapsed = 0;
readonly DateTime _startTick;
public override int Damage
{
get { return 10; }
}
public override float Speed
{
get { return 100; }
}
public ClusterBomb()
{
_startTick = DateTime.Now;
}
public override Color Color
{
get
{
var r = (byte)((_elapsed / FuseTime) * 255f);
var g = (byte)(128 + Math.Sin(_elapsed / 150f) * 127f);
var b = (byte)(255 - g);
return new Color(r, g, b);
}
}
public override void Update(Microsoft.Xna.Framework.GameTime time)
{
_elapsed = (DateTime.Now - _startTick).TotalMilliseconds;
if (_elapsed >= FuseTime)
{
this.Health = 0;
}
base.Update(time);
}
private void CreateCluster(float angle, string owner)
{
var entity = EntityFactory.Instance.CreateEntity<ProjectileBase>(
typeof(Bullet),
owner,
Position,
Vector2.Zero,
angle);
Matrix m = Matrix.CreateRotationZ(angle + (float)(WeaponBase.Randomizer.NextDouble() * .2f - .1f));
Vector2 velocity = Vector2.Transform(-Vector2.UnitY, m);
entity.Position += velocity * 10;
entity.Velocity = velocity * entity.Speed * (float)(WeaponBase.Randomizer.NextDouble() + 0.5f);
//TODO.. fix
//FiredShots.Enqueue(entity);
}
public override void ApplyGravity(GameTime time)
{
float timeSeconds = time.ElapsedGameTime.Milliseconds * .001f;
Velocity = new Vector2(
Velocity.X,
Velocity.Y + (timeSeconds * GravityModifier * 0.5f));
}
#region IKillable Members
public void Kill()
{
//TODO: make sure the clusters are only created on the client that created the cluster, and then let the server send them to all klients
for (float i = 0; i < 45; i += .5f)
CreateCluster(i, this.Owner);
}
#endregion
}
}

View File

@@ -0,0 +1,8 @@
namespace SpacePew.Models.Projectiles
{
public enum CollisionType
{
Explode,
Bounce
}
}

View File

@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
namespace SpacePew.Models.Projectiles
{
public class HomingBullet : Bullet
{
public HomingBullet()
{
this.Color = Color.PowderBlue;
}
public override float Speed
{
get
{
return 200f;
}
}
public override int Damage
{
get
{
return 3;
}
}
private Player _target;
const float TimeIncrementSpeed = 5;
public override void Update(GameTime time)
{
base.Update(time);
if (_target == null)
{
GetTarget();
}
if (_target != null)
{
var delta = new Vector2(_target.Position.X - this.Position.X, _target.Position.Y - this.Position.Y);
if (delta.Length() > TimeIncrementSpeed)
{
delta.Normalize();
delta.X *= TimeIncrementSpeed;
delta.Y *= TimeIncrementSpeed;
}
this.Position = new Vector2(Position.X + (int)delta.X, Position.Y + (int)delta.Y);
}
}
private void GetTarget()
{
var players = EntityFactory.Instance.Entities.OfType<Player>().Where(player => player.Owner != this.Owner).ToList();
if (players.Count > 0)
{
_target = FindClosestPlayer(players, this.Position);
}
}
private static Player FindClosestPlayer(IEnumerable<Player> list, Vector2 pointToCompare)
{
Player closestPlayer = list.ToList()[0];
float distance = float.PositiveInfinity;
foreach (var player in list)
{
float dx = pointToCompare.X - player.Position.X;
float dy = pointToCompare.Y - player.Position.Y;
float d = dx * dx - dy * dy;
if (d < distance)
{
distance = d;
closestPlayer = player;
}
}
return closestPlayer;
}
}
}

View File

@@ -0,0 +1,12 @@
namespace SpacePew.Models.Projectiles
{
public interface IProjectile : IEntity
{
string HitSoundAssetName { get; }
string FireSoundAssetName { get; }
int Damage { get; }
float Speed { get; }
CollisionType CollisionType { get; }
}
}

View File

@@ -0,0 +1,29 @@
using System;
using Microsoft.Xna.Framework;
namespace SpacePew.Models.Projectiles
{
public class LongShot : Bullet
{
public override Vector2 Origin
{
get { return new Vector2(5, 12); }
}
public override string TextureName
{
get { return "longshot"; }
}
public override void ApplyGravity(GameTime time)
{
base.ApplyGravity(time);
//Sätt rotationen till lika som riktningen som pilen åker
Vector2 vNormal = Velocity;
vNormal.Normalize();
Angle = (vNormal.X > 0 ? 1f : -1f) * (float)(Math.Acos(Vector2.Dot(-Vector2.UnitY, vNormal)));
}
}
}

View File

@@ -0,0 +1,75 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew.Models.Projectiles
{
public sealed class Missile : ProjectileBase
{
#region Constructors
public Missile()
{
this.Color = Color.Red;
this.Velocity = new Vector2();
this.Angle = 0;
this.Health = 10;
}
public Missile(Vector2 position)
: this()
{
this.Position = position;
}
#endregion
#region IEntity Members
public override void CollideWithLevel(Level level)
{
// blow stuff
}
public override int Health
{
get;
set;
}
public override string TextureName
{
get { return "bullet"; }
}
#endregion
#region IProjectile Members
public override string FireSoundAssetName
{
get { return "Audio/Waves/bullet_sound"; }
}
public override string HitSoundAssetName
{
get { return "Audio/Waves/bullet_hit"; }
}
public override int Damage
{
get { return 50; }
}
public override float Speed
{
get { return 600f; }
}
public override CollisionType CollisionType
{
get { return CollisionType.Explode; }
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
namespace SpacePew.Models.Projectiles
{
public abstract class ProjectileBase : EntityBase, IProjectile
{
#region IEntity Members
public override bool Collide(IEntity entity)
{
bool collided = base.Collide(entity);
if (collided)
{
SoundManager.Play(HitSoundAssetName, this.Position);
}
return collided;
}
public override void CollideWithLevel(Level level)
{
if (this.CollisionType == CollisionType.Explode)
{
// blow up somehow (particle system is there, but needs to trash the level a little more too)
}
else if (this.CollisionType == CollisionType.Bounce)
{
this.Velocity -= (this.Velocity * 1.9f);
}
}
public override void Created()
{
SoundManager.Play(FireSoundAssetName, this.Position);
}
#endregion
#region IProjectile Members
public abstract string HitSoundAssetName { get; }
public abstract string FireSoundAssetName { get; }
public abstract int Damage { get; }
public abstract float Speed { get; }
public abstract CollisionType CollisionType { get; }
#endregion
}
}

View File

@@ -0,0 +1,20 @@
namespace SpacePew.Models.Weapons
{
public class Cannon : WeaponBase
{
public override float HeatGeneration
{
get { return 0.4f; }
}
public override int Delay
{
get { return 35; }
}
public override int Spread
{
get { return 0; }
}
}
}

View File

@@ -0,0 +1,20 @@
namespace SpacePew.Models.Weapons
{
public class ClusterLauncher : WeaponBase
{
public override float HeatGeneration
{
get { return 100f; }
}
public override int Delay
{
get { return 0; }
}
public override int Spread
{
get { return 0; }
}
}
}

View File

@@ -0,0 +1,13 @@
using SpacePew.Models.Projectiles;
namespace SpacePew.Models.Weapons
{
public interface IWeapon
{
int Delay { get; }
int Spread { get; }
float Heat { get; set; }
float HeatGeneration { get; }
void Fire(IProjectile projectile, Player player);
}
}

View File

@@ -0,0 +1,20 @@
namespace SpacePew.Models.Weapons
{
public class Launcher : WeaponBase
{
public override float HeatGeneration
{
get { return 100f; }
}
public override int Delay
{
get { return 200; }
}
public override int Spread
{
get { return 0; }
}
}
}

View File

@@ -0,0 +1,24 @@
namespace SpacePew.Models.Weapons
{
/// <summary>
/// A slower version of the cannon, should be used for powerful projectiles like the homing bullets to even things out
/// </summary>
public class SecondaryCannon : Cannon
{
public override float HeatGeneration
{
get
{
return 1f;
}
}
public override int Delay
{
get
{
return 80;
}
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using Microsoft.Xna.Framework;
using SpacePew.Models.Projectiles;
namespace SpacePew.Models.Weapons
{
public class TriCannon : WeaponBase
{
public override float HeatGeneration
{
get { return 0.8f; }
}
public override int Delay
{
get { return 40; }
}
public override int Spread
{
get { return 3; }
}
public override void Fire(IProjectile projectile, Player player)
{
if (Heat + this.HeatGeneration > MaxHeat)
return;
Heat += 1f * this.HeatGeneration;
if (_lastShot <= DateTime.Now.AddMilliseconds(-this.Delay - (Heat >= HeatStartAffectAt ? Heat : 0)))
{
float angle = player.Angle + (float)(Randomizer.Next(-Spread * 100, Spread * 100) / 9000.0);
InternalFire(projectile, player, angle - 0.15f);
InternalFire(projectile, player, angle);
InternalFire(projectile, player, angle + 0.15f);
_lastShot = DateTime.Now;
}
}
private static void InternalFire(IProjectile projectile, IEntity player, float angle)
{
var entity = EntityFactory.Instance.CreateEntity<ProjectileBase>(
projectile.GetType(),
player.Owner,
player.Position,
new Vector2(),
angle);
Matrix m = Matrix.CreateRotationZ(angle);
Vector2 velocity = Vector2.Transform(-Vector2.UnitY, m);
entity.Position += velocity * (player.Origin.Y + entity.Origin.Y);
entity.Velocity = velocity * projectile.Speed;
entity.Velocity = player.Velocity + entity.Velocity;
FiredShots.Enqueue(entity);
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using SpacePew.Models.Projectiles;
namespace SpacePew.Models.Weapons
{
public abstract class WeaponBase : IWeapon
{
protected const int MaxHeat = 100;
protected const int HeatStartAffectAt = MaxHeat / 2;
static WeaponBase()
{
FiredShots = new Queue<IProjectile>();
}
public static Queue<IProjectile> FiredShots;
protected DateTime _lastShot;
private static Random _randomizer;
public static Random Randomizer
{
get { return _randomizer ?? (_randomizer = new Random()); }
}
private float _heat;
protected WeaponBase()
{
_lastShot = DateTime.Now;
}
public virtual float Heat
{
get { return _heat; }
set { _heat = value; }
}
#region IWeapon Members
public abstract float HeatGeneration { get; }
public abstract int Delay { get; }
public abstract int Spread { get; }
public virtual void Fire(IProjectile projectile, Player player)
{
if (_heat + this.HeatGeneration > MaxHeat)
return;
_heat += 1f * this.HeatGeneration;
if (_lastShot <= DateTime.Now.AddMilliseconds(-this.Delay - (_heat >= HeatStartAffectAt ? _heat : 0)))
{
float angle = player.Angle + (float)(Randomizer.Next(-Spread * 100, Spread * 100) / 9000.0);
var entity = EntityFactory.Instance.CreateEntity<ProjectileBase>(
projectile.GetType(),
player.Owner,
player.Position,
new Vector2(),
angle);
Matrix m = Matrix.CreateRotationZ(angle);
Vector2 velocity = Vector2.Transform(-Vector2.UnitY, m);
entity.Position += velocity * (player.Origin.Y + entity.Origin.Y);
entity.Velocity = velocity * projectile.Speed;
entity.Velocity = player.Velocity + entity.Velocity;
FiredShots.Enqueue(entity);
_lastShot = DateTime.Now;
}
}
#endregion
}
}