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

31
SpacePew/Arena.cs Normal file
View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
namespace SpacePew
{
public class Arena : DrawableGameComponent
{
public Arena(Game game) : base(game)
{
}
protected override void LoadContent()
{
base.LoadContent();
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
}
}

View File

@@ -0,0 +1,93 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew.Camera
{
public class Camera2D : GameComponent, ICamera2D
{
private Vector2 _position;
protected float _viewportHeight;
protected float _viewportWidth;
public Camera2D(Game game) : base(game) { }
#region Properties
public Vector2 Position
{
get { return _position; }
set { _position = value; }
}
public float Rotation { get; set; }
public Vector2 Origin { get; set; }
public float Scale { get; set; }
public Vector2 ScreenCenter { get; protected set; }
public Matrix Transform { get; set; }
public IFocusable Focus { get; set; }
public float MoveSpeed { get; set; }
#endregion
/// <summary>
/// Called when the GameComponent needs to be initialized.
/// </summary>
public override void Initialize()
{
_viewportWidth = Game.GraphicsDevice.Viewport.Width;
_viewportHeight = Game.GraphicsDevice.Viewport.Height;
ScreenCenter = new Vector2(_viewportWidth / 2, _viewportHeight / 2);
Scale = 1;
MoveSpeed = 5f;
base.Initialize();
}
public override void Update(GameTime gameTime)
{
// Create the Transform used by any
// spritebatch process
Transform = Matrix.Identity *
Matrix.CreateTranslation(-Position.X, -Position.Y, 0) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateTranslation(Origin.X, Origin.Y, 0) *
Matrix.CreateScale(new Vector3(Scale, Scale, Scale));
Origin = ScreenCenter / Scale;
// Move the Camera to the position that it needs to go
var delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
_position.X += (Focus.Position.X - Position.X) * MoveSpeed * delta;
_position.Y += (Focus.Position.Y - Position.Y) * MoveSpeed * delta;
base.Update(gameTime);
}
/// <summary>
/// Determines whether the target is in view given the specified position.
/// This can be used to increase performance by not drawing objects
/// directly in the viewport
/// </summary>
/// <param name="position">The position.</param>
/// <param name="texture">The texture.</param>
/// <returns>
/// <c>true</c> if [is in view] [the specified position]; otherwise, <c>false</c>.
/// </returns>
public bool IsInView(Vector2 position, Texture2D texture)
{
// If the object is not within the horizontal bounds of the screen
if ((position.X + texture.Width) < (Position.X - Origin.X) || (position.X) > (Position.X + Origin.X))
return false;
// If the object is not within the vertical bounds of the screen
if ((position.Y + texture.Height) < (Position.Y - Origin.Y) || (position.Y) > (Position.Y + Origin.Y))
return false;
// In View
return true;
}
}
}

View File

@@ -0,0 +1,72 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew.Camera
{
public interface ICamera2D
{
/// <summary>
/// Gets or sets the position of the camera
/// </summary>
/// <value>The position.</value>
Vector2 Position { get; set; }
/// <summary>
/// Gets or sets the move speed of the camera.
/// The camera will tween to its destination.
/// </summary>
/// <value>The move speed.</value>
float MoveSpeed { get; set; }
/// <summary>
/// Gets or sets the rotation of the camera.
/// </summary>
/// <value>The rotation.</value>
float Rotation { get; set; }
/// <summary>
/// Gets the origin of the viewport (accounts for Scale)
/// </summary>
/// <value>The origin.</value>
Vector2 Origin { get; }
/// <summary>
/// Gets or sets the scale of the Camera
/// </summary>
/// <value>The scale.</value>
float Scale { get; set; }
/// <summary>
/// Gets the screen center (does not account for Scale)
/// </summary>
/// <value>The screen center.</value>
Vector2 ScreenCenter { get; }
/// <summary>
/// Gets the transform that can be applied to
/// the SpriteBatch Class.
/// </summary>
/// <see cref="SpriteBatch"/>
/// <value>The transform.</value>
Matrix Transform { get; }
/// <summary>
/// Gets or sets the focus of the Camera.
/// </summary>
/// <seealso cref="IFocusable"/>
/// <value>The focus.</value>
IFocusable Focus { get; set; }
/// <summary>
/// Determines whether the target is in view given the specified position.
/// This can be used to increase performance by not drawing objects
/// directly in the viewport
/// </summary>
/// <param name="position">The position.</param>
/// <param name="texture">The texture.</param>
/// <returns>
/// <c>true</c> if the target is in view at the specified position; otherwise, <c>false</c>.
/// </returns>
bool IsInView(Vector2 position, Texture2D texture);
}
}

View File

@@ -0,0 +1,9 @@
using Microsoft.Xna.Framework;
namespace SpacePew.Camera
{
public interface IFocusable
{
Vector2 Position { get; }
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

88
SpacePew/EntityFactory.cs Normal file
View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Models;
namespace SpacePew
{
public class EntityFactory
{
public static EntityFactory Instance { get; private set; }
private MainGame _game;
private readonly List<IEntity> _entities = new List<IEntity>();
public IList<IEntity> Entities
{
get { return _entities; }
}
public void RemoveEntities(IEnumerable<IEntity> entities)
{
Action<IEntity> a = e =>
{
e.Collide(null);
_entities.Remove(e);
};
entities.ToList().ForEach(e =>
{
if (e is IKillable)
(e as IKillable).Kill();
_entities.Remove(e);
});
}
public void RemoveEntity(IEntity entity)
{
_entities.Remove(entity);
}
public EntityFactory(MainGame game)
{
Instance = this;
this._game = game;
}
public T CreateEntity<T>(string owner, Vector2 position, Vector2 velocity, float angle) where T : IEntity, new()
{
var entity = new T();
var tex = TextureManager.LoadTexture(entity.TextureName);
entity.Texture = tex;
entity.Position = position;
entity.Velocity = velocity;
entity.Angle = angle;
entity.Owner = owner;
this._entities.Add(entity);
entity.Created();
return entity;
}
public T CreateEntity<T>(Type entityType, string owner, Vector2 position, Vector2 velocity, float angle) where T : IEntity
{
T entity = (T)entityType.Assembly.CreateInstance(entityType.FullName);
Texture2D tex = TextureManager.LoadTexture(entity.TextureName);
entity.Texture = tex;
entity.Position = position;
entity.Velocity = velocity;
entity.Angle = angle;
entity.Owner = owner;
this._entities.Add(entity);
entity.Created();
return entity;
}
}
}

View File

@@ -0,0 +1,294 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using Lidgren.Network;
namespace SpacePew.Extensions
{
public static class LidgrenExtensions
{
/// <summary>
/// Write a Point
/// </summary>
public static void Write(this NetBuffer message, Point value)
{
message.Write(value.X);
message.Write(value.Y);
}
/// <summary>
/// Read a Point
/// </summary>
public static Point ReadPoint(this NetBuffer message)
{
return new Point(message.ReadInt32(), message.ReadInt32());
}
/// <summary>
/// Write a Single with half precision (16 bits)
/// </summary>
public static void WriteHalfPrecision(this NetBuffer message, float value)
{
message.Write(new HalfSingle(value).PackedValue);
}
/// <summary>
/// Reads a half precision Single written using WriteHalfPrecision(float)
/// </summary>
public static float ReadHalfPrecisionSingle(this NetBuffer message)
{
HalfSingle h = new HalfSingle();
h.PackedValue = message.ReadUInt16();
return h.ToSingle();
}
/// <summary>
/// Writes a Vector2
/// </summary>
public static void Write(this NetBuffer message, Vector2 vector)
{
message.Write(vector.X);
message.Write(vector.Y);
}
/// <summary>
/// Reads a Vector2
/// </summary>
public static Vector2 ReadVector2(this NetBuffer message)
{
Vector2 retval;
retval.X = message.ReadSingle();
retval.Y = message.ReadSingle();
return retval;
}
/// <summary>
/// Writes a Vector3
/// </summary>
public static void Write(this NetBuffer message, Vector3 vector)
{
message.Write(vector.X);
message.Write(vector.Y);
message.Write(vector.Z);
}
/// <summary>
/// Writes a Vector3 at half precision
/// </summary>
public static void WriteHalfPrecision(this NetBuffer message, Vector3 vector)
{
message.Write(new HalfSingle(vector.X).PackedValue);
message.Write(new HalfSingle(vector.Y).PackedValue);
message.Write(new HalfSingle(vector.Z).PackedValue);
}
/// <summary>
/// Reads a Vector3
/// </summary>
public static Vector3 ReadVector3(this NetBuffer message)
{
Vector3 retval;
retval.X = message.ReadSingle();
retval.Y = message.ReadSingle();
retval.Z = message.ReadSingle();
return retval;
}
/// <summary>
/// Writes a Vector3 at half precision
/// </summary>
public static Vector3 ReadHalfPrecisionVector3(this NetBuffer message)
{
HalfSingle hx = new HalfSingle();
hx.PackedValue = message.ReadUInt16();
HalfSingle hy = new HalfSingle();
hy.PackedValue = message.ReadUInt16();
HalfSingle hz = new HalfSingle();
hz.PackedValue = message.ReadUInt16();
Vector3 retval;
retval.X = hx.ToSingle();
retval.Y = hy.ToSingle();
retval.Z = hz.ToSingle();
return retval;
}
/// <summary>
/// Writes a Vector4
/// </summary>
public static void Write(this NetBuffer message, Vector4 vector)
{
message.Write(vector.X);
message.Write(vector.Y);
message.Write(vector.Z);
message.Write(vector.W);
}
/// <summary>
/// Reads a Vector4
/// </summary>
public static Vector4 ReadVector4(this NetBuffer message)
{
Vector4 retval;
retval.X = message.ReadSingle();
retval.Y = message.ReadSingle();
retval.Z = message.ReadSingle();
retval.W = message.ReadSingle();
return retval;
}
/// <summary>
/// Writes a unit vector (ie. a vector of length 1.0, for example a surface normal)
/// using specified number of bits
/// </summary>
public static void WriteUnitVector3(this NetBuffer message, Vector3 unitVector, int numberOfBits)
{
float x = unitVector.X;
float y = unitVector.Y;
float z = unitVector.Z;
double invPi = 1.0 / Math.PI;
float phi = (float)(Math.Atan2(x, y) * invPi);
float theta = (float)(Math.Atan2(z, Math.Sqrt(x * x + y * y)) * (invPi * 2));
int halfBits = numberOfBits / 2;
message.WriteSignedSingle(phi, halfBits);
message.WriteSignedSingle(theta, numberOfBits - halfBits);
}
/// <summary>
/// Reads a unit vector written using WriteUnitVector3(numberOfBits)
/// </summary>
public static Vector3 ReadUnitVector3(this NetBuffer message, int numberOfBits)
{
int halfBits = numberOfBits / 2;
float phi = message.ReadSignedSingle(halfBits) * (float)Math.PI;
float theta = message.ReadSignedSingle(numberOfBits - halfBits) * (float)(Math.PI * 0.5);
Vector3 retval;
retval.X = (float)(Math.Sin(phi) * Math.Cos(theta));
retval.Y = (float)(Math.Cos(phi) * Math.Cos(theta));
retval.Z = (float)Math.Sin(theta);
return retval;
}
/// <summary>
/// Writes a unit quaternion using the specified number of bits per element
/// for a total of 4 x bitsPerElements bits. Suggested value is 8 to 24 bits.
/// </summary>
public static void WriteRotation(this NetBuffer message, Quaternion quaternion, int bitsPerElement)
{
if (quaternion.X > 1.0f)
quaternion.X = 1.0f;
if (quaternion.Y > 1.0f)
quaternion.Y = 1.0f;
if (quaternion.Z > 1.0f)
quaternion.Z = 1.0f;
if (quaternion.W > 1.0f)
quaternion.W = 1.0f;
if (quaternion.X < -1.0f)
quaternion.X = -1.0f;
if (quaternion.Y < -1.0f)
quaternion.Y = -1.0f;
if (quaternion.Z < -1.0f)
quaternion.Z = -1.0f;
if (quaternion.W < -1.0f)
quaternion.W = -1.0f;
message.WriteSignedSingle(quaternion.X, bitsPerElement);
message.WriteSignedSingle(quaternion.Y, bitsPerElement);
message.WriteSignedSingle(quaternion.Z, bitsPerElement);
message.WriteSignedSingle(quaternion.W, bitsPerElement);
}
/// <summary>
/// Reads a unit quaternion written using WriteRotation(... ,bitsPerElement)
/// </summary>
public static Quaternion ReadRotation(this NetBuffer message, int bitsPerElement)
{
Quaternion retval;
retval.X = message.ReadSignedSingle(bitsPerElement);
retval.Y = message.ReadSignedSingle(bitsPerElement);
retval.Z = message.ReadSignedSingle(bitsPerElement);
retval.W = message.ReadSignedSingle(bitsPerElement);
return retval;
}
/// <summary>
/// Writes an orthonormal matrix (rotation, translation but not scaling or projection)
/// </summary>
public static void WriteMatrix(this NetBuffer message, ref Matrix matrix)
{
Quaternion rot = Quaternion.CreateFromRotationMatrix(matrix);
WriteRotation(message, rot, 24);
message.Write(matrix.M41);
message.Write(matrix.M42);
message.Write(matrix.M43);
}
/// <summary>
/// Writes an orthonormal matrix (rotation, translation but no scaling or projection)
/// </summary>
public static void WriteMatrix(this NetBuffer message, Matrix matrix)
{
Quaternion rot = Quaternion.CreateFromRotationMatrix(matrix);
WriteRotation(message, rot, 24);
message.Write(matrix.M41);
message.Write(matrix.M42);
message.Write(matrix.M43);
}
/// <summary>
/// Reads a matrix written using WriteMatrix()
/// </summary>
public static Matrix ReadMatrix(this NetBuffer message)
{
Quaternion rot = ReadRotation(message, 24);
Matrix retval = Matrix.CreateFromQuaternion(rot);
retval.M41 = message.ReadSingle();
retval.M42 = message.ReadSingle();
retval.M43 = message.ReadSingle();
return retval;
}
/// <summary>
/// Reads a matrix written using WriteMatrix()
/// </summary>
public static void ReadMatrix(this NetBuffer message, ref Matrix destination)
{
Quaternion rot = ReadRotation(message, 24);
destination = Matrix.CreateFromQuaternion(rot);
destination.M41 = message.ReadSingle();
destination.M42 = message.ReadSingle();
destination.M43 = message.ReadSingle();
}
/// <summary>
/// Writes a bounding sphere
/// </summary>
public static void Write(this NetBuffer message, BoundingSphere bounds)
{
message.Write(bounds.Center.X);
message.Write(bounds.Center.Y);
message.Write(bounds.Center.Z);
message.Write(bounds.Radius);
}
/// <summary>
/// Reads a bounding sphere written using Write(message, BoundingSphere)
/// </summary>
public static BoundingSphere ReadBoundingSphere(this NetBuffer message)
{
BoundingSphere retval;
retval.Center.X = message.ReadSingle();
retval.Center.Y = message.ReadSingle();
retval.Center.Z = message.ReadSingle();
retval.Radius = message.ReadSingle();
return retval;
}
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Models;
namespace SpacePew.Extensions
{
public static class RenderExtensions
{
public static Vector2 AsVector2D(this Point p)
{
return new Vector2(p.X, p.Y);
}
public static void Draw(this SpriteBatch batch, TiledTexture texture, Rectangle destination, Color color)
{
Draw(batch, texture, destination, new Rectangle(0, 0, texture.Width, texture.Height), color);
}
public static void Draw(this SpriteBatch batch, TiledTexture texture, Rectangle dstRect, Rectangle srcRect, Color color)
{
//TODO: kolla om dom ens syns innan man renderar.. hur man nu ska kunna göra det..
var wratio = dstRect.Width / (double)srcRect.Width;
var hratio = dstRect.Height / (double)srcRect.Height;
var pos = new Point(dstRect.X, dstRect.Y);
dstRect = new Rectangle(0, 0, (int)(wratio * texture.TileWidth), (int)(hratio * texture.TileHeight));
for (var j = 0; j < texture.XTiles; j++)
{
for (var i = 0; i < texture.YTiles; i++)
{
//if srcRect.Intersects tile
var tile = texture[i * texture.XTiles + j];
dstRect.X = pos.X + (int)(tile.Position.X * wratio);
dstRect.Y = pos.Y + (int)(tile.Position.Y * hratio);
batch.Draw(tile.Texture, dstRect, color);
}
}
}
}
}

BIN
SpacePew/Game.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
SpacePew/GameThumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

112
SpacePew/Hud.cs Normal file
View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Models;
namespace SpacePew
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
public class Hud : GameComponent, IDrawable
{
SpriteBatch _spriteBatch;
readonly MainGame _game;
SpriteFont _consoleFont;
public Hud(MainGame game)
: base(game)
{
_game = game;
}
/// <summary>
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
/// </summary>
public override void Initialize()
{
_spriteBatch = new SpriteBatch(_game.GraphicsDevice);
_consoleFont = _game.Content.Load<SpriteFont>("Fonts\\ConsoleFont");
base.Initialize();
}
public void Draw(GameTime gameTime)
{
if (_game.NetworkClient.LocalPlayer != null)
{
_spriteBatch.Begin();
_spriteBatch.DrawString(_consoleFont,
string.Format("Health: {0}",
_game.NetworkClient.LocalPlayer.Health),
new Vector2(300, _game.GraphicsDevice.Viewport.Height - 100),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Fuel: {0}",
_game.NetworkClient.LocalPlayer.Fuel),
new Vector2(300, _game.GraphicsDevice.Viewport.Height - 75),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Heat #1: {0}",
_game.NetworkClient.LocalPlayer.Weapon.Heat),
new Vector2(500, _game.GraphicsDevice.Viewport.Height - 100),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Heat #2: {0}",
_game.NetworkClient.LocalPlayer.SecondaryWeapon.Heat),
new Vector2(500, _game.GraphicsDevice.Viewport.Height - 75),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Entities: {0}",
((List<IEntity>)EntityFactory.Instance.Entities).Count),
new Vector2(500, _game.GraphicsDevice.Viewport.Height - 50),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Pos X: {0}",
_game.NetworkClient.LocalPlayer.Position.X),
new Vector2(700, _game.GraphicsDevice.Viewport.Height - 100),
Color.White);
_spriteBatch.DrawString(_consoleFont,
string.Format("Pos Y: {0}",
_game.NetworkClient.LocalPlayer.Position.Y),
new Vector2(700, _game.GraphicsDevice.Viewport.Height - 75),
Color.White);
_spriteBatch.End();
}
}
public int DrawOrder
{
get { return 2; }
}
public bool Visible
{
get { return true; }
}
event EventHandler<EventArgs> IDrawable.DrawOrderChanged
{
add { }
remove { }
}
event EventHandler<EventArgs> IDrawable.VisibleChanged
{
add { }
remove { }
}
}
}

BIN
SpacePew/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

663
SpacePew/KeyboardHelper.cs Normal file
View File

@@ -0,0 +1,663 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
namespace SpacePew
{
[Flags]
public enum KbModifiers
{
None = 0,
Ctrl = 1,
Shift = 2,
Alt = 4,
}
public static class KeyboardHelper
{
public static bool TreadNumpadAsNumeric = true;
private static readonly string[] _unShiftedKeysString = new string[256]
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
" ",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"",
"",
"",
"",
"",
"",
"",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"",
"",
"",
"",
"",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"*",
"+",
"",
"-",
".",
"/",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
";",
"=",
",",
"-",
".",
"/",
"`",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"[",
"\\",
"]",
"'",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
};
private static string[] shiftedkeysstring = new string[256]
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
" ",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
")",
"!",
"@",
"#",
"$",
"%",
"^",
"&",
"*",
"(",
"",
"",
"",
"",
"",
"",
"",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"*",
"+",
"",
"-",
".",
"/",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
":",
"+",
"<",
"_",
">",
"?",
"~",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"{",
"|",
"}",
"\"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
};
static KeyboardHelper()
{
}
public static bool IsKeyAlpha(Keys k)
{
return k >= Keys.A && k <= Keys.Z;
}
public static bool IsKeyNumber(Keys k)
{
return k >= Keys.D0 && k <= Keys.D9;
}
public static bool IsKeyNumberpad(Keys k)
{
return k >= Keys.NumPad0 && k <= Keys.NumPad9;
}
public static bool IsKeyNumeric(Keys k)
{
return KeyboardHelper.IsKeyNumber(k) || KeyboardHelper.TreadNumpadAsNumeric && KeyboardHelper.IsKeyNumberpad(k);
}
public static bool IsKeyAlphanumeric(Keys k)
{
return KeyboardHelper.IsKeyAlpha(k) || KeyboardHelper.IsKeyNumeric(k);
}
public static bool IsFkey(Keys k)
{
return k >= Keys.F1 && k <= Keys.F12;
}
public static bool IsKeySpace(Keys k)
{
return k == Keys.Space;
}
public static bool IsShift(Keys k)
{
return k == Keys.LeftShift || k == Keys.RightShift;
}
public static bool IsCtrl(Keys k)
{
return k == Keys.LeftControl || k == Keys.RightControl;
}
public static bool IsAlt(Keys k)
{
return k == Keys.LeftAlt || k == Keys.RightAlt;
}
public static bool IsShiftDown(KbModifiers m)
{
return (KbModifiers.Shift & m) == KbModifiers.Shift;
}
public static bool IsCtrlDown(KbModifiers m)
{
return (KbModifiers.Ctrl & m) == KbModifiers.Ctrl;
}
public static bool IsAltDown(KbModifiers m)
{
return (KbModifiers.Alt & m) == KbModifiers.Alt;
}
public static bool IsMod(Keys k)
{
return KeyboardHelper.IsShift(k) || KeyboardHelper.IsAlt(k) || KeyboardHelper.IsCtrl(k);
}
public static KbModifiers IsShiftM(Keys k)
{
return k == Keys.LeftShift || k == Keys.RightShift ? KbModifiers.Shift : KbModifiers.None;
}
public static KbModifiers IsCtrlM(Keys k)
{
return k == Keys.LeftControl || k == Keys.RightControl ? KbModifiers.Ctrl : KbModifiers.None;
}
public static KbModifiers IsAltM(Keys k)
{
return k == Keys.LeftAlt || k == Keys.RightAlt ? KbModifiers.Alt : KbModifiers.None;
}
public static string ToPrintableString(Keys k, KbModifiers m)
{
return KeyboardHelper.ToPrintableString(k, m, true, true, true, false);
}
public static string ToPrintableString(Keys k, KbModifiers m, bool selectspecials)
{
return KeyboardHelper.ToPrintableString(k, m, selectspecials, true, true, false);
}
public static string ToPrintableString(Keys k, KbModifiers m, bool selectspecials, bool selectalphas, bool selectnumerics)
{
return KeyboardHelper.ToPrintableString(k, m, selectspecials, selectalphas, selectnumerics, false);
}
public static string ToPrintableString(Keys k, KbModifiers m, bool selectspecials, bool selectalphas, bool selectnumerics, bool suppressspace)
{
if (KeyboardHelper.IsKeySpace(k) && !suppressspace)
return " ";
if (KeyboardHelper.IsKeyAlpha(k) && selectalphas || KeyboardHelper.IsKeyNumber(k) && selectnumerics || KeyboardHelper.TreadNumpadAsNumeric && KeyboardHelper.IsKeyNumberpad(k) && selectnumerics || selectspecials && (!KeyboardHelper.IsKeyAlpha(k) && !KeyboardHelper.IsKeyNumeric(k) || KeyboardHelper.IsKeyNumber(k) && KeyboardHelper.IsShiftDown(m)))
{
if (!KeyboardHelper.IsShiftDown(m))
return KeyboardHelper._unShiftedKeysString[k.GetHashCode()];
if (selectspecials || !KeyboardHelper.IsKeyNumber(k))
return KeyboardHelper.shiftedkeysstring[k.GetHashCode()];
}
return "";
}
public static KbModifiers GetModifiers(KeyboardState ks)
{
return ks.GetPressedKeys().Aggregate(KbModifiers.None, (current, k) => current | KeyboardHelper.IsShiftM(k) | KeyboardHelper.IsAltM(k) | KeyboardHelper.IsCtrlM(k));
}
}
}

181
SpacePew/LevelLoader.cs Normal file
View File

@@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Media;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using SpacePew.Models;
using Rectangle = System.Drawing.Rectangle;
namespace SpacePew
{
static class LevelLoader
{
public static Level LoadLevel(string filePath, ContentManager cm, GraphicsDevice device)
{
var levelResources = GetResourceList(filePath);
if (!levelResources.ContainsKey("leveldata.xml"))
throw new InvalidOperationException("Level: " + filePath + " doesnt contain any leveldata.xml");
var levelData = GetXmlFile(levelResources["leveldata.xml"]);
string baseTexture = levelData.SelectSingleNode("//baseTexture").InnerText.ToLower();
string indestructibleTexture = levelData.SelectSingleNode("//indestructibleTexture").InnerText.ToLower();
var spriteBatch = new SpriteBatch(device);
var level = new Level();
level.FilePath = filePath;
level.Texture = LoadTextureTiles(levelResources[baseTexture], device, spriteBatch);
level.IndestructibleTexture = LoadTextureTiles(levelResources[indestructibleTexture], device, spriteBatch);
level.DeformedTexture = new TiledTexture
{
Width = level.Texture.Width,
Height = level.Texture.Height,
TileHeight = level.Texture.TileHeight,
TileWidth = level.Texture.TileWidth,
XTiles = level.Texture.XTiles,
YTiles = level.Texture.YTiles
};
level.Texture.ForEach(t => level.DeformedTexture.Add(new Tile(
new RenderTarget2D(device, level.Texture.TileWidth, level.Texture.TileHeight, false,
SurfaceFormat.Color, DepthFormat.Depth24,
device.PresentationParameters.MultiSampleCount,
RenderTargetUsage.PreserveContents
),
t.Position)));
if (levelData.SelectSingleNode("//song") != null)
{
string songName = levelData.SelectSingleNode("//song").InnerText.ToLower();
level.OggVorbisSong = levelResources[songName];
}
level.Initialize();
return level;
}
private static XmlDocument GetXmlFile(byte[] rawData)
{
var d = new XmlDocument();
d.LoadXml(System.Text.Encoding.UTF8.GetString(rawData));
return d;
}
public static TiledTexture LoadTextureTiles(Byte[] bitmapData, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
using (var ms = new MemoryStream(bitmapData))
{
ms.Seek(0, SeekOrigin.Begin);
using (var image = Image.FromStream(ms))
{
return LoadTextureTiles(image, device, spriteBatch, tileWidth, tileHeight);
}
}
}
public static TiledTexture LoadTextureTiles(string fileName, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
using (var image = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + fileName.Replace("/", "\\")))
{
return LoadTextureTiles(image, device, spriteBatch, tileWidth, tileHeight);
}
}
public static TiledTexture LoadTextureTiles(Image image, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
//OBS!!! S<>tt kartans bredd el h<>jd till ett primtal o det <20>r k<>rt iom att d<> kan man inte hitta en j<>mn multiple och en oj<6F>mn kommer att anv<6E>ndas
//och det kommer att pricka i framtiden.
if (tileWidth == 0)
tileWidth = FindNearbyMultiple(image.Width, 1000);
if (tileHeight == 0)
tileHeight = FindNearbyMultiple(image.Height, 1000);
int tilesX = (image.Width % tileWidth == 0)
? (int)Math.Floor(image.Width / (double)tileWidth)
: (int)Math.Ceiling(image.Width / (double)tileWidth);
int tilesY = (image.Height % tileHeight == 0)
? (int)Math.Floor(image.Height / (double)tileHeight)
: (int)Math.Ceiling(image.Height / (double)tileHeight);
var ret = new TiledTexture
{
TileWidth = tileWidth,
TileHeight = tileHeight,
XTiles = tilesX,
YTiles = tilesY,
Width = image.Width,
Height = image.Height
};
for (var j = 0; j < tilesX; j++)
{
for (var i = 0; i < tilesY; i++)
{
var part = new Bitmap(tileWidth, tileHeight, image.PixelFormat);
var graphics = Graphics.FromImage(part);
var srcRect = new Rectangle(j * tileWidth, i * tileHeight, tileWidth, tileHeight);
graphics.DrawImage(image, 0, 0, srcRect, GraphicsUnit.Pixel);
using (var ms = new MemoryStream())
{
//TODO: n<>got vettigare <20>n s<> h<>r f<>r att f<> fram bytesen... tar ju <20>r och dagar att ladda nu.
part.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
ret.Add(new Tile(Texture2D.FromStream(device, ms), new Microsoft.Xna.Framework.Point(j * tileWidth, i * tileHeight)));
}
}
}
return ret;
}
private static int FindNearbyMultiple(int totLen, int chunkLen)
{
chunkLen = totLen / (int)Math.Ceiling(totLen / (double)chunkLen);
var step = 0;
while (step < 100)
{
var t = chunkLen - step;
if ((totLen % t) == 0)
return t;
t = chunkLen + step;
if ((totLen % t) == 0)
return t;
step++;
}
return FindNearbyMultiple(totLen - 1, chunkLen);
}
private static Dictionary<string, byte[]> GetResourceList(string file)
{
var resources = new Dictionary<string, byte[]>();
using (var stream = new ZipInputStream(File.OpenRead(file)))
{
ZipEntry entry = null;
while ((entry = stream.GetNextEntry()) != null)
{
if (entry.Name.Length > 0)
{
var buf = new byte[(int)entry.Size];
stream.Read(buf, 0, buf.Length);
resources.Add(entry.Name.ToLower().Trim(), buf);
}
}
}
return resources;
}
}
}

BIN
SpacePew/Levels/hippie.zip Normal file

Binary file not shown.

483
SpacePew/MainGame.cs Normal file
View File

@@ -0,0 +1,483 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using SpacePew.Camera;
using SpacePew.Models;
using SpacePew.Models.Weapons;
using SpacePew.Networking;
using SpacePew.ParticleSystem;
using Color = Microsoft.Xna.Framework.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;
using SpacePew.Extensions;
using System.Linq;
using System.Windows.Forms;
namespace SpacePew
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class MainGame : Game
{
public static int CenterX;
public static int CenterY;
public UdpServer NetworkServer { get; private set; }
public UdpClient NetworkClient { get; private set; }
private Level _level;
public Level Level
{
get { return _level; }
set { _level = value; }
}
private SpriteBatch _spriteBatch;
public SpriteBatch SpriteBatch
{
get
{
return _spriteBatch;
}
}
readonly GraphicsDeviceManager _graphics;
readonly EntityFactory _entityFactory;
Hud _hud;
Minimap _minimap;
private readonly UdpNetworkGui _udpClientGui;
private KeyboardState _currentKeyboardState;
private GamePadState _currentGamePadState;
private Texture2D _backgroundTexture;
private ExplosionParticleSystem _explosion;
private ExplosionSmokeParticleSystem _smoke;
private SmokePlumeParticleSystem _smokePlume;
private NetworkMessenger _networkMessenger;
private Song _gameSong;
public Song GameSong
{
get { return _gameSong; }
}
private ICamera2D _camera;
private readonly Random _randomizer;
public static bool IsKeyboardInUse;
public void AddGameComponents()
{
_hud = new Hud(this);
Components.Add(_hud);
_minimap = new Minimap(this);
Components.Add(_minimap);
_camera = new Camera2D(this)
{
Focus = NetworkClient.LocalPlayer
};
Components.Add((IGameComponent)_camera);
_explosion = new ExplosionParticleSystem(this, 1, _camera);
Components.Add(_explosion);
_smoke = new ExplosionSmokeParticleSystem(this, 2, _camera);
Components.Add(_smoke);
_smokePlume = new SmokePlumeParticleSystem(this, 9, _camera);
Components.Add(_smokePlume);
_networkMessenger = new NetworkMessenger(this, NetworkClient);
Components.Add(_networkMessenger);
Components.Add(new ScoreBoard(this, NetworkClient));
}
public void AddExplosion(Vector2 position, float size)
{
_explosion.AddParticles(position, size);
_smoke.AddParticles(position, size);
}
public MainGame()
{
Trace.Listeners.Add(new TextWriterTraceListener("debug.log"));
Trace.AutoFlush = true;
Trace.Indent();
Trace.WriteLine(string.Empty);
Trace.WriteLine(DateTime.Now);
Trace.WriteLine("------------------------------------------------------------------------------------------------------------------");
Window.Title = "Space, pew pew!";
Content.RootDirectory = "Content";
NetworkServer = new UdpServer();
NetworkClient = new UdpClient(this);
_graphics = new GraphicsDeviceManager(this);
_entityFactory = new EntityFactory(this);
SoundManager.Initialize(this);
TextureManager.Initialize(this);
IsMouseVisible = true;
_graphics.CreateDevice();
Cursor.Hide();
_graphics.PreferredBackBufferWidth = 1366;
_graphics.PreferredBackBufferHeight = 768;
//var screen = Screen.AllScreens.First(e => e.Primary);
//Window.IsBorderless = true;
//Window.Position = new Point(screen.Bounds.X, screen.Bounds.Y);
//_graphics.PreferredBackBufferWidth = screen.Bounds.Width;
//_graphics.PreferredBackBufferHeight = screen.Bounds.Height;
_graphics.ApplyChanges();
CenterX = _graphics.PreferredBackBufferWidth / 2;
CenterY = _graphics.PreferredBackBufferHeight / 2;
_randomizer = new Random();
_udpClientGui = new UdpNetworkGui(this, _graphics, (UdpClient)NetworkClient, (UdpServer)NetworkServer);
Components.Add(_udpClientGui);
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
_udpClientGui.Initialize();
_spriteBatch = new SpriteBatch(GraphicsDevice);
_backgroundTexture = TextureManager.LoadTexture("stars");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
}
protected override void OnExiting(object sender, EventArgs args)
{
if (_level != null)
{
_level.StopLevelSong();
}
if (NetworkClient.IsSessionAlive)
{
NetworkClient.ExitSession("Quitting...");
}
NetworkServer.Shutdown();
Trace.WriteLine("Exiting");
Trace.Unindent();
Trace.Flush();
base.OnExiting(sender, args);
}
/// <summary>
/// Handles input.
/// </summary>
private void HandleInput()
{
_currentKeyboardState = Keyboard.GetState();
_currentGamePadState = GamePad.GetState(PlayerIndex.One);
// Check for exit.
if (IsActive && IsPressed(Microsoft.Xna.Framework.Input.Keys.Escape, Buttons.Back))
{
Exit();
}
}
/// <summary>
/// Checks if the specified button is pressed on either keyboard or gamepad.
/// </summary>
bool IsPressed(Microsoft.Xna.Framework.Input.Keys key, Buttons button)
{
return (_currentKeyboardState.IsKeyDown(key) || _currentGamePadState.IsButtonDown(button));
}
/// <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)
{
HandleInput();
if (!NetworkClient.IsSessionAlive || NetworkClient.LocalPlayer == null)
{
// If we are not in a network session, update the
// menu screen that will let us create or join one.
}
else
{
while (WeaponBase.FiredShots.Count > 0)
{
NetworkClient.EntitiesToSend.Add(WeaponBase.FiredShots.Dequeue());
}
NetworkClient.Update();
NetworkClient.LocalPlayer.HandleKeyboard(Keyboard.GetState());
var entitiesToKill = new HashSet<IEntity>();
//fixa en metod f<>r entity som sk<73>ter det h<>r..
foreach (var entity in _entityFactory.Entities)
{
entity.Update(gameTime);
foreach (var player in NetworkClient.Players)
{
if (player.IsCollisionWith(entity))
{
player.CollideWith(entity);
if (!(entity is Player))
{
AddExplosion(entity.Position, 0.05f);
entitiesToKill.Add(entity);
}
}
if (player == NetworkClient.LocalPlayer && player.Health <= 0)
{
AddExplosion(player.Position, 1f);
player.Kill();
NetworkClient.SendDeath(entity);
var message = new NetworkMessage
{
Sent = DateTime.Now
};
if (player.Owner == entity.Owner)
{
message.Color = player.Color;
message.Message = string.Format("- {0} commited suicide.", player.Owner);
}
else
{
var killer = ((List<Player>)NetworkClient.Players).Find(p => p.Owner == entity.Owner);
message.Message = string.Format("{0} killed {1}.", entity.Owner, player.Owner);
message.Color = killer.Color;
}
NetworkMessenger.SendMessage(message);
}
}
entity.Health -= _level.Collide(entity, CenterX, CenterY);
if (NetworkClient.LocalPlayer.Health <= 0)
{
AddExplosion(NetworkClient.LocalPlayer.Position, 1f);
NetworkClient.LocalPlayer.Kill();
NetworkMessenger.AddDeath(NetworkClient.LocalPlayer);
NetworkMessenger.SendMessage(new NetworkMessage
{
Color = NetworkClient.LocalPlayer.Color,
Message = GetRandomCrashMessage(),
Sent = DateTime.Now
});
}
if (!(entity is Player) && entity.Health <= 0)
{
entitiesToKill.Add(entity);
AddExplosion(entity.Position, 0.05f);
}
}
_entityFactory.RemoveEntities(entitiesToKill);
}
base.Update(gameTime);
}
private string GetRandomCrashMessage()
{
int random = _randomizer.Next(0, 3);
var crashMessages = new List<string>
{
"{0} is driving under influence.",
"{0} crashed.",
"{0} sent himself straight towards the wall."
};
return string.Format(crashMessages[random], NetworkClient.LocalPlayer.Owner);
}
/// <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.Black);
if (NetworkClient.IsSessionAlive)
{
if (!BeginDraw() || NetworkClient.LocalPlayer == null)
return;
_graphics.GraphicsDevice.Clear(Color.Black);
RenderDeformation();
RenderTiledBackground();
RenderLevel();
RenderEntities();
}
base.Draw(gameTime);
}
private static readonly BlendState
opaqueExceptAlpha = new BlendState
{
ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.One,
ColorDestinationBlend = Blend.InverseDestinationAlpha,
AlphaDestinationBlend = Blend.InverseDestinationAlpha,
ColorWriteChannels = ColorWriteChannels.Alpha
};
void RenderDeformation()
{
var hits = new List<MapHit>();
while (_level.Hits.Count > 0)
{
hits.Add(_level.Hits.Dequeue());
}
foreach (var tile in _level.DeformedTexture)
{
_graphics.GraphicsDevice.SetRenderTarget((RenderTarget2D)tile.Texture);
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); // TODO: fixa blendstaten d<>r uppe s<> att den tar h<>nsyn till alpha i source
foreach (var hit in hits)
{
_spriteBatch.Draw(hit.Texture,
hit.Position + _camera.ScreenCenter - tile.Position.AsVector2D(),
null,
Color.Black,
hit.Angle,
hit.Origin,
1,
SpriteEffects.None,
1);
}
_spriteBatch.End();
}
_graphics.GraphicsDevice.SetRenderTarget(null);
}
private void RenderTiledBackground()
{
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
var pos = Vector2.Zero;
var scrollPos = NetworkClient.LocalPlayer.Position / 3.0f;
int startX = ((int)scrollPos.X) % _backgroundTexture.Width;
int startY = ((int)scrollPos.Y) % _backgroundTexture.Height;
for (int y = -startY; y < GraphicsDevice.Viewport.Height; y += _backgroundTexture.Height)
{
for (int x = -startX; x < GraphicsDevice.Viewport.Width; x += _backgroundTexture.Width)
{
pos.X = x; pos.Y = y;
_spriteBatch.Draw(_backgroundTexture, pos, Color.White);
}
}
_spriteBatch.End();
}
void RenderLevel()
{
var bounds = new Rectangle(0, 0, _level.Texture.TileWidth, _level.Texture.TileHeight);
var viewPort = new Rectangle(
(int)_camera.Position.X - _graphics.GraphicsDevice.Viewport.Width / 2,
(int)_camera.Position.Y - _graphics.GraphicsDevice.Viewport.Height / 2,
_graphics.GraphicsDevice.Viewport.Width + _graphics.GraphicsDevice.Viewport.Width / 2,
_graphics.GraphicsDevice.Viewport.Height + _graphics.GraphicsDevice.Viewport.Height / 2);
for (var i = 0; i < _level.Texture.Count; i++)
{
var tile = _level.Texture[i];
var deformedTile = _level.DeformedTexture[i];
var indestructibleTile = _level.IndestructibleTexture[i];
bounds.X = tile.Position.X;
bounds.Y = tile.Position.Y;
if (viewPort.Intersects(bounds))
{
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
_spriteBatch.Draw(indestructibleTile.Texture, new Vector2(indestructibleTile.Position.X - _camera.Position.X, indestructibleTile.Position.Y - _camera.Position.Y));
_spriteBatch.Draw(deformedTile.Texture, new Vector2(deformedTile.Position.X - _camera.Position.X, deformedTile.Position.Y - _camera.Position.Y));
_spriteBatch.End();
}
}
}
private void RenderEntities()
{
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, _camera.Transform);
foreach (var entity in _entityFactory.Entities)
{
_spriteBatch.Draw(entity.Texture,
entity.Position,
null,
entity.Color,
entity.Angle,
entity.Origin,
1,
SpriteEffects.None,
1);
}
_spriteBatch.End();
}
}
}

111
SpacePew/Minimap.cs Normal file
View File

@@ -0,0 +1,111 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Extensions;
using SpacePew.Models;
namespace SpacePew
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
public class Minimap : GameComponent, IDrawable
{
private const int MinimapWidth = 160;
private int _minimapModifier;
private readonly MainGame _game;
private SpriteBatch _spriteBatch;
private int _screenWidth;
private int _screenHeight;
private Texture2D _miniPlayer;
public Minimap(MainGame game)
: base(game)
{
_game = game;
}
/// <summary>
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
/// </summary>
public override void Initialize()
{
_spriteBatch = new SpriteBatch(_game.GraphicsDevice);
_screenWidth = _game.GraphicsDevice.PresentationParameters.BackBufferWidth;
_screenHeight = _game.GraphicsDevice.PresentationParameters.BackBufferHeight;
_miniPlayer = TextureManager.LoadTexture("bullet");
base.Initialize();
}
public void Draw(GameTime gameTime)
{
if (_game.NetworkClient.LocalPlayer != null)
{
_minimapModifier = _game.Level.Texture.Width / MinimapWidth;
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
int minimapHeight = _game.Level.Texture.Height / _minimapModifier > _screenHeight ?
_screenHeight - 20 :
_game.Level.Texture.Height / _screenHeight;
if (minimapHeight > _screenHeight)
minimapHeight = _screenHeight - 20;
var rect = new Rectangle(10, _screenHeight - minimapHeight - 10,
_game.Level.Texture.Width / _minimapModifier,
minimapHeight);
//Skriv ut spelarpluppen <20>ver hela ytan i svart f<>r att rensa
_spriteBatch.Draw(_miniPlayer, rect, Color.Black);
_spriteBatch.Draw(_game.Level.DeformedTexture, rect, Color.White);
_spriteBatch.Draw(_game.Level.IndestructibleTexture, rect, Color.White);
float xScale = _game.Level.Texture.Width / (float)rect.Width;
float yScale = _game.Level.Texture.Height / (float)rect.Height;
float centerX = _screenWidth / 2;
float centerY = _screenHeight / 2;
foreach (Player player in _game.NetworkClient.Players)
{
var miniMapPosition = new Vector2(rect.X - 1 + (player.Position.X + centerX) / xScale, rect.Y - 1 + (player.Position.Y + centerY) / yScale);
_spriteBatch.Draw(_miniPlayer, miniMapPosition, player.Color);
}
_spriteBatch.End();
}
}
public int DrawOrder
{
get { return 2; }
}
public bool Visible
{
get { return true; }
}
event EventHandler<EventArgs> IDrawable.DrawOrderChanged
{
add { }
remove { }
}
event EventHandler<EventArgs> IDrawable.VisibleChanged
{
add { }
remove { }
}
}
}

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
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SpacePew.Models;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew.Networking
{
public class NetworkMessage
{
// TODO: Add SoundAssetName to make NetworkMessenger play custom sounds upon different messages
public string Message { get; set; }
public DateTime Sent { get; set; }
public Color Color { get; set; }
public bool IsChatMessage { get; set; }
}
}

View File

@@ -0,0 +1,374 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using SpacePew.Models;
namespace SpacePew.Networking
{
/// <summary>
/// TODO: This is not really a network messenger yet, so we need to change the functionality a little (send all message over network in the loop down there)
/// </summary>
public class NetworkMessenger : Microsoft.Xna.Framework.GameComponent, IDrawable
{
private readonly MainGame _game;
private SpriteBatch _spriteBatch;
private SpriteFont _netFont;
private Rectangle _chatRectangle;
private Rectangle _textBounds;
private static UdpClient _client;
private static List<NetworkMessage> _messages;
private const int DefaultMessageLifeTime = 10;
public NetworkMessenger(MainGame game, UdpClient client)
: base(game)
{
_game = game;
_client = client;
_messages = new List<NetworkMessage>();
}
/// <summary>
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
/// </summary>
public override void Initialize()
{
_spriteBatch = new SpriteBatch(_game.GraphicsDevice);
_netFont = _game.Content.Load<SpriteFont>("Fonts\\Default");
_chatRectangle = new Rectangle(300, 20, 300, _game.GraphicsDevice.Viewport.Height - 40);
_textBounds = new Rectangle();
base.Initialize();
}
public static void AddDeath(IEntity entity)
{
_client.SendDeath(entity);
}
public static void DisplayMessage(NetworkMessage message)
{
_messages.Add(message);
}
public static void SendMessage(NetworkMessage message)
{
_messages.Add(message);
_client.SendMessage(message);
if (message.IsChatMessage)
{
SoundManager.Play("Audio/Waves/message", _client.LocalPlayer.Position);
}
}
private string _chatMessage = string.Empty;
private KeyboardState _oldKeyboardState;
private KeyboardState _currentKeyboardState;
bool chatting = false;
/// <summary>
/// Allows the game component to update itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Update(GameTime gameTime)
{
MainGame.IsKeyboardInUse = chatting;
_oldKeyboardState = _currentKeyboardState;
_currentKeyboardState = Keyboard.GetState();
Keys[] pressedKeys = _currentKeyboardState.GetPressedKeys();
bool isShiftDown = pressedKeys.Any(KeyboardHelper.IsShift);
foreach (Keys key in pressedKeys)
{
if (!_oldKeyboardState.IsKeyUp(key)) continue;
if (key == Keys.T && !chatting)
{
chatting = true;
continue;
}
if (!chatting) continue;
switch (key)
{
case Keys.Back:
_chatMessage = _chatMessage.Remove(_chatMessage.Length - 1, 1);
break;
case Keys.Space:
_chatMessage = _chatMessage + " ";
break;
default:
if (key == Keys.Enter && chatting)
{
chatting = false;
SendMessage(new NetworkMessage()
{
Color = _client.LocalPlayer.Color,
Message =
string.Format("{0}: {1}", _client.LocalPlayer.Owner,
_chatMessage),
Sent = DateTime.Now,
IsChatMessage = true
});
_chatMessage = string.Empty;
}
else
{
if (isShiftDown)
{
_chatMessage += KeyboardHelper.ToPrintableString(key, KbModifiers.None).ToUpper();
}
else
{
_chatMessage += KeyboardHelper.ToPrintableString(key, KbModifiers.None);
}
}
break;
}
}
for (int i = _messages.Count - 1; i >= 0; i--)
{
if (_messages[i].Sent.AddSeconds(DefaultMessageLifeTime) <= DateTime.Now)
{
_messages.RemoveAt(i);
}
}
base.Update(gameTime);
}
public void Draw(GameTime gameTime)
{
_spriteBatch.Begin();
int yOffset = 0;
if (chatting)
{
_spriteBatch.DrawString(_netFont, "Chat: " + _chatMessage,
new Vector2(300, _game.GraphicsDevice.Viewport.Height - 140), Color.White);
}
foreach (var message in _messages)
{
DrawString(_spriteBatch,
_netFont,
message.Message,
_chatRectangle,
message.Color,
TextAlignment.TopLeft,
true,
new Vector2(0, (_messages.IndexOf(message) * 15) + yOffset),
out _textBounds);
yOffset += _textBounds.Height;
}
_spriteBatch.End();
}
public int DrawOrder
{
get { return 5; }
}
public bool Visible
{
get { return true; }
}
private enum TextAlignment
{
Top,
Left,
Middle,
Right,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
private static void DrawString(SpriteBatch sb, SpriteFont fnt, string text, Rectangle r,
Color col, TextAlignment align, bool performWordWrap, Vector2 offsett, out Rectangle textBounds)
{
textBounds = r;
if (text == null) return;
if (text == string.Empty) return;
var lines = new StringCollection();
lines.AddRange(text.Split(new string[] { "\\n" }, StringSplitOptions.RemoveEmptyEntries));
Rectangle tmprect = ProcessLines(fnt, r, performWordWrap, lines);
var pos = new Vector2(r.X, r.Y);
int aStyle = 0;
switch (align)
{
case TextAlignment.Bottom:
pos.Y = r.Bottom - tmprect.Height;
aStyle = 1;
break;
case TextAlignment.BottomLeft:
pos.Y = r.Bottom - tmprect.Height;
aStyle = 0;
break;
case TextAlignment.BottomRight:
pos.Y = r.Bottom - tmprect.Height;
aStyle = 2;
break;
case TextAlignment.Left:
pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 0;
break;
case TextAlignment.Middle:
pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 1;
break;
case TextAlignment.Right:
pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2));
aStyle = 2;
break;
case TextAlignment.Top:
aStyle = 1;
break;
case TextAlignment.TopLeft:
aStyle = 0;
break;
case TextAlignment.TopRight:
aStyle = 2;
break;
}
foreach (string txt in lines)
{
Vector2 size = fnt.MeasureString(txt);
switch (aStyle)
{
case 0:
pos.X = r.X;
break;
case 1:
pos.X = r.X + ((r.Width / 2) - (size.X / 2));
break;
case 2:
pos.X = r.Right - size.X;
break;
}
sb.DrawString(fnt, txt, pos + offsett, col);
pos.Y += fnt.LineSpacing;
}
textBounds = tmprect;
}
private static Rectangle ProcessLines(SpriteFont fnt, Rectangle r, bool performWordWrap, StringCollection lines)
{
Rectangle bounds = r;
bounds.Width = 0;
bounds.Height = 0;
int index = 0;
float Width;
bool lineInserted = false;
while (index < lines.Count)
{
string linetext = lines[index];
Vector2 size = fnt.MeasureString(linetext);
if (performWordWrap && size.X > r.Width)
{
string endspace = string.Empty;
if (linetext.EndsWith(" "))
{
endspace = " ";
linetext = linetext.TrimEnd();
}
int i = linetext.LastIndexOf(" ", StringComparison.InvariantCulture);
if (i != -1)
{
string lastword = linetext.Substring(i + 1);
if (index == lines.Count - 1)
{
lines.Add(lastword);
lineInserted = true;
}
else
{
if (lineInserted)
{
lines[index + 1] = lastword + endspace + lines[index + 1];
}
else
{
lines.Insert(index + 1, lastword);
lineInserted = true;
}
}
lines[index] = linetext.Substring(0, i + 1);
}
else
{
lineInserted = false;
size = fnt.MeasureString(lines[index]);
if (size.X > bounds.Width) Width = size.X;
bounds.Height += fnt.LineSpacing;
index++;
}
}
else
{
lineInserted = false;
size = fnt.MeasureString(lines[index]);
if (size.X > bounds.Width) bounds.Width = (int)size.X;
bounds.Height += fnt.LineSpacing;
index++;
}
}
return bounds;
}
event EventHandler<EventArgs> IDrawable.DrawOrderChanged
{
add { }
remove { }
}
event EventHandler<EventArgs> IDrawable.VisibleChanged
{
add { }
remove { }
}
}
}

View File

@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Globalization;
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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using SpacePew.Models;
namespace SpacePew.Networking
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
public class ScoreBoard : Microsoft.Xna.Framework.GameComponent, IDrawable
{
public static List<ScoreBoardItem> CurrentScoreBoard { get; set; }
private readonly MainGame _game;
private readonly UdpClient _client;
private Texture2D _scoreBoardTexture;
private SpriteBatch _spriteBatch;
private SpriteFont _scoreFont;
public ScoreBoard(MainGame game, UdpClient client)
: base(game)
{
_game = game;
_client = client;
CurrentScoreBoard = new List<ScoreBoardItem>();
}
/// <summary>
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
/// </summary>
public override void Initialize()
{
_spriteBatch = new SpriteBatch(_game.GraphicsDevice);
_scoreFont = _game.Content.Load<SpriteFont>("Fonts\\Default");
_scoreBoardTexture = _game.Content.Load<Texture2D>("scoreboard");
base.Initialize();
}
bool requestedScoreBoard;
/// <summary>
/// Allows the game component to update itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Tab))
{
if (!requestedScoreBoard)
{
_client.RequestScoreBoard();
}
requestedScoreBoard = true;
}
else
{
requestedScoreBoard = false;
}
base.Update(gameTime);
}
public void Draw(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Tab))
{
_spriteBatch.Begin();
_spriteBatch.Draw(_scoreBoardTexture, new Vector2(20, 20), Color.White);
foreach (ScoreBoardItem item in CurrentScoreBoard)
{
Player player = ((List<Player>)_client.Players).Find(p => p.Owner == item.Name);
if (player != null)
{
Color color = player.Color;
int yOffset = (CurrentScoreBoard.IndexOf(item) * 15) + 70;
_spriteBatch.DrawString(_scoreFont, item.Name, new Vector2(35, yOffset), color);
_spriteBatch.DrawString(_scoreFont, item.Kills.ToString(CultureInfo.InvariantCulture), new Vector2(185, yOffset), color);
_spriteBatch.DrawString(_scoreFont, item.Deaths.ToString(CultureInfo.InvariantCulture), new Vector2(243, yOffset), color);
_spriteBatch.DrawString(_scoreFont, (DateTime.Now - item.Joined).Minutes.ToString(CultureInfo.InvariantCulture),
new Vector2(314, yOffset), color);
_spriteBatch.DrawString(_scoreFont, item.Ping.ToString(CultureInfo.InvariantCulture), new Vector2(373, yOffset), color);
}
}
_spriteBatch.End();
}
}
public int DrawOrder
{
get { return 5; }
}
public bool Visible
{
get { return true; }
}
event EventHandler<EventArgs> IDrawable.DrawOrderChanged
{
add { }
remove { }
}
event EventHandler<EventArgs> IDrawable.VisibleChanged
{
add { }
remove { }
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SpacePew.Networking
{
public class ScoreBoardItem
{
public string Name { get; set; }
public int Kills { get; set; }
public int Deaths { get; set; }
public DateTime Joined { get; set; }
public long Ping { get; set; }
}
}

View File

@@ -0,0 +1,64 @@
using System.Diagnostics;
using Lidgren.Network;
using System.IO;
using SpacePew.Common;
namespace SpacePew.Networking
{
public class StreamingClient
{
private FileStream _inputStream;
private int _sentOffset;
private int _chunkLen;
private byte[] _tmpBuffer;
private NetConnection _connection;
public StreamingClient(NetConnection conn, string fileName)
{
_connection = conn;
_inputStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
_chunkLen = _connection.Peer.Configuration.MaximumTransmissionUnit - 20;
_tmpBuffer = new byte[_chunkLen];
_sentOffset = 0;
}
public void Heartbeat()
{
if (_inputStream == null)
return;
if (_connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, 1))
{
long remaining = _inputStream.Length - _sentOffset;
int sendBytes = (remaining > _chunkLen ? _chunkLen : (int)remaining);
_inputStream.Read(_tmpBuffer, 0, sendBytes);
NetOutgoingMessage message;
if (_sentOffset == 0)
{
message = _connection.Peer.CreateMessage(sendBytes + 8);
message.Write((int)UdpNetworkPacketType.LevelResponse);
message.Write((ulong)_inputStream.Length);
message.Write(Path.GetFileName(_inputStream.Name));
_connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, 1);
}
message = _connection.Peer.CreateMessage(sendBytes + 8);
message.Write((int)UdpNetworkPacketType.LevelResponse);
message.Write(_tmpBuffer, 0, sendBytes);
_connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, 1);
_sentOffset += sendBytes;
if (remaining - sendBytes <= 0)
{
_inputStream.Close();
_inputStream.Dispose();
_inputStream = null;
}
}
}
}
}

View File

@@ -0,0 +1,62 @@
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Lidgren.Network;
using SpacePew.Common;
using System.Net;
namespace SpacePew.Networking
{
public abstract class UdpBase
{
protected Color[] _playerColors =
{
Color.Red,
Color.Blue,
Color.Green,
Color.Yellow,
Color.Purple,
Color.White,
Color.Red,
Color.LightBlue,
Color.Orange,
Color.Gray
};
protected byte[] ObjectToByteArray(object obj)
{
if (obj == null)
return null;
var memoryStream = new MemoryStream();
var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress);
var formatter = new BinaryFormatter();
formatter.Serialize(gZipStream, obj);
gZipStream.Close();
memoryStream.Close();
return memoryStream.ToArray();
}
protected object ByteArrayToObject(byte[] bytes)
{
var memoryStream = new MemoryStream();
var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress);
var formatter = new BinaryFormatter();
memoryStream.Write(bytes, 0, bytes.Length);
memoryStream.Seek(0, SeekOrigin.Begin);
var obj = formatter.Deserialize(gzipStream);
gzipStream.Close();
memoryStream.Close();
return obj;
}
}
}

View File

@@ -0,0 +1,586 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Extensions;
using Lidgren.Network;
using System.Collections;
using SpacePew.Models;
using SpacePew.Common;
using System.Net;
namespace SpacePew.Networking
{
public class UdpClient : UdpBase
{
private string _playerName;
private readonly NetClient _client;
private Level _level;
private readonly MainGame _game;
private int _colorIndex;
private IPEndPoint _masterServerEndpoint;
private UdpClient()
{
}
public UdpClient(MainGame game)
{
_game = game;
_masterServerEndpoint = NetUtility.Resolve("spacepew.wodanaz.se", Constants.MasterServerPort); // TODO: Fixa upp masterserver någonstans
EntitiesToSend = new List<IEntity>();
var configuration = new NetPeerConfiguration("SpacePew");
configuration.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
configuration.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);
configuration.EnableMessageType(NetIncomingMessageType.UnconnectedData);
configuration.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
_client = new NetClient(configuration);
_client.Start();
}
public List<IEntity> EntitiesToSend { get; set; }
public NetClient CurrentClient
{
get { return _client; }
}
private Player _localPlayer;
public Player LocalPlayer
{
get
{
return _localPlayer;
}
set
{
_localPlayer = value;
}
}
private readonly List<Player> _players = new List<Player>();
public IList<Player> Players
{
get
{
return _players;
}
}
public bool IsSessionAlive
{
get
{
return _client != null && _client.ConnectionStatus == NetConnectionStatus.Connected;
}
}
public void JoinSession(string host, string playerName)
{
JoinSession(new IPEndPoint(System.Net.Dns.GetHostAddresses(host)[0], SpacePew.Common.Constants.GameServerPort), playerName);
}
public void JoinSession(IPEndPoint endpoint, string playerName)
{
_playerName = playerName;
var hailMessage = _client.CreateMessage(playerName);
_client.Connect(endpoint, hailMessage);
while (_client.ServerConnection == null)
{
// wait
}
System.Threading.Thread.Sleep(500); // TODO: nya lidgren är dumt i huvet, grotta i vad skiten sätter i någon tråd se'n
System.Diagnostics.Trace.WriteLine("Got server connection...");
WriteLevelRequest();
WaitForLevel();
WriteJoiningMessage();
WaitForJoin();
if (_level.OggVorbisSong != null)
{
new Thread(_level.PlayLevelSong).Start();
}
}
public void ExitSession(string reason)
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDisconnecting);
message.Write(_playerName);
_client.SendMessage(message, NetDeliveryMethod.ReliableOrdered);
_client.Disconnect(reason);
}
public void SendMessage(NetworkMessage message)
{
var netMessage = _client.CreateMessage();
netMessage.Write((int)UdpNetworkPacketType.MessageSent);
netMessage.Write(message.Color.ToVector3());
netMessage.Write(message.Sent.ToString(CultureInfo.InvariantCulture));
netMessage.Write(message.Message);
netMessage.Write(message.IsChatMessage);
_client.SendMessage(netMessage, NetDeliveryMethod.UnreliableSequenced);
}
public void RequestScoreBoard()
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.RequestingScoreboard);
_client.SendMessage(message, NetDeliveryMethod.UnreliableSequenced);
}
private void ReadMessage(NetIncomingMessage netMessage)
{
var color = new Color(netMessage.ReadVector3());
var sent = DateTime.Parse(netMessage.ReadString(), CultureInfo.InvariantCulture);
string message = netMessage.ReadString();
bool isChatMessage = netMessage.ReadBoolean();
NetworkMessenger.DisplayMessage(new NetworkMessage() { Color = color, Sent = sent, Message = message, IsChatMessage = isChatMessage});
}
public void SendDeath(IEntity killedBy)
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDying);
message.Write(_playerName);
message.Write(killedBy.Owner); // TODO: server side score board
_client.SendMessage(message, NetDeliveryMethod.ReliableUnordered);
}
private void WriteLevelRequest()
{
Trace.WriteLine("WriteLevelRequest");
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.LevelRequest);
_client.SendMessage(message, NetDeliveryMethod.ReliableUnordered);
System.Diagnostics.Trace.WriteLine("Sent level request...");
}
private void WriteJoiningMessage()
{
Trace.WriteLine("WriteJoiningMessage");
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerJoining);
message.Write(_playerName);
_client.SendMessage(message, NetDeliveryMethod.ReliableUnordered);
}
private void WaitForJoin()
{
System.Diagnostics.Trace.WriteLine("WaitForJoin");
bool hasAnswer = false;
while (!hasAnswer) // wait for answer
{
NetIncomingMessage message;
while ((message = _client.ReadMessage()) != null)
{
if (message.MessageType == NetIncomingMessageType.Data)
{
var packetType = (UdpNetworkPacketType)message.ReadInt32();
if (packetType == UdpNetworkPacketType.PlayerJoined)
{
string owner = message.ReadString();
int colorIndex = message.ReadInt32();
Color color = _playerColors[colorIndex];
_colorIndex = Array.IndexOf(_playerColors, color);
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
int collisionSize = message.ReadInt32();
var collisionData = message.ReadBytes(collisionSize);
_level.CollisionData = (bool[])ByteArrayToObject(collisionData);
_level.BuildLevelFromCollisionData();
Player p = Player.CreatePlayer(pos, owner);
p.Color = color;
p.Position = pos;
p.Velocity = velocity;
p.Angle = angle;
_localPlayer = p;
_players.Add(p);
hasAnswer = true;
}
}
}
}
}
public void Update()
{
NetIncomingMessage message;
while ((message = _client.ReadMessage()) != null)
{
ReadBuffer(message);
}
if (EntitiesToSend.Count > 0)
{
WriteServerShots();
}
WritePlayerUpdatePacket();
}
private void WriteServerShots()
{
SendEntities(EntitiesToSend);
}
private void WritePlayerUpdatePacket()
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerUpdate);
message.Write(_localPlayer.Owner);
message.Write(_colorIndex);
message.Write(_localPlayer.Position);
message.Write(_localPlayer.Velocity);
message.Write(_localPlayer.Angle);
message.Write(_localPlayer.Health);
_client.SendMessage(message, NetDeliveryMethod.UnreliableSequenced);
}
private void ReadBuffer(NetIncomingMessage message)
{
switch (message.MessageType)
{
case NetIncomingMessageType.Data:
{
var packetType = (UdpNetworkPacketType)message.ReadInt32();
switch (packetType)
{
case UdpNetworkPacketType.PlayerUpdate:
ReadPlayers(message);
break;
case UdpNetworkPacketType.EntitiesCreated:
ReadEntities(message);
break;
case UdpNetworkPacketType.MessageReceived:
ReadMessage(message);
break;
case UdpNetworkPacketType.PlayerDied:
ReadPlayerDied(message);
break;
case UdpNetworkPacketType.SendingScoreBoard:
ReadScoreBoard(message);
break;
case UdpNetworkPacketType.EntityCreated:
ReadEntity(message);
break;
case UdpNetworkPacketType.PlayerDisconnected:
RemovePlayer(message);
break;
case UdpNetworkPacketType.LevelResponse:
ReadLevel(message);
break;
}
}
break;
}
_client.Recycle(message);
}
private void WaitForLevel()
{
System.Diagnostics.Trace.WriteLine("WaitForLevel");
while (_level == null) // wait for level
{
NetIncomingMessage message;
while ((message = _client.ReadMessage()) != null)
{
if (message.MessageType == NetIncomingMessageType.Data)
{
var packetType = (UdpNetworkPacketType)message.ReadInt32();
if (packetType == UdpNetworkPacketType.LevelResponse)
{
ReadLevel(message);
}
}
}
}
}
private static ulong _levelLength;
private static ulong _levelReceived;
private static FileStream _levelWriteStream;
private static int _levelTimeStarted;
string levelPath = string.Empty;
private void ReadLevel(NetIncomingMessage message)
{
int chunkLen = message.LengthBytes;
if (_levelLength == 0)
{
_levelLength = message.ReadUInt64();
string filename = message.ReadString();
var downloadLevelFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Downloads\\Levels\\");
levelPath = Path.Combine(downloadLevelFolder, filename);
_levelWriteStream = new FileStream(levelPath, FileMode.Create, FileAccess.Write, FileShare.None);
_levelTimeStarted = Environment.TickCount;
return;
}
byte[] all = message.ReadBytes(message.LengthBytes - 4); // offset for UdpNetworkPacketType
_levelReceived += (ulong)all.Length;
_levelWriteStream.Write(all, 0, all.Length);
//int v = (int)(((float)_levelReceived / (float)_levelLength) * 100.0f);
//int passed = Environment.TickCount - _levelTimeStarted;
//double psec = (double)passed / 1000.0;
//double bps = (double)_levelReceived / psec;
//var passedText = NetUtility.ToHumanReadable((long)bps) + " per second";
if (_levelReceived >= _levelLength)
{
Trace.WriteLine("Got level");
_levelWriteStream.Flush();
_levelWriteStream.Close();
_levelWriteStream.Dispose();
_level = LevelLoader.LoadLevel(levelPath, _game.Content, _game.GraphicsDevice);
_game.Level = _level;
}
}
private void RemovePlayer(NetIncomingMessage message)
{
string name = message.ReadString();
Player player = _players.Find(p => p.Owner == name);
if (player != null)
{
EntityFactory.Instance.RemoveEntity(player);
NetworkMessenger.DisplayMessage(new NetworkMessage()
{
Color = player.Color,
Message = string.Format("{0} has left.", player.Owner),
Sent = DateTime.Now
});
_players.Remove(player);
}
}
private void ReadScoreBoard(NetIncomingMessage message)
{
int count = message.ReadInt32();
var scoreBoard = new List<ScoreBoardItem>();
for (int i = 0; i < count; i++)
{
var item = new ScoreBoardItem
{
Name = message.ReadString(),
Kills = message.ReadInt32(),
Deaths = message.ReadInt32(),
Joined = DateTime.Parse(message.ReadString(), CultureInfo.InvariantCulture),
Ping = message.ReadInt64()
};
scoreBoard.Add(item);
}
ScoreBoard.CurrentScoreBoard = scoreBoard;
}
private void ReadPlayerDied(NetIncomingMessage message)
{
string playerName = message.ReadString();
Player player = _players.Find(p => p.Owner == playerName);
if (player != null)
{
_game.AddExplosion(player.Position, 1f);
player.Kill();
}
}
private void ReadEntities(NetIncomingMessage message)
{
int count = message.ReadInt32();
for (int i = 0; i < count; i++)
{
string entityType = message.ReadString();
string owner = message.ReadString();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
EntityFactory.Instance.CreateEntity<IEntity>(Type.GetType(entityType), owner, pos, velocity, angle);
}
}
private void ReadEntity(NetIncomingMessage message)
{
string entityType = message.ReadString();
string owner = message.ReadString();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
EntityFactory.Instance.CreateEntity<IEntity>(Type.GetType(entityType), owner, pos, velocity, angle);
}
private void ReadPlayers(NetIncomingMessage message)
{
string owner = message.ReadString();
int colorIndex = message.ReadInt32();
Color color = _playerColors[colorIndex];
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
if (owner == LocalPlayer.Owner)
return;
Player player = _players.Find(p => p.Owner == owner);
if (player == null)
{
Player p = Player.CreatePlayer(new Vector2(300, 280), owner);
p.Position = pos;
p.Color = color;
p.Velocity = velocity;
p.Angle = angle;
p.Owner = owner;
_players.Add(p);
NetworkMessenger.DisplayMessage(new NetworkMessage()
{
Color = p.Color,
Message = string.Format("{0} has joined.", p.Owner),
Sent = DateTime.Now
});
}
else
{
int index = _players.IndexOf(player);
player.Owner = owner;
player.Color = color;
player.Position = pos;
player.Velocity = velocity;
player.Angle = angle;
_players[index] = player;
}
}
public void SendEntities(List<IEntity> entities)
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntitiesCreated);
message.Write(entities.Count);
lock (EntitiesToSend)
{
for (int i = entities.Count - 1; i >= 0; i--)
{
message.Write(entities[i].GetType().ToString());
message.Write(_localPlayer.Owner);
message.Write(entities[i].Position);
message.Write(entities[i].Velocity);
message.Write(entities[i].Angle);
}
}
EntitiesToSend.Clear();
_client.SendMessage(message, NetDeliveryMethod.UnreliableSequenced);
}
public void SendEntity(IEntity entity)
{
var message = _client.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntityCreated);
message.Write(entity.GetType().ToString());
message.Write(_localPlayer.Owner);
message.Write(entity.Position);
message.Write(entity.Velocity);
message.Write(entity.Angle);
_client.SendMessage(message, NetDeliveryMethod.UnreliableSequenced);
}
public void GetServerList()
{
var listRequest = _client.CreateMessage();
listRequest.Write((byte)UdpNetworkPacketType.RequestHostList);
_client.SendUnconnectedMessage(listRequest, _masterServerEndpoint);
}
public void RequestNATIntroduction(long hostid)
{
if (hostid == 0)
{
return;
}
if (_masterServerEndpoint == null)
throw new Exception("Must connect to master server first!");
IPAddress mask;
var message = _client.CreateMessage();
message.Write((byte)UdpNetworkPacketType.RequestIntroduction);
message.Write(new IPEndPoint(NetUtility.GetMyAddress(out mask), _client.Port));
message.Write(hostid);
message.Write(_playerName);
_client.SendUnconnectedMessage(message, _masterServerEndpoint);
}
}
}

View File

@@ -0,0 +1,361 @@
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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Threading;
using SpacePew.Models;
#if WINDOWS
using TomShane.Neoforce.Controls;
using Lidgren.Network;
using System.Net;
using System.Diagnostics;
#endif
namespace SpacePew.Networking
{
/// <summary>
/// This is a game component that implements IUpdateable.
/// </summary>
#if WINDOWS
public class UdpNetworkGui : Microsoft.Xna.Framework.DrawableGameComponent
{
private MainGame _game;
private UdpClient _client;
private UdpServer _server;
private GraphicsDeviceManager _graphics;
private Manager _manager;
private Window _window;
private TabControl _tabControl;
private TextBox _nameTextBox;
private TextBox _nameTextBox2;
private TextBox _ipTextBox;
private Label _nameLabel;
private Label _nameLabel2;
private ListBox _localGamesListBox;
private Label _joinErrorLabel;
private Label _ipLabel;
private Button _createButton;
private Button _joinButton;
private Button _refreshButton;
public UdpNetworkGui(MainGame game, GraphicsDeviceManager graphics, UdpClient client, UdpServer server)
: base(game)
{
_game = game;
_graphics = graphics;
_client = client;
_server = server;
_client.CurrentClient.Start();
_manager = new Manager(game, _graphics, "Default");
_manager.Skin = new Skin(_manager, "Default");
_manager.AutoCreateRenderTarget = true;
_manager.TargetFrames = 60;
_manager.LogUnhandledExceptions = false;
_manager.ShowSoftwareCursor = true;
}
/// <summary>
/// Allows the game component to perform any initialization it needs to before starting
/// to run. This is where it can query for any required services and load content.
/// </summary>
public override void Initialize()
{
base.Initialize();
_window = new Window(_manager);
_window.Init();
_window.Text = "Space, pew pew!";
_window.Width = 480;
_window.Height = 200;
_window.Center();
_window.CloseButtonVisible = false;
_window.Resizable = false;
_window.Visible = true;
_tabControl = new TabControl(_manager);
_tabControl.Width = _window.Width;
_tabControl.Height = _window.Height;
_tabControl.Parent = _window;
_nameLabel = new Label(_manager);
_nameLabel.Init();
_nameLabel.Width = 100;
_nameLabel.Height = 24;
_nameLabel.Text = "Name";
_nameLabel.Left = 10;
_nameLabel.Top = 10;
_nameTextBox = new TextBox(_manager);
_nameTextBox.Init();
_nameTextBox.Width = 140;
_nameTextBox.Height = 24;
_nameTextBox.Left = 50;
_nameTextBox.Top = 10;
_nameLabel2 = new Label(_manager);
_nameLabel2.Init();
_nameLabel2.Width = 100;
_nameLabel2.Height = 24;
_nameLabel2.Text = "Name";
_nameLabel2.Left = 10;
_nameLabel2.Top = 10;
_nameTextBox2 = new TextBox(_manager);
_nameTextBox2.Init();
_nameTextBox2.Width = 140;
_nameTextBox2.Height = 24;
_nameTextBox2.Left = 50;
_nameTextBox2.Top = 10;
_createButton = new Button(_manager);
_createButton.Init();
_createButton.Text = "Create game";
_createButton.Width = 140;
_createButton.Height = 24;
_createButton.Left = 50;
_createButton.Top = 40;
_createButton.Click += _createButton_Click;
_ipLabel = new Label(_manager);
_ipLabel.Init();
_ipLabel.Width = 100;
_ipLabel.Height = 24;
_ipLabel.Text = "Host";
_ipLabel.Left = 10;
_ipLabel.Top = 40;
_ipTextBox = new TextBox(_manager);
_ipTextBox.Init();
_ipTextBox.Width = 140;
_ipTextBox.Height = 24;
_ipTextBox.Left = 50;
_ipTextBox.Top = 40;
_joinErrorLabel = new Label(_manager);
_joinErrorLabel.Init();
_joinErrorLabel.Width = 460;
_joinErrorLabel.Height = 24;
_joinErrorLabel.Left = 10;
_joinErrorLabel.Top = 110;
_joinErrorLabel.Text = string.Empty;
_joinErrorLabel.TextColor = Color.DarkRed;
_joinButton = new Button(_manager);
_joinButton.Init();
_joinButton.Text = "Join game";
_joinButton.Width = 140;
_joinButton.Height = 24;
_joinButton.Left = 50;
_joinButton.Top = 70;
_joinButton.Anchor = Anchors.Bottom;
_joinButton.Click += _joinButton_Click;
_localGamesListBox = new ListBox(_manager);
_localGamesListBox.Init();
_localGamesListBox.Left = 200;
_localGamesListBox.Top = 10;
_localGamesListBox.Height = 84;
_localGamesListBox.Width = 254;
_localGamesListBox.ItemIndexChanged += new TomShane.Neoforce.Controls.EventHandler(_localGamesListBox_ItemIndexChanged);
_refreshButton = new Button(_manager);
_refreshButton.Init();
_refreshButton.Text = "Refresh";
_refreshButton.Width = 140;
_refreshButton.Height = 24;
_refreshButton.Left = 314;
_refreshButton.Top = 104;
_refreshButton.Click += _refreshButton_Click;
_nameTextBox.Click += ChangeTextBoxColor;
_nameTextBox2.Click += ChangeTextBoxColor;
_ipTextBox.Click += ChangeTextBoxColor;
_tabControl.AddPage();
_tabControl.AddPage();
_tabControl.TabPages[0].Text = "Create";
_tabControl.TabPages[0].Add(_nameLabel);
_tabControl.TabPages[0].Add(_nameTextBox);
_tabControl.TabPages[0].Add(_createButton);
_tabControl.TabPages[1].Text = "Join";
_tabControl.TabPages[1].Add(_nameLabel2);
_tabControl.TabPages[1].Add(_nameTextBox2);
_tabControl.TabPages[1].Add(_ipLabel);
_tabControl.TabPages[1].Add(_ipTextBox);
_tabControl.TabPages[1].Add(_joinButton);
_tabControl.TabPages[1].Add(_joinErrorLabel);
_tabControl.TabPages[1].Add(_localGamesListBox);
_tabControl.TabPages[1].Add(_refreshButton);
_manager.Add(_window);
_manager.Initialize();
_client.CurrentClient.DiscoverLocalPeers(SpacePew.Common.Constants.GameServerPort);
}
private void _refreshButton_Click(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
_localGamesListBox.Items.Clear();
_client.CurrentClient.DiscoverLocalPeers(SpacePew.Common.Constants.GameServerPort);
}
private void ChangeTextBoxColor(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
((TomShane.Neoforce.Controls.Control)sender).Color = Color.TransparentBlack;
}
private void _localGamesListBox_ItemIndexChanged(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
_ipTextBox.Text = _localGamesListBox.Items[_localGamesListBox.ItemIndex].ToString();
}
private void _createButton_Click(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
_nameTextBox.Color = string.IsNullOrEmpty(_nameTextBox.Text) ? Color.Pink : Color.TransparentBlack;
if (_nameTextBox.Color == Color.Pink)
{
return;
}
string levelPath = AppDomain.CurrentDomain.BaseDirectory + "\\Levels\\hippie.zip"; // TODO: V<>lja
var level = LevelLoader.LoadLevel(levelPath, _game.Content, GraphicsDevice);
_server.SetLevel(level);
_window.Close();
Trace.WriteLine("CreateSession()");
_server.CreateSession();
new Thread(_server.Listen).Start();
_client.JoinSession("127.0.0.1", _nameTextBox.Text);
_game.AddGameComponents();
_game.Components.Remove(this);
}
private void _joinButton_Click(object sender, TomShane.Neoforce.Controls.EventArgs e)
{
_ipTextBox.Color = string.IsNullOrEmpty(_ipTextBox.Text) ? Color.Pink : Color.TransparentBlack;
_nameTextBox2.Color = string.IsNullOrEmpty(_nameTextBox2.Text) ? Color.Pink : Color.TransparentBlack;
if (_ipTextBox.Color == Color.Pink || _nameTextBox2.Color == Color.Pink)
{
return;
}
var splits = _ipTextBox.Text.Split(' ');
if (splits.Count() > 1)
{
var host = Int64.Parse(splits[0]);
_client.RequestNATIntroduction(host);
}
else
{
try
{
_client.JoinSession(_ipTextBox.Text, _nameTextBox2.Text);
_game.AddGameComponents();
_game.Components.Remove(this);
}
catch (NetException ex)
{
_joinErrorLabel.Text = ex.Message;
return;
}
}
}
private DateTime _lastUpdate = DateTime.Now.AddSeconds(-5);
private static Dictionary<long, IPEndPoint[]> _hostList = new Dictionary<long, IPEndPoint[]>();
/// <summary>
/// Allows the game component to update itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Update(GameTime gameTime)
{
_manager.Update(gameTime);
if (_lastUpdate <= DateTime.Now.AddSeconds(-5))
{
_lastUpdate = DateTime.Now;
_client.CurrentClient.DiscoverLocalPeers(SpacePew.Common.Constants.GameServerPort);
_client.GetServerList();
}
NetIncomingMessage message;
while ((message = _client.CurrentClient.ReadMessage()) != null)
{
if (message.MessageType == NetIncomingMessageType.UnconnectedData)
{
var id = message.ReadInt64();
var hostInternal = message.ReadIPEndPoint();
var hostExternal = message.ReadIPEndPoint();
_hostList[id] = new IPEndPoint[] { hostInternal, hostExternal };
_localGamesListBox.Items.Clear();
foreach (var kvp in _hostList)
{
_localGamesListBox.Items.Add(kvp.Key.ToString() + " (" + kvp.Value[1] + ")");
}
}
else if (message.MessageType == NetIncomingMessageType.DiscoveryResponse)
{
IPEndPoint ep = message.ReadIPEndPoint();
if (!_localGamesListBox.Items.Contains(ep.Address.ToString()))
{
_localGamesListBox.Items.Add(ep.Address.ToString());
}
}
else if (message.MessageType == NetIncomingMessageType.NatIntroductionSuccess)
{
try
{
_client.JoinSession(message.SenderEndPoint, _nameTextBox2.Text);
_game.AddGameComponents();
_game.Components.Remove(this);
}
catch (NetException ex)
{
_joinErrorLabel.Text = ex.Message;
return;
}
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
_manager.BeginDraw(gameTime);
GraphicsDevice.Clear(Color.Black);
_manager.EndDraw();
base.Draw(gameTime);
}
}
#endif
}

View File

@@ -0,0 +1,405 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Microsoft.Xna.Framework;
using SpacePew.Extensions;
using Lidgren.Network;
using System.Net;
using Microsoft.Xna.Framework.Graphics;
using System.Net.NetworkInformation;
using SpacePew.Models;
using SpacePew.Common;
namespace SpacePew.Networking
{
public class UdpServer : UdpBase
{
private NetPeerConfiguration _configuration;
private NetServer _server;
private Level _level;
private readonly List<ScoreBoardItem> _scoreBoard;
private readonly List<string> _players;
private readonly Vector2 _defaultPosition = new Vector2(300, 280);
private IPEndPoint _masterServerEndpoint;
public UdpServer()
: base()
{
_masterServerEndpoint = NetUtility.Resolve("spacepew.wodanaz.se", Constants.MasterServerPort); // TODO: Fixa upp masterserver någonstans
_scoreBoard = new List<ScoreBoardItem>();
_players = new List<string>();
}
public void CreateSession()
{
if (_server == null)
{
_configuration = new NetPeerConfiguration("SpacePew")
{
MaximumConnections = 16,
Port = SpacePew.Common.Constants.GameServerPort
};
_configuration.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
_configuration.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);
_configuration.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
_server = new NetServer(_configuration);
_server.Start();
}
}
public void SetLevel(Level level)
{
_level = level;
}
public void Shutdown()
{
if (_server != null && _server.Status == NetPeerStatus.Running)
{
_server.Shutdown("Quitting");
}
}
public void Listen()
{
System.Diagnostics.Trace.WriteLine("Server.Listen()");
while (_server.Status == NetPeerStatus.Running)
{
NetIncomingMessage message;
while ((message = _server.ReadMessage()) != null)
{
ReadBuffer(message, message.SenderConnection);
}
if (NetTime.Now > lastRegistered + 60)
{
RegisterWithMasterServer();
}
StreamLevelToClients();
}
}
private void StreamLevelToClients()
{
foreach (var conn in _server.Connections)
{
var client = conn.Tag as StreamingClient;
if (client != null)
client.Heartbeat();
}
}
float lastRegistered = -60.0f;
private void RegisterWithMasterServer()
{
IPAddress mask;
IPAddress localAddress = NetUtility.GetMyAddress(out mask);
var message = _server.CreateMessage();
message.Write((byte)UdpNetworkPacketType.RegisterHost);
message.Write(_server.UniqueIdentifier);
message.Write(new IPEndPoint(localAddress, Constants.GameServerPort));
_server.SendUnconnectedMessage(message, _masterServerEndpoint);
lastRegistered = (float)NetTime.Now;
}
private void ReadBuffer(NetIncomingMessage message, NetConnection sender)
{
switch (message.MessageType)
{
case NetIncomingMessageType.Data:
{
var packetType = (UdpNetworkPacketType)message.ReadInt32();
switch (packetType)
{
case UdpNetworkPacketType.PlayerUpdate:
WritePlayerUpdate(message, sender);
break;
case UdpNetworkPacketType.EntitiesCreated:
WriteEntities(message, sender);
break;
case UdpNetworkPacketType.MessageSent:
WriteMessage(message, sender);
break;
case UdpNetworkPacketType.EntityCreated:
WriteEntity(message, sender);
break;
case UdpNetworkPacketType.PlayerDying:
WritePlayerDied(message, sender);
break;
case UdpNetworkPacketType.RequestingScoreboard:
WriteScoreBoard(sender);
break;
case UdpNetworkPacketType.PlayerJoining:
{
string name = message.ReadString();
_players.Add(name);
sender.Tag = name;
_scoreBoard.Add(new ScoreBoardItem() { Name = name, Joined = DateTime.Now });
WritePlayerJoinedPacket(sender, name);
break;
}
case UdpNetworkPacketType.PlayerDisconnecting:
{
string name = message.ReadString();
WritePlayerDisconnectedPacket(sender, name);
break;
}
case UdpNetworkPacketType.LevelRequest:
{
WriteLevelResponse(message);
break;
}
}
}
break;
case NetIncomingMessageType.ConnectionApproval:
AuthorizeConnection(sender);
break;
case NetIncomingMessageType.DiscoveryRequest:
WriteDiscoveryResponse(sender);
break;
case NetIncomingMessageType.StatusChanged:
{
var status = (NetConnectionStatus)message.ReadByte();
var msg = message.ReadString();
break;
}
}
_server.Recycle(message);
}
private void WriteLevelResponse(NetIncomingMessage message)
{
message.SenderConnection.Tag = new StreamingClient(message.SenderConnection, _level.FilePath);
}
private void WriteDiscoveryResponse(NetConnection sender)
{
if (sender == null)
return;
var message = _server.CreateMessage();
// TODO: Skicka med lite stats
_server.SendDiscoveryResponse(message, sender.RemoteEndPoint);
}
private void WritePlayerDisconnectedPacket(NetConnection sender, string name)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDisconnected);
message.Write(name);
_server.SendToAll(message, sender, NetDeliveryMethod.ReliableUnordered, 0);
_players.Remove(name);
}
private void WriteScoreBoard(NetConnection sender)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.SendingScoreBoard);
int count = _scoreBoard.Count;
message.Write(count);
var ping = new Ping();
foreach (var item in _scoreBoard)
{
message.Write(item.Name);
message.Write(item.Kills);
message.Write(item.Deaths);
message.Write(item.Joined.ToString(CultureInfo.InvariantCulture));
//TODO: Fixa riktig ping
//NetConnection connection = _server.Connections.Find(s => s.Tag.ToString() == item.Name);
//long pingTime = ping.Send(connection.RemoteEndpoint.Address).RoundtripTime;
const long pinglong = 14;
message.Write(pinglong);
}
_server.SendMessage(message, sender, NetDeliveryMethod.UnreliableSequenced);
}
private void WriteMessage(NetIncomingMessage incomingMessage, NetConnection sender)
{
Vector3 colorVector = incomingMessage.ReadVector3();
string dateString = incomingMessage.ReadString();
string message = incomingMessage.ReadString();
bool isChatMessage = incomingMessage.ReadBoolean();
var outgoingMessage = _server.CreateMessage();
outgoingMessage.Write((int)UdpNetworkPacketType.MessageReceived);
outgoingMessage.Write(colorVector);
outgoingMessage.Write(dateString);
outgoingMessage.Write(message);
outgoingMessage.Write(isChatMessage);
_server.SendToAll(outgoingMessage, sender, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void WritePlayerDied(NetIncomingMessage incomingMessage, NetConnection sender)
{
string playerName = incomingMessage.ReadString();
string killedBy = incomingMessage.ReadString();
if (playerName != killedBy)
{
AddKillScore(killedBy);
}
AddDeathScore(playerName);
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDied);
message.Write(playerName);
_server.SendToAll(message, sender, NetDeliveryMethod.ReliableUnordered, 0);
}
private void AddKillScore(string name)
{
ScoreBoardItem item = _scoreBoard.Find(i => i.Name == name);
item.Kills++;
_scoreBoard[_scoreBoard.IndexOf(item)] = item;
}
private void AddDeathScore(string name)
{
ScoreBoardItem item = _scoreBoard.Find(i => i.Name == name);
item.Deaths++;
_scoreBoard[_scoreBoard.IndexOf(item)] = item;
}
private void WriteEntities(NetIncomingMessage incomingMessage, NetConnection sender)
{
int count = incomingMessage.ReadInt32();
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntitiesCreated);
message.Write(count);
for (int i = 0; i < count; i++)
{
message.Write(incomingMessage.ReadString());
message.Write(incomingMessage.ReadString());
message.Write(incomingMessage.ReadVector2());
message.Write(incomingMessage.ReadVector2());
message.Write(incomingMessage.ReadFloat());
}
_server.SendToAll(message, sender, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void AuthorizeConnection(NetConnection sender)
{
string name = Encoding.ASCII.GetString(sender.RemoteHailMessage.Data);
if (!string.IsNullOrEmpty(name) && !_players.Contains(name))
{
sender.Approve();
}
else
{
sender.Deny("A player with that name is already playing.");
}
}
private void WritePlayerJoinedPacket(NetConnection sender, string name)
{
System.Diagnostics.Trace.WriteLine("In WritePlayerJoined()...");
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerJoined);
message.Write(name);
message.Write(_server.Connections.IndexOf(sender));
message.Write(_defaultPosition); // TODO: positions should be stored on the level somehow
message.Write(Vector2.Zero);
message.Write(0f);
_level.BuildCollisionDataFromLevel();
byte[] collisionData = ObjectToByteArray(_level.CollisionData);
message.Write(collisionData.Length);
message.Write(collisionData);
_server.SendMessage(message, sender, NetDeliveryMethod.ReliableUnordered);
System.Diagnostics.Trace.WriteLine("Sent joined...");
}
private void WriteEntity(NetIncomingMessage message, NetConnection sender)
{
string entityType = message.ReadString();
string owner = message.ReadString();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
WriteEntityPacket(sender, entityType, owner, ref pos, ref velocity, angle);
}
private void WriteEntityPacket(NetConnection connectionToExclude, string entityType, string owner, ref Vector2 pos, ref Vector2 velocity, float angle)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntityCreated);
message.Write(entityType);
message.Write(owner);
message.Write(pos);
message.Write(velocity);
message.Write(angle);
_server.SendToAll(message, connectionToExclude, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void WritePlayerUpdate(NetIncomingMessage message, NetConnection sender)
{
string owner = message.ReadString();
int colorIndex = message.ReadInt32();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
WritePlayerUpdatePacket(sender, owner, colorIndex, ref pos, ref velocity, angle);
}
private void WritePlayerUpdatePacket(NetConnection connectionToExclude, string owner, int colorIndex, ref Vector2 pos, ref Vector2 velocity, float angle)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerUpdate);
message.Write(owner);
message.Write(colorIndex);
message.Write(pos);
message.Write(velocity);
message.Write(angle);
_server.SendToAll(message, connectionToExclude, NetDeliveryMethod.UnreliableSequenced, 1);
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Camera;
namespace SpacePew.ParticleSystem
{
public class ExplosionParticleSystem : ParticleSystem
{
public ExplosionParticleSystem(MainGame game, int howManyEffects, ICamera2D camera) : base(game, howManyEffects, camera) { }
protected override void InitializeConstants()
{
_textureFilename = "ParticleTextures\\explosion";
_minInitialSpeed = 40;
_maxInitialSpeed = 500;
_minAcceleration = 0;
_maxAcceleration = 0;
_minLifetime = .5f;
_maxLifetime = 1.0f;
_minScale = .3f;
_maxScale = 1.0f;
_minNumParticles = 20;
_maxNumParticles = 25;
_minRotationSpeed = -MathHelper.PiOver4;
_maxRotationSpeed = MathHelper.PiOver4;
_blendState = BlendState.Additive;
DrawOrder = AdditiveDrawOrder;
}
protected override void InitializeParticle(Particle p, Vector2 where)
{
base.InitializeParticle(p, where);
p.Acceleration = -p.Velocity / p.Lifetime;
}
}
}

View File

@@ -0,0 +1,41 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Camera;
namespace SpacePew.ParticleSystem
{
public class ExplosionSmokeParticleSystem : ParticleSystem
{
public ExplosionSmokeParticleSystem(MainGame game, int howManyEffects, ICamera2D camera)
: base(game, howManyEffects, camera)
{
}
protected override void InitializeConstants()
{
_textureFilename = "ParticleTextures\\smoke";
_minInitialSpeed = 20;
_maxInitialSpeed = 200;
_minAcceleration = -10;
_maxAcceleration = -50;
_minLifetime = 1.0f;
_maxLifetime = 2.5f;
_minScale = 1.0f;
_maxScale = 2.0f;
_minNumParticles = 10;
_maxNumParticles = 20;
_minRotationSpeed = -MathHelper.PiOver4;
_maxRotationSpeed = MathHelper.PiOver4;
_blendState = BlendState.AlphaBlend;
DrawOrder = AlphaBlendDrawOrder;
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using Microsoft.Xna.Framework;
namespace SpacePew.ParticleSystem
{
public class Particle
{
private static readonly Random _random = new Random();
private float RandomBetween(float min, float max)
{
return min + (float)_random.NextDouble() * (max - min);
}
public Vector2 Position;
public Vector2 Velocity;
public Vector2 Acceleration;
public float Scale { get; set; }
public float Lifetime { get; private set; }
public float TimeSinceStart { get; private set; }
public float Rotation { get; private set; }
public float RotationSpeed { get; private set; }
public bool Active
{
get { return TimeSinceStart < Lifetime; }
}
public void Initialize(Vector2 position, Vector2 velocity, Vector2 acceleration, float lifetime, float scale, float rotationSpeed)
{
this.Position = position;
this.Velocity = velocity;// *this.Scale;
this.Acceleration = acceleration;
this.Lifetime = lifetime * this.Scale;
this.Scale = scale * this.Scale;
this.RotationSpeed = rotationSpeed;
this.TimeSinceStart = 0.0f;
this.Rotation = RandomBetween(0, MathHelper.TwoPi);
}
public void Update(float dt)
{
Velocity += Acceleration * dt;
Position += Velocity * dt;
Rotation += RotationSpeed * dt;
TimeSinceStart += dt;
}
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using SpacePew.Camera;
namespace SpacePew.ParticleSystem
{
public abstract class ParticleSystem : DrawableGameComponent
{
private static readonly Random _random = new Random();
protected Random Random
{
get { return _random; }
}
protected float RandomBetween(float min, float max)
{
return min + (float)_random.NextDouble() * (max - min);
}
public const int AlphaBlendDrawOrder = 100;
public const int AdditiveDrawOrder = 200;
private readonly MainGame _game;
private readonly int _howManyEffects;
private Texture2D _texture;
private Vector2 _origin;
private Particle[] _particles;
private Queue<Particle> _freeParticles;
public int FreeParticleCount
{
get { return _freeParticles.Count; }
}
protected int _minNumParticles;
protected int _maxNumParticles;
protected string _textureFilename;
protected float _minInitialSpeed;
protected float _maxInitialSpeed;
protected float _minAcceleration;
protected float _maxAcceleration;
protected float _minRotationSpeed;
protected float _maxRotationSpeed;
protected float _minLifetime;
protected float _maxLifetime;
protected float _minScale;
protected float _maxScale;
protected BlendState _blendState;
protected ICamera2D _camera;
protected ParticleSystem(MainGame game, int howManyEffects, ICamera2D camera)
: base(game)
{
this._game = game;
this._howManyEffects = howManyEffects;
this._camera = camera;
}
public override void Initialize()
{
InitializeConstants();
_particles = new Particle[_howManyEffects * _maxNumParticles];
_freeParticles = new Queue<Particle>(_howManyEffects * _maxNumParticles);
for (int i = 0; i < _particles.Length; i++)
{
_particles[i] = new Particle();
_freeParticles.Enqueue(_particles[i]);
}
base.Initialize();
}
protected abstract void InitializeConstants();
protected override void LoadContent()
{
if (string.IsNullOrEmpty(_textureFilename))
{
throw new ArgumentNullException("textureFilename");
}
_texture = _game.Content.Load<Texture2D>(_textureFilename);
_origin.X = _texture.Width / 2;
_origin.Y = _texture.Height / 2;
base.LoadContent();
}
public void AddParticles(Vector2 where, float scale)
{
int numParticles = Random.Next(_minNumParticles, _maxNumParticles);
for (int i = 0; i < numParticles && _freeParticles.Count > 0; i++)
{
Particle p = _freeParticles.Dequeue();
p.Scale = scale;
InitializeParticle(p, where);
}
}
protected virtual void InitializeParticle(Particle p, Vector2 where)
{
Vector2 direction = PickRandomDirection();
float velocity =
RandomBetween(_minInitialSpeed, _maxInitialSpeed);
float acceleration =
RandomBetween(_minAcceleration, _maxAcceleration);
float lifetime =
RandomBetween(_minLifetime, _maxLifetime);
float scale =
RandomBetween(_minScale, _maxScale);
float rotationSpeed =
RandomBetween(_minRotationSpeed, _maxRotationSpeed);
p.Initialize(
where, velocity * direction, acceleration * direction,
lifetime, scale, rotationSpeed);
}
protected virtual Vector2 PickRandomDirection()
{
float angle = RandomBetween(0, MathHelper.TwoPi);
return new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
}
public override void Update(GameTime gameTime)
{
var dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
foreach (var p in _particles.Where(p => p.Active))
{
p.Update(dt);
if (!p.Active)
{
_freeParticles.Enqueue(p);
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
_game.SpriteBatch.Begin(SpriteSortMode.Deferred, _blendState, null, null, null, null, _camera.Transform);
foreach (Particle p in _particles)
{
if (!p.Active)
continue;
float normalizedLifetime = p.TimeSinceStart / p.Lifetime;
float alpha = 4 * normalizedLifetime * (1 - normalizedLifetime);
var color = new Color(new Vector4(1, 1, 1, alpha));
float scale = p.Scale * (.75f + .25f * normalizedLifetime);
_game.SpriteBatch.Draw(_texture,
p.Position,
null,
color,
p.Rotation,
_origin,
scale,
SpriteEffects.None,
0.0f);
}
_game.SpriteBatch.End();
base.Draw(gameTime);
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SpacePew.Camera;
namespace SpacePew.ParticleSystem
{
public class SmokePlumeParticleSystem : ParticleSystem
{
public SmokePlumeParticleSystem(MainGame game, int howManyEffects, ICamera2D camera)
: base(game, howManyEffects, camera)
{
}
protected override void InitializeConstants()
{
_textureFilename = "ParticleTextures\\smoke";
_minInitialSpeed = 20;
_maxInitialSpeed = 100;
_minAcceleration = 0;
_maxAcceleration = 0;
_minLifetime = 5.0f;
_maxLifetime = 7.0f;
_minScale = .5f;
_maxScale = 1.0f;
_minNumParticles = 7;
_maxNumParticles = 15;
_minRotationSpeed = -MathHelper.PiOver4 / 2.0f;
_maxRotationSpeed = MathHelper.PiOver4 / 2.0f;
_blendState = BlendState.AlphaBlend;
DrawOrder = AlphaBlendDrawOrder;
}
protected override Vector2 PickRandomDirection()
{
float radians = RandomBetween(
MathHelper.ToRadians(80), MathHelper.ToRadians(100));
Vector2 direction = Vector2.Zero;
direction.X = (float)Math.Cos(radians);
direction.Y = -(float)Math.Sin(radians);
return direction;
}
protected override void InitializeParticle(Particle p, Vector2 where)
{
base.InitializeParticle(p, where);
p.Acceleration.X += RandomBetween(10, 50);
}
}
}

26
SpacePew/Program.cs Normal file
View File

@@ -0,0 +1,26 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
#endregion
namespace SpacePew
{
#if WINDOWS || LINUX
/// <summary>
/// The main class.
/// </summary>
public static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (var game = new MainGame())
game.Run();
}
}
#endif
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SpacePew")]
[assembly: AssemblyProduct("SpacePew")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © 2009")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1588cda1-b2dd-4e65-bd68-1dcdcc35901d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]

41
SpacePew/SoundManager.cs Normal file
View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;
namespace SpacePew
{
public static class SoundManager
{
private static MainGame _game;
public static void Initialize(MainGame game)
{
_game = game;
}
public static SoundEffectInstance GetSoundEffectInstance(string assetName)
{
var soundEffect = _game.Content.Load<SoundEffect>(assetName);
var soundEffectInstance = soundEffect.CreateInstance();
return soundEffectInstance;
}
private static int _playCalled = 0;
public static void Play(string assetName, Vector2 position)
{
Debug.Print("Play called: " + ++_playCalled);
var soundEffect = _game.Content.Load<SoundEffect>(assetName);
var soundEffectInstance = soundEffect.CreateInstance();
var emitter = new AudioEmitter();
var listener = new AudioListener();
emitter.Position = new Vector3(position, 0);
listener.Position = new Vector3(_game.NetworkClient.LocalPlayer.Position, 0);
soundEffectInstance.Apply3D(listener, emitter);
soundEffectInstance.Play();
}
}
}

236
SpacePew/SpacePew.csproj Normal file
View File

@@ -0,0 +1,236 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1C82F1B3-6F3C-47EC-901A-E656D037F862}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpacePew</RootNamespace>
<AssemblyName>SpacePew</AssemblyName>
<FileAlignment>512</FileAlignment>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Windows\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Windows\Release\</OutputPath>
<DefineConstants>TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Compile Include="Arena.cs" />
<Compile Include="Camera\Camera2D.cs" />
<Compile Include="Camera\ICamera2D.cs" />
<Compile Include="Camera\IFocusable.cs" />
<Compile Include="EntityFactory.cs" />
<Compile Include="Extensions\LidgrenExtensions.cs" />
<Compile Include="Extensions\RenderExtensions.cs" />
<Compile Include="Hud.cs" />
<Compile Include="KeyboardHelper.cs" />
<Compile Include="LevelLoader.cs" />
<Compile Include="MainGame.cs" />
<Compile Include="Minimap.cs" />
<Compile Include="Models\EntityBase.cs" />
<Compile Include="Models\Explosion.cs" />
<Compile Include="Models\IEntity.cs" />
<Compile Include="Models\IKillable.cs" />
<Compile Include="Models\Level.cs" />
<Compile Include="Models\MapHit.cs" />
<Compile Include="Models\Player.cs" />
<Compile Include="Models\Projectiles\BouncingBullet.cs" />
<Compile Include="Models\Projectiles\Bullet.cs" />
<Compile Include="Models\Projectiles\ClusterBomb.cs" />
<Compile Include="Models\Projectiles\CollisionType.cs" />
<Compile Include="Models\Projectiles\HomingBullet.cs" />
<Compile Include="Models\Projectiles\IProjectile.cs" />
<Compile Include="Models\Projectiles\LongShot.cs" />
<Compile Include="Models\Projectiles\Missile.cs" />
<Compile Include="Models\Projectiles\ProjectileBase.cs" />
<Compile Include="Models\Weapons\Cannon.cs" />
<Compile Include="Models\Weapons\ClusterLauncher.cs" />
<Compile Include="Models\Weapons\IWeapon.cs" />
<Compile Include="Models\Weapons\Launcher.cs" />
<Compile Include="Models\Weapons\SecondaryCannon.cs" />
<Compile Include="Models\Weapons\TriCannon.cs" />
<Compile Include="Models\Weapons\WeaponBase.cs" />
<Compile Include="Networking\NetworkMessage.cs" />
<Compile Include="Networking\NetworkMessenger.cs" />
<Compile Include="Networking\ScoreBoard.cs" />
<Compile Include="Networking\ScoreBoardItem.cs" />
<Compile Include="Networking\StreamingClient.cs" />
<Compile Include="Networking\UdpBase.cs" />
<Compile Include="Networking\UdpClient.cs" />
<Compile Include="Networking\UdpNetworkGui.cs" />
<Compile Include="Networking\UdpServer.cs" />
<Compile Include="ParticleSystem\ExplosionParticleSystem.cs" />
<Compile Include="ParticleSystem\ExplosionSmokeParticleSystem.cs" />
<Compile Include="ParticleSystem\Particle.cs" />
<Compile Include="ParticleSystem\ParticleSystem.cs" />
<Compile Include="ParticleSystem\SmokePlumeParticleSystem.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SoundManager.cs" />
<Compile Include="TextureManager.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.85.5.452, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Library\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework, Version=3.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="NAudio">
<HintPath>..\Library\NAudio.dll</HintPath>
</Reference>
<Reference Include="NVorbis">
<HintPath>..\Library\NVorbis.dll</HintPath>
</Reference>
<Reference Include="NVorbis.NAudioSupport">
<HintPath>..\Library\NVorbis.NAudioSupport.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=2.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct3D11, Version=2.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\SharpDX.Direct3D11.dll</HintPath>
</Reference>
<Reference Include="SharpDX.MediaFoundation, Version=2.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\SharpDX.MediaFoundation.dll</HintPath>
</Reference>
<Reference Include="SharpDX.XAudio2, Version=2.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\SharpDX.XAudio2.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Content Include="C:\Program Files %28x86%29\MonoGame\v3.0\Assemblies\WindowsGL\SDL.dll">
<Link>SDL.dll</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Downloads\Levels\dummy.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Game.ico" />
<Content Include="GameThumbnail.png" />
<Content Include="Icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj">
<Project>{49ba1c69-6104-41ac-a5d8-b54fa9f696e8}</Project>
<Name>Lidgren.Network</Name>
</ProjectReference>
<ProjectReference Include="..\Neoforce\TomShane.Neoforce.Controls.csproj">
<Project>{ac5f1cd8-aa8e-4db5-814f-86c214175841}</Project>
<Name>TomShane.Neoforce.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\SpacePew.Common\SpacePew.Common.csproj">
<Project>{ba98d4ca-718b-4e50-ad4d-f48e8ca67624}</Project>
<Name>SpacePew.Common</Name>
</ProjectReference>
<ProjectReference Include="..\SpacePew.Content\SpacePew.Content\SpacePew.Content.csproj">
<Project>{944baed2-53a4-47e9-ae89-7f6c5843de94}</Project>
<Name>SpacePew.Content</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="Content\Skins\Blue.skin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\Skins\Default.skin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\Skins\Green.skin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\Skins\Magenta.skin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Content\Skins\Purple.skin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Levels\hippie.zip">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
namespace SpacePew
{
public static class TextureManager
{
private static MainGame _game;
static readonly Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>();
public static void Initialize(MainGame game)
{
_game = game;
}
public static Texture2D LoadTexture(string assetName)
{
if (!Textures.ContainsKey(assetName))
{
var texture = _game.Content.Load<Texture2D>(assetName);
Textures.Add(assetName, texture);
}
return Textures[assetName];
}
}
}

3
SpacePew/app.config Normal file
View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>