old experiments in writing C# games

This commit is contained in:
James Turk 2024-09-06 19:47:51 -04:00
commit 5a73410b54
97 changed files with 4568 additions and 0 deletions

5
Dakota/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

3
Dakota/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Nez"]
path = Nez
url = git@github.com:prime31/Nez.git

11
Dakota/.idea/.idea.Dakota/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,11 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/.idea.Dakota.iml
/projectSettingsUpdater.xml
/modules.xml
/contentModel.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

7
Dakota/.idea/.idea.Dakota/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/Nez" vcs="Git" />
</component>
</project>

28
Dakota/Dakota.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dakota", "Dakota\Dakota.csproj", "{2FF89EAA-6572-40AB-8A4D-BCE3275F113F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.MG38", "Nez\Nez.Portable\Nez.MG38.csproj", "{0A2DAF9B-E04C-4624-BA85-82CEA0F7D1F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DakotaTests", "DakotaTests\DakotaTests.csproj", "{24B9130D-9930-43D2-A3EA-8D3055355502}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2FF89EAA-6572-40AB-8A4D-BCE3275F113F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2FF89EAA-6572-40AB-8A4D-BCE3275F113F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2FF89EAA-6572-40AB-8A4D-BCE3275F113F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2FF89EAA-6572-40AB-8A4D-BCE3275F113F}.Release|Any CPU.Build.0 = Release|Any CPU
{0A2DAF9B-E04C-4624-BA85-82CEA0F7D1F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A2DAF9B-E04C-4624-BA85-82CEA0F7D1F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A2DAF9B-E04C-4624-BA85-82CEA0F7D1F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A2DAF9B-E04C-4624-BA85-82CEA0F7D1F6}.Release|Any CPU.Build.0 = Release|Any CPU
{24B9130D-9930-43D2-A3EA-8D3055355502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24B9130D-9930-43D2-A3EA-8D3055355502}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24B9130D-9930-43D2-A3EA-8D3055355502}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24B9130D-9930-43D2-A3EA-8D3055355502}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=batcher/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,12 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=04195ef0_002Db45a_002D4c34_002D9acc_002D490c75ed258a/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="All tests from &amp;lt;DakotaTests&amp;gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
&lt;Project Location="/Users/james/Desktop/Dakota/DakotaTests" Presentation="&amp;lt;DakotaTests&amp;gt;" /&gt;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=3c8f59d4_002Debac_002D44f8_002Dbbfc_002D599bf5002101/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &amp;lt;DakotaTests&amp;gt; #3" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
&lt;Project Location="/Users/james/Desktop/Dakota/DakotaTests" Presentation="&amp;lt;DakotaTests&amp;gt;" /&gt;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=b58decbb_002Df9a2_002D4b45_002Db0f2_002D95bdb60e00b7/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="All tests from &amp;lt;DakotaTests&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
&lt;Project Location="/Users/james/Desktop/Dakota/DakotaTests" Presentation="&amp;lt;DakotaTests&amp;gt;" /&gt;
&lt;/SessionState&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Renderable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Renderables/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,27 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin Sprites/Ship00.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:Sprites/Ship00.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="Content\Content.mgcb" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nez\Nez.Portable\Nez.MG38.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,31 @@
using Microsoft.Xna.Framework;
namespace Dakota.Data
{
public static class GameConstants
{
public const int UiRenderLayerBg = 910;
public const int UiRenderLayerFg = 900;
public const int BackgroundRenderLayer = 50;
public static Color ColorBlack = Color.Black;
// Space UI
public static Color SpaceUiColor = Color.White;
public static Color SpaceHudFontColor = new Color(0, 255, 0);
// Space Gameplay
public const float ShipAcceleration = 100;
public const float ShipTurnSpeed = 10;
// Space Colors
public static Color ShipColor = Color.White;
public static Color BoostColor = new Color(255, 128, 0);
public static Color AsteroidColor = new Color(128, 128, 128);
public static Color FriendlyWeaponColor = new Color(0, 255, 0);
public static Color HostileWeaponColor = new Color(255, 0, 255);
public static Color SpaceCommandColor = new Color(128, 128, 255);
public static Color NoFlyZoneColor = new Color(200, 0, 0);
}
}

View File

@ -0,0 +1,24 @@
using Dakota.Space;
namespace Dakota.Data
{
public enum ProjectileType
{
Bullet,
Beam
}
public class PrimaryWeapon
{
public static PrimaryWeapon Gun = new PrimaryWeapon
{Name = "MASS DRIVER", Projectile = ProjectileType.Bullet, Speed = 200f, Duration = 2};
public static PrimaryWeapon Beam = new PrimaryWeapon
{Name = "PHASE BEAM", Projectile = ProjectileType.Beam, Speed = 100f, Duration = 0.2f};
public float Duration;
public string Name;
public ProjectileType Projectile;
public float Speed;
}
}

View File

@ -0,0 +1,58 @@
namespace Dakota.Data
{
public class Zone
{
public int Height;
public bool IsCurvedX;
public bool IsCurvedY;
// a rectangular region in space
public int UniversalX;
public int UniversalY;
public int Width;
public Zone()
{
UniversalX = 0;
UniversalY = 0;
Width = 3000;
Height = 3000;
IsCurvedX = false;
IsCurvedY = false;
}
}
public static class ZoneData
{
private static Zone[,] _zones = new Zone[26, 26];
public static Zone GetZone(int x, int y)
{
if (_zones[x, y] is null)
{
var zone = new Zone
{
UniversalX = x,
UniversalY = y,
Width = 3000,
Height = 3000
};
// Act 1, Scene 1
if (x == 16 && y == 13)
{
zone.Width = 1000;
zone.Height = 1000;
}
if (x == 3 && y == 3) zone.IsCurvedX = true;
if (x == 3 && y > 8 && y < 16) zone.IsCurvedY = true;
_zones[x, y] = zone;
}
return _zones[x, y];
}
}
}

14
Dakota/Dakota/Game1.cs Normal file
View File

@ -0,0 +1,14 @@
using Dakota.Space;
using Nez;
namespace Dakota
{
public class Game1 : Core
{
protected override void Initialize()
{
base.Initialize();
Scene = new SpaceScene();
}
}
}

BIN
Dakota/Dakota/Icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
Dakota/Dakota/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -0,0 +1,118 @@
using Dakota.Data;
using Dakota.Space;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Missions
{
public class Mission1 : SpaceMission
{
/*
* 1) fly into boundary: add asteroids & boundary
* 2) destroy one asteroid: OK 3 more
* 3) three more: zone map
* 4) fly to highlighted zone
* this is a metroidvania shooter?
*/
private NoFlyZone _noFlyZone;
private string _status;
private const int SmallAsteroidGoal = 16;
public override string GetMissionStatus()
{
return _status;
}
public override void OnStart()
{
ZoneShiftDisabled = true;
SpaceScene.CurrentZone = ZoneData.GetZone(16, 13);
SpaceScene.PlayerWarpTo(new Vector2(500, 500));
SpaceScene.Primary = PrimaryWeapon.Gun;
_status = "EXPLORE AREA";
AddBoundary("inner",
new Rectangle(100, 100, SpaceScene.CurrentZone.Width - 100, SpaceScene.CurrentZone.Height - 100));
_noFlyZone = SpaceScene.CreateEntity("no fly zone").AddComponent(new NoFlyZone(100));
_noFlyZone.Enabled = false;
Core.Schedule(0.1f,
timer => SpaceScene.DialogBox.ShowDialog(
"THIS IS YOUR FIRST TIME FLYING \nOUTSIDE SIMULATION.\nTRY AND FLY AROUND A BIT.", 10));
}
internal void AddEmitters()
{
SpaceScene.AsteroidEmitter.EmitSpeed = 5;
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(0, 0));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(1000, 1000));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(0, 1000));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(1000, 0));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(500, 0));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(0, 500));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(1000, 500));
SpaceScene.AsteroidEmitter.AddEmitter(new Vector2(500, 1000));
}
public override void OnExitRegion(string name)
{
if (!_noFlyZone.Enabled)
{
SpaceScene.DialogBox.ShowDialog("IT IS EASY TO GET LOST IN SPACE\nLET'S STAY CLOSE FOR NOW", 3);
_noFlyZone.Enabled = true;
_status = "DESTROY ASTEROIDS";
AddEmitters();
}
AutopilotReverse(150);
}
public override void OnAsteroidDestroyed(AsteroidSize size)
{
base.OnAsteroidDestroyed(size);
if (size == AsteroidSize.LARGE && AsteroidsDestroyed[AsteroidSize.LARGE] == 1)
{
SpaceScene.DialogBox.ShowDialog("GREAT JOB! BE SURE TO BREAK UP THE REST OF IT", 3);
}
else if (size == AsteroidSize.MEDIUM && AsteroidsDestroyed[AsteroidSize.MEDIUM] % 3 == 0)
{
SpaceScene.DialogBox.ShowDialog("KEEP IT UP!", 3);
}
else if (size == AsteroidSize.SMALL)
{
if (AsteroidsDestroyed[AsteroidSize.SMALL] >= 4 &&
AsteroidsDestroyed[AsteroidSize.SMALL] < SmallAsteroidGoal)
{
var percent = (int) ((float) AsteroidsDestroyed[AsteroidSize.SMALL] / SmallAsteroidGoal * 100);
_status = $"DESTROY ASTEROIDS\n{percent}";
}
switch (AsteroidsDestroyed[AsteroidSize.SMALL])
{
case 4:
SpaceScene.DialogBox.ShowDialog("OK ONE DOWN, PHEW!\nTAKE OUT 3 MORE", 3);
break;
case 10:
SpaceScene.DialogBox.ShowDialog("JUST A FEW MORE!", 3);
break;
case SmallAsteroidGoal:
SpaceScene.DialogBox.ShowDialog("ALL DONE! LET'S LOOK AT YOUR MAP.", 3);
break;
}
}
}
public override void OnPlayerHit()
{
base.OnPlayerHit();
if (PlayerHitCount == 1)
SpaceScene.DialogBox.ShowDialog("WATCH OUT, THESE SHIPS ARE EXPENSIVE", 3);
else if (PlayerHitCount == 10)
SpaceScene.DialogBox.ShowDialog("YOU ARE TERRIBLE AT THIS", 3);
}
}
}

View File

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using Dakota.Data;
using Dakota.Space;
using Dakota.Utils;
using Microsoft.Xna.Framework;
using Nez;
using Random = Nez.Random;
namespace Dakota.Missions
{
public class SpaceMission : SceneComponent
{
protected SpaceScene SpaceScene => (SpaceScene) Scene;
protected int PlayerHitCount;
protected Dictionary<AsteroidSize, int> AsteroidsDestroyed;
public bool ZoneShiftDisabled;
private readonly Dictionary<string, Rectangle> _boundaries;
private readonly Dictionary<string, bool> _lastFrame;
private Vector2? _autopilotDestination;
protected SpaceMission()
{
ZoneShiftDisabled = false;
AsteroidsDestroyed = new Dictionary<AsteroidSize, int>();
foreach (AsteroidSize size in Enum.GetValues(typeof(AsteroidSize))) AsteroidsDestroyed[size] = 0;
_boundaries = new Dictionary<string, Rectangle>();
_lastFrame = new Dictionary<string, bool>();
}
protected void AddBoundary(string name, Rectangle rect)
{
_boundaries[name] = rect;
_lastFrame[name] = false;
}
protected void AutopilotTo(Vector2 to)
{
_autopilotDestination = to;
SpaceScene.CenterText.SetText("AUTOPILOT ENGAGED", 3);
}
protected void AutopilotReverse(int magnitude)
{
var backwards = -Vector2.Normalize(SpaceScene.Player.GetComponent<SpaceObject>().Velocity);
AutopilotTo(SpaceScene.Player.Position + backwards * magnitude);
}
#region Hooks
// these methods can be overriden on missions to control behavior
public virtual string GetMissionStatus()
{
return "";
}
public virtual void OnStart()
{
}
public virtual void OnAsteroidDestroyed(AsteroidSize size)
{
AsteroidsDestroyed[size] += 1;
}
public virtual void OnPlayerHit()
{
PlayerHitCount += 1;
}
public virtual void OnEnterRegion(string name)
{
}
public virtual void OnExitRegion(string name)
{
}
#endregion
public override void Update()
{
// check boundaries
foreach (var (name, rect) in _boundaries)
{
var thisFrame = rect.Contains(SpaceScene.Player.Position);
if (thisFrame && !_lastFrame[name])
OnEnterRegion(name);
if (!thisFrame && _lastFrame[name])
OnExitRegion(name);
_lastFrame[name] = thisFrame;
}
// autopilot adjustments
if (_autopilotDestination != null)
{
var dist = SpaceScene.Player.Position - (Vector2) _autopilotDestination;
if (dist.Length() < 35)
{
_autopilotDestination = null;
SpaceScene.CenterText.SetText("AUTOPILOT DISENGAGED", 3);
SpaceScene.Player.GetComponent<SpaceObject>().Velocity = Vector2.Zero;
SpaceScene.Player.GetComponent<PlayerShip>().Thrust(0);
}
else
{
var targetAngle = DakotaUtils.ToAngle(dist);
if (dist.Length() > 100)
targetAngle += (float) Math.PI;
if (SpaceScene.Player.Rotation - targetAngle > 0.1f)
SpaceScene.Player.Rotation -= GameConstants.ShipTurnSpeed * Time.DeltaTime;
else if (targetAngle - SpaceScene.Player.Rotation > 0.1f)
SpaceScene.Player.Rotation += GameConstants.ShipTurnSpeed * Time.DeltaTime;
else
SpaceScene.Player.GetComponent<PlayerShip>().Thrust(.01f);
}
}
}
}
}

16
Dakota/Dakota/Program.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
namespace Dakota
{
public static class Program
{
[STAThread]
private static void Main()
{
using (var game = new Game1())
{
game.Run();
}
}
}
}

View File

@ -0,0 +1,58 @@
using Dakota.Data;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Renderables
{
public class DialogBox : RenderableComponent, IUpdatable
{
public override float Width => 1000;
public override float Height => 100;
private const int Padding = 10;
private const int PhotoBoxSize = 72;
private float _durationRemaining;
private VectorText _vt;
private StaticBox _sb;
public override void OnAddedToEntity()
{
RenderLayer = GameConstants.UiRenderLayerBg;
_vt = Entity.AddComponent(new VectorText("", 20, GameConstants.SpaceUiColor));
_vt.LocalOffset = new Vector2(Padding * 2 + PhotoBoxSize, Padding);
_sb = Entity.AddComponent(new StaticBox(72, 72, GameConstants.SpaceCommandColor));
_sb.LocalOffset = new Vector2(Padding, Padding);
}
public override void Render(Batcher batcher, Camera camera)
{
batcher.DrawRect(Entity.Position, Width, Height, GameConstants.ColorBlack);
batcher.DrawHollowRect(Entity.Position, Width - 5, Height, GameConstants.SpaceUiColor);
batcher.DrawHollowRect(Entity.Position.X + Padding, Entity.Position.Y + Padding,
PhotoBoxSize, PhotoBoxSize, GameConstants.SpaceUiColor);
}
public void Update()
{
_durationRemaining -= Time.DeltaTime;
if (_durationRemaining < 0)
{
Enabled = false;
_vt.Enabled = false;
_sb.Enabled = false;
}
}
public void ShowDialog(string text, float duration)
{
_durationRemaining = duration;
_vt.Text = text;
_vt.Color = GameConstants.SpaceCommandColor;
Enabled = true;
_vt.Enabled = true;
_sb.Enabled = true;
}
}
}

View File

@ -0,0 +1,35 @@
using Dakota.Data;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Renderables
{
public class StaticBox : RenderableComponent
{
public override float Width => _width;
public override float Height => _height;
private int _width;
private int _height;
public StaticBox(int width, int height, Color color)
{
_width = width;
_height = height;
Color = color;
RenderLayer = GameConstants.UiRenderLayerBg;
}
public override void Render(Batcher batcher, Camera camera)
{
for (var x = 0; x < Width; ++x)
for (var y = 0; y < Height; ++y)
if (Random.Chance(0.2f))
batcher.DrawPixel(
Entity.Position.X + LocalOffset.X + x,
Entity.Position.Y + LocalOffset.Y + y,
Color);
}
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Renderables
{
public class TimedVectorText : VectorText, IUpdatable
{
private float _durationRemaining;
public TimedVectorText(int size, Color color) : base("", size, color)
{
}
public void Update()
{
if (Text.Length > 0)
{
_durationRemaining -= Time.DeltaTime;
if (_durationRemaining < 0) Text = "";
}
}
public void SetText(string text, float duration)
{
Text = text;
_durationRemaining = duration;
}
}
}

View File

@ -0,0 +1,37 @@
using Microsoft.Xna.Framework;
using Nez;
using Nez.PhysicsShapes;
namespace Dakota.Renderables
{
public class VectorSprite : RenderableComponent, IUpdatable
{
private Vector2[] _polygon;
private Vector2[] _rotatedPolygon;
public override float Width => 100;
public override float Height => 100;
public VectorSprite(Vector2[] polygon, Color color)
{
_polygon = polygon;
_rotatedPolygon = new Vector2[polygon.Length];
Color = color;
}
public override void OnAddedToEntity()
{
Polygon.RotatePolygonVerts(Entity.Rotation, _polygon, _rotatedPolygon);
}
public override void Render(Batcher batcher, Camera camera)
{
Polygon.RotatePolygonVerts(Entity.Rotation, _polygon, _rotatedPolygon);
batcher.DrawPolygon(Entity.Position, _rotatedPolygon, Color, true, 1);
}
public void Update()
{
}
}
}

View File

@ -0,0 +1,458 @@
using System;
using System.Collections.Generic;
using Dakota.Data;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Renderables
{
public class VectorText : RenderableComponent
{
private const char Unprintable = '~';
private static Dictionary<char, Vector2?[]> _font = new Dictionary<char, Vector2?[]>();
public int Size;
public string Text;
public float Thickness = 1.0f;
static VectorText()
{
// each entry corresponds to the vectors for a given glyph
// lines are drawn from point to point the way one would if writing
// a null will "lift the pen" so to speak, starting a new set of
// lines not connected to the prior set
_font[Unprintable] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(1, 1),
null,
new Vector2(0, 1),
new Vector2(1, 0)
};
_font['A'] = new Vector2?[]
{
new Vector2(0, 1),
new Vector2(0.5f, 0),
new Vector2(1, 1),
null,
new Vector2(0.2f, 0.5f),
new Vector2(0.7f, 0.5f)
};
_font['B'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0.8f),
new Vector2(1, 0.6f),
new Vector2(0, 0.5f),
new Vector2(1, 0.4f),
new Vector2(1, 0.2f),
new Vector2(0, 0)
};
_font['C'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
_font['D'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(0.5f, 1),
new Vector2(1, 0.6f),
new Vector2(1, 0.4f),
new Vector2(0.5f, 0),
new Vector2(0, 0)
};
_font['E'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
null,
new Vector2(0, 0.5f),
new Vector2(1, 0.5f)
};
_font['F'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
null,
new Vector2(0, 0.5f),
new Vector2(1, 0.5f)
};
_font['G'] = new Vector2?[]
{
new Vector2(1, 0.2f),
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0.7f),
new Vector2(0.5f, 0.7f)
};
_font['H'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
null,
new Vector2(1, 0),
new Vector2(1, 1),
null,
new Vector2(0, 0.5f),
new Vector2(1, 0.5f)
};
_font['I'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
null,
new Vector2(0, 1),
new Vector2(1, 1),
null,
new Vector2(0.5f, 0),
new Vector2(0.5f, 1)
};
_font['J'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(1, 1),
new Vector2(0.5f, 1),
new Vector2(0, 0.7f)
};
_font['K'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0.5f),
new Vector2(1, 1),
null,
new Vector2(0, 0),
new Vector2(0, 1)
};
_font['L'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
_font['M'] = new Vector2?[]
{
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(0.5f, 0.2f),
new Vector2(1, 0),
new Vector2(1, 1)
};
_font['N'] = new Vector2?[]
{
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 1),
new Vector2(1, 0)
};
_font['O'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0)
};
_font['P'] = new Vector2?[]
{
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 0.4f),
new Vector2(0, 0.4f)
};
_font['Q'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0),
null,
new Vector2(1, 1),
new Vector2(0.5f, 0.6f)
};
_font['R'] = new Vector2?[]
{
new Vector2(0, 1),
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 0.4f),
new Vector2(0, 0.4f),
new Vector2(1, 1)
};
_font['S'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 0.5f),
new Vector2(1, 0.5f),
new Vector2(1, 1),
new Vector2(0, 1)
};
_font['T'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
null,
new Vector2(0.5f, 0),
new Vector2(0.5f, 1)
};
_font['U'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0)
};
_font['V'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0.5f, 1),
new Vector2(1, 0)
};
_font['W'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(0.5f, 0.7f),
new Vector2(1, 1),
new Vector2(1, 0)
};
_font['X'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 1),
null,
new Vector2(1, 0),
new Vector2(0, 1)
};
_font['Y'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0.5f, 0.4f),
new Vector2(1, 0),
null,
new Vector2(0.5f, 0.4f),
new Vector2(0.5f, 1)
};
_font['Z'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
_font['0'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 1)
};
_font['1'] = new Vector2?[]
{
new Vector2(0.5f, 1),
new Vector2(0.5f, 0),
new Vector2(0.3f, 0.2f)
};
_font['2'] = new Vector2?[]
{
new Vector2(0, 0.2f),
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
_font['3'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 0.5f),
new Vector2(1, 0.5f),
new Vector2(1, 1),
new Vector2(0, 1)
};
_font['4'] = new Vector2?[]
{
new Vector2(0.8f, 1),
new Vector2(0.8f, 0),
new Vector2(0, 0.5f),
new Vector2(1, 0.5f)
};
_font['5'] = new Vector2?[]
{
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 0.5f),
new Vector2(1, 0.5f),
new Vector2(0, 1)
};
_font['6'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0.6f),
new Vector2(0, 0.6f)
};
_font['7'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1)
};
_font['8'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(0, 0)
};
_font['9'] = new Vector2?[]
{
new Vector2(1, 1),
new Vector2(1, 0),
new Vector2(0, 0),
new Vector2(0, 0.4f),
new Vector2(1, 0.4f)
};
_font[' '] = new Vector2?[] { };
_font['.'] = new Vector2?[]
{
new Vector2(0.5f, 0.9f),
new Vector2(0.6f, 0.9f),
new Vector2(0.6f, 1),
new Vector2(0.5f, 1),
new Vector2(0.5f, 0.9f)
};
_font['!'] = new Vector2?[]
{
new Vector2(0.55f, 0),
new Vector2(0.55f, 0.8f),
null,
new Vector2(0.5f, 0.9f),
new Vector2(0.6f, 0.9f),
new Vector2(0.6f, 1),
new Vector2(0.5f, 1),
new Vector2(0.5f, 0.9f)
};
_font['?'] = new Vector2?[]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 0.4f),
new Vector2(0.55f, 0.4f),
new Vector2(0.55f, 0.8f),
null,
new Vector2(0.5f, 0.9f),
new Vector2(0.6f, 0.9f),
new Vector2(0.6f, 1),
new Vector2(0.5f, 1),
new Vector2(0.5f, 0.9f)
};
_font[','] = new Vector2?[]
{
new Vector2(0.7f, 0.6f),
new Vector2(0.6f, 1)
};
_font['\''] = new Vector2?[]
{
new Vector2(0.7f, 0),
new Vector2(0.6f, 0.3f)
};
_font[':'] = new Vector2?[]
{
new Vector2(0.5f, 0.9f),
new Vector2(0.6f, 0.9f),
new Vector2(0.6f, 1),
new Vector2(0.5f, 1),
new Vector2(0.5f, 0.9f),
null,
new Vector2(0.5f, 0),
new Vector2(0.6f, 0),
new Vector2(0.6f, 0.1f),
new Vector2(0.5f, 0.1f),
new Vector2(0.5f, 0)
};
_font['-'] = new Vector2?[]
{
new Vector2(0.2f, 0.5f),
new Vector2(0.8f, 0.5f)
};
_font['+'] = new Vector2?[]
{
new Vector2(0.2f, 0.5f),
new Vector2(0.8f, 0.5f),
null,
new Vector2(0.5f, 0.2f),
new Vector2(0.5f, 0.8f)
};
}
public VectorText(string text, int size, Color color)
{
Text = text;
Size = size;
Color = color;
RenderLayer = GameConstants.UiRenderLayerFg;
}
// approximate
public override float Width => Size * Text.Length;
public override float Height => Size;
public override void Render(Batcher batcher, Camera camera)
{
var spacing = 5;
var curOffset = new Vector2(-Size, 0);
foreach (var ch in Text)
{
Vector2?[] letter;
if (ch == '\n')
{
curOffset.X = -Size;
curOffset.Y += Size + spacing;
continue;
}
else if (_font.ContainsKey(ch))
{
letter = _font[ch];
curOffset.X += Size + spacing;
}
else
{
letter = _font[Unprintable];
curOffset.X += Size + spacing;
Console.WriteLine($"UNPRINTABLE: {ch}");
}
for (var i = 0; i < letter.Length - 1; i++)
if (letter[i] != null && letter[i + 1] != null)
batcher.DrawLine(
(Vector2) letter[i] * Size + curOffset + Entity.Position + LocalOffset,
(Vector2) letter[i + 1] * Size + curOffset + Entity.Position + LocalOffset,
Color,
Thickness
);
}
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota
{
public class ScreenSpin : Component, IUpdatable
{
private readonly Vector2 _around;
private float _speed;
public ScreenSpin(Vector2 around, float speed)
{
_speed = speed;
_around = around;
}
public void Update()
{
Entity.Scene.Camera.Rotation += _speed * Time.DeltaTime;
if (Entity.Scene.Camera.Rotation > 5) Entity.RemoveComponent(this);
}
public override void OnAddedToEntity()
{
Entity.Scene.Camera.Position = _around;
}
}
}

View File

@ -0,0 +1,87 @@
using System;
using Dakota.Data;
using Dakota.Renderables;
using Dakota.Utils;
using Nez;
using Random = Nez.Random;
using Vector2 = Microsoft.Xna.Framework.Vector2;
namespace Dakota.Space
{
public enum AsteroidSize
{
SMALL,
MEDIUM,
LARGE,
HUGE
}
public class Asteroid : Component, ITriggerListener
{
public AsteroidSize Size;
public Asteroid(AsteroidSize size = AsteroidSize.LARGE)
{
Size = size;
}
void ITriggerListener.OnTriggerEnter(Collider other, Collider self)
{
if (other.Entity.Name == "bullet" && !other.Entity.IsDestroyed)
{
var scene = (SpaceScene) Entity.Scene;
scene.HitAsteroid(self.Entity, other.Entity.Position);
other.Entity.Destroy();
}
// need to only process A-A collisions once, so use ID comparison
if (other.Entity.Name == "asteroid" && other.Entity.Id > self.Entity.Id)
{
other.CollidesWith(self, out var collisionResult);
self.Entity.Position += collisionResult.MinimumTranslationVector;
var p1 = self.Entity.Position;
var v1 = self.Entity.GetComponent<SpaceObject>().Velocity;
var p2 = other.Entity.Position;
var v2 = other.Entity.GetComponent<SpaceObject>().Velocity;
var diff1 = p1 - p2;
var diff2 = p2 - p1;
var newV1 = v1 - Vector2.Dot(v1 - v2, diff1) / diff1.LengthSquared() * diff1;
var newV2 = v2 - Vector2.Dot(v2 - v1, diff2) / diff2.LengthSquared() * diff2;
self.Entity.GetComponent<SpaceObject>().Velocity = newV1;
other.Entity.GetComponent<SpaceObject>().Velocity = newV2;
}
}
void ITriggerListener.OnTriggerExit(Collider other, Collider self)
{
}
public override void OnAddedToEntity()
{
var numPoints = Random.NextInt(3) + 7;
var polygon = new Vector2[numPoints];
for (var i = 0; i < numPoints; i++)
{
var angle = (float) ((float) i / numPoints * 2 * Math.PI);
var radius = Radius() + Random.MinusOneToOne() * Radius() * 0.2f;
polygon[i] = radius * DakotaUtils.VecFromAngle(angle);
}
// need to clone polygon here so original is intact for drawing rotations
Entity.AddComponent(new PolygonCollider((Vector2[]) polygon.Clone())).IsTrigger = true;
Entity.AddComponent(new VectorSprite(polygon, GameConstants.AsteroidColor));
}
public float Radius()
{
return Size switch
{
AsteroidSize.HUGE => 128,
AsteroidSize.LARGE => 72,
AsteroidSize.MEDIUM => 48,
AsteroidSize.SMALL => 24,
_ => 256
};
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using Dakota.Utils;
using Microsoft.Xna.Framework;
using Nez;
using Random = Nez.Random;
namespace Dakota.Space
{
public class BaddieEmitter : SceneComponent, IUpdatable
{
private List<Vector2> _emitterPoints;
private float _nextEmission;
public float EmitSpeed;
public BaddieEmitter()
{
_emitterPoints = new List<Vector2>();
EmitSpeed = 0;
_nextEmission = 0;
}
public void AddEmitter(Vector2 pos)
{
_emitterPoints.Add(pos);
}
public void Emit()
{
var scene = (SpaceScene) Scene;
var posIndex = Random.NextInt(_emitterPoints.Count);
var pos = _emitterPoints[posIndex];
var angle = DakotaUtils.ToAngle(new Vector2(scene.CurrentZone.Width / 2 - pos.X,
scene.CurrentZone.Height / 2 - pos.Y));
var vel = DakotaUtils.VecFromAngle(angle) * (Random.NextFloat(30) + 30);
scene.AddAsteroid(pos, AsteroidSize.LARGE, vel);
}
public override void Update()
{
if (EmitSpeed > 0)
{
if (_nextEmission == 0)
_nextEmission = EmitSpeed;
_nextEmission -= Time.DeltaTime;
if (_nextEmission < 0)
{
_nextEmission += EmitSpeed;
Emit();
}
}
}
}
}

View File

@ -0,0 +1,68 @@
using Dakota.Data;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Space
{
public class GalacticMap : RenderableComponent
{
private const float GridSize = 25f;
public override float Width => 500;
public override float Height => 520;
public GalacticMap()
{
RenderLayer = GameConstants.UiRenderLayerBg;
}
public void FillBox(Batcher batcher, int x, int y, Color color)
{
batcher.DrawRect(
GridSize * x + 1 + Entity.Position.X,
GridSize * y + 2 + Entity.Position.Y,
GridSize - 3,
GridSize - 3,
color);
}
public override void Render(Batcher batcher, Camera camera)
{
var xSectors = 26;
var ySectors = 26;
// draw horizontal lines
for (var i = 0; i <= ySectors; i++)
{
batcher.DrawLine(
0 + Entity.Position.X,
i * GridSize + Entity.Position.Y,
xSectors * GridSize + Entity.Position.X,
i * GridSize + Entity.Position.Y,
GameConstants.SpaceUiColor);
// draw vertical lines
for (var j = 0; j <= xSectors; j++)
{
batcher.DrawLine(
j * GridSize + Entity.Position.X,
0 + Entity.Position.Y,
j * GridSize + Entity.Position.X,
ySectors * GridSize + Entity.Position.Y,
GameConstants.SpaceUiColor);
if (i < ySectors && j < xSectors)
{
if (ZoneData.GetZone(j, i).IsCurvedX)
FillBox(batcher, j, i, Color.Purple);
if (ZoneData.GetZone(j, i).IsCurvedY)
FillBox(batcher, j, i, Color.Brown);
}
}
}
// color current zone
var scene = (SpaceScene) Entity.Scene;
FillBox(batcher, scene.CurrentZone.UniversalX, scene.CurrentZone.UniversalY, Color.White);
}
}
}

View File

@ -0,0 +1,36 @@
using Dakota.Data;
using Nez;
namespace Dakota.Space
{
public class NoFlyZone : RenderableComponent
{
public override float Width => 800;
public override float Height => 800;
private int _padding;
private RectangleF _innerRect;
private RectangleF _outerRect;
public NoFlyZone(int padding)
{
_padding = padding;
}
public override void OnAddedToEntity()
{
var scene = (SpaceScene) Entity.Scene;
_innerRect = new RectangleF(_padding, _padding, scene.CurrentZone.Width - _padding,
scene.CurrentZone.Height - _padding);
_outerRect = new RectangleF(_padding - 10, _padding - 10, scene.CurrentZone.Width - _padding + 20,
scene.CurrentZone.Height - _padding + 20);
}
public override void Render(Batcher batcher, Camera camera)
{
// terrible looking, what should this look like?
batcher.DrawHollowRect(_innerRect, GameConstants.NoFlyZoneColor);
batcher.DrawHollowRect(_outerRect, GameConstants.NoFlyZoneColor);
}
}
}

View File

@ -0,0 +1,159 @@
using System;
using Dakota.Data;
using Dakota.Renderables;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Nez;
using Nez.Particles;
namespace Dakota.Space
{
public enum ShipUpgrades
{
InertialThrusters, // reverse-thrust to create false feeling of inertia
HyperspaceStabilizer // reduce likelihood of hyperspace malfunction
}
public enum ShipWeapons
{
PhaseBlaster, // simple blaster
LaserBeam, // steady pulsed beam
RailGun // unstable spray
}
// one idea is to have these enter R&D and you can get an imperfect version that gets better as you use it
// if you're gonna have all these sweet upgrades, better have fun shit to fly near
public class PlayerShip : Component, IUpdatable, ITriggerListener
{
private VirtualButton _fireInput;
private VirtualButton _secondaryFireInput;
private VirtualIntegerAxis _rotateInput;
private VirtualButton _thrustInput;
private VirtualButton _warpInput;
private float _emitCounter;
private ParticleEmitter _emitter;
private ParticleEmitterConfig _emitterConfig;
private VectorSprite _booster;
private float _autothrustTime;
void ITriggerListener.OnTriggerEnter(Collider other, Collider self)
{
if (other.Entity.Name == "asteroid")
{
var scene = (SpaceScene) Entity.Scene;
scene.PlayerHit();
scene.HitAsteroid(other.Entity, self.Entity.Position);
}
}
void ITriggerListener.OnTriggerExit(Collider other, Collider self)
{
}
private bool ThrustOn => _thrustInput.IsDown || _autothrustTime > 0;
public void Thrust(float time)
{
_autothrustTime = time;
}
public void Update()
{
var obj = Entity.GetComponent<SpaceObject>();
if (_fireInput.IsPressed) ((SpaceScene) Entity.Scene).FirePrimary();
if (_warpInput.IsPressed) ((SpaceScene) Entity.Scene).Warp();
obj.SetAcceleration(ThrustOn ? GameConstants.ShipAcceleration : 0);
_booster.Enabled = ThrustOn;
if (ThrustOn)
_emitCounter += Time.DeltaTime;
while (_emitCounter > 0.01f)
{
_emitter.Emit(1);
_emitCounter -= 0.01f;
}
obj.TurnVelocity = _rotateInput.Value * GameConstants.ShipTurnSpeed;
_emitterConfig.Angle = MathHelper.ToDegrees(Entity.Rotation) + 90;
_emitter.LocalOffset = new Vector2(-16 * (float) Math.Sin(Entity.Rotation),
16 * (float) Math.Cos(Entity.Rotation));
}
public override void OnAddedToEntity()
{
Entity.AddComponent(new SpaceObject());
var shipPolygon = new[]
{
new Vector2(0, -16),
new Vector2(-16, 16),
new Vector2(0, 10),
new Vector2(16, 16)
};
Entity.AddComponent(new VectorSprite(shipPolygon, GameConstants.ShipColor));
var boostPoly = new[]
{
new Vector2(-16, 16),
new Vector2(-8, 24),
new Vector2(0, 12),
new Vector2(8, 24),
new Vector2(16, 16)
};
_booster = Entity.AddComponent(new VectorSprite(boostPoly, GameConstants.BoostColor));
SetupInput();
// don't need indent for collider, also need own copy
// since PolygonCollider modifies the array for rotations
var colliderPolygon = new[]
{
new Vector2(0, -16),
new Vector2(-16, 16),
new Vector2(16, 16)
};
Entity.AddComponent(new PolygonCollider(colliderPolygon)).IsTrigger = true;
var ec = new ParticleEmitterConfig();
ec.SourcePositionVariance = new Vector2(2, 2);
ec.Speed = 30;
ec.SpeedVariance = 1;
ec.ParticleLifespan = 3;
ec.ParticleLifespanVariance = 1;
ec.Angle = 180;
ec.AngleVariance = 0;
ec.StartColor = Color.Orange;
ec.FinishColor = Color.Transparent;
ec.StartParticleSize = 4;
ec.FinishParticleSize = 0;
ec.MaxParticles = 200;
ec.EmitterType = ParticleEmitterType.Gravity;
_emitterConfig = ec;
_emitter = Entity.AddComponent(new ParticleEmitter(ec));
_emitter.LocalOffset = new Vector2(0, 16);
}
private void SetupInput()
{
_fireInput = new VirtualButton();
_fireInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.Space));
_fireInput.SetRepeat(0.5f, 0.5f);
_secondaryFireInput = new VirtualButton();
_secondaryFireInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.LeftShift));
_thrustInput = new VirtualButton();
_thrustInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.Up));
_warpInput = new VirtualButton();
_warpInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.X));
_rotateInput = new VirtualIntegerAxis();
_rotateInput.Nodes.Add(new VirtualAxis.KeyboardKeys(VirtualInput.OverlapBehavior.TakeNewer, Keys.Left,
Keys.Right));
}
}
}

View File

@ -0,0 +1,71 @@
using Dakota.Data;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Space
{
public class Projectile : RenderableComponent, IUpdatable
{
private float _duration;
private bool _playerFired;
private ProjectileType _type;
private Vector2 _velocity;
public Projectile(ProjectileType type, bool playerFired, float duration)
{
_type = type;
_playerFired = playerFired;
_duration = duration;
}
public override float Width => 2;
public override float Height => 2;
public void Update()
{
_duration -= Time.DeltaTime;
if (_duration <= 0)
Entity.Destroy();
}
public override void OnAddedToEntity()
{
_velocity = Entity.GetComponent<SpaceObject>().Velocity;
Collider collider;
switch (_type)
{
case ProjectileType.Bullet:
collider = Entity.AddComponent(new CircleCollider(1));
break;
case ProjectileType.Beam:
collider = Entity.AddComponent(new PolygonCollider(new[]
{
new Vector2(0, 0),
_velocity * 2
}));
break;
default:
collider = Entity.AddComponent(new CircleCollider(1));
break;
}
collider.IsTrigger = true;
}
public override void Render(Batcher batcher, Camera camera)
{
var color = _playerFired ? GameConstants.FriendlyWeaponColor : GameConstants.HostileWeaponColor;
switch (_type)
{
case ProjectileType.Bullet:
batcher.DrawCircle(Entity.Position, 1, color);
break;
case ProjectileType.Beam:
batcher.DrawLine(Entity.Position, Entity.Position + _velocity * 2, color);
break;
}
}
}
}

View File

@ -0,0 +1,47 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Nez;
namespace Dakota.Space
{
public class SpaceControls : SceneComponent, IUpdatable
{
private VirtualButton _pauseInput;
private VirtualButton _debugInput;
public SpaceControls()
{
_pauseInput = new VirtualButton();
_pauseInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.P));
_debugInput = new VirtualButton();
_debugInput.Nodes.Add(new VirtualButton.KeyboardKey(Keys.A));
}
public override void Update()
{
if (Scene is SpaceScene ss)
{
if (_pauseInput.IsPressed) ss.TogglePause();
if (_debugInput.IsPressed)
{
// horizontal
//ss.AddAsteroid(new Vector2(400, 400), AsteroidSize.LARGE, new Vector2(100, 0));
//ss.AddAsteroid(new Vector2(900, 400), AsteroidSize.LARGE, new Vector2(-100, 0));
// vertical
//ss.AddAsteroid(new Vector2(400, 0), AsteroidSize.LARGE, new Vector2(0, 100));
//ss.AddAsteroid(new Vector2(400, 900), AsteroidSize.LARGE, new Vector2(0, -100));
ss.AddAsteroid(new Vector2(0, 0), AsteroidSize.LARGE, new Vector2(100, 100));
//ss.AddAsteroid(new Vector2(300, 300), AsteroidSize.LARGE, new Vector2(100, 100));
ss.AddAsteroid(new Vector2(300, 0), AsteroidSize.LARGE, new Vector2(-100, 100));
//ss.AsteroidEmitter.Emit();
}
}
}
}
}

View File

@ -0,0 +1,96 @@
using Dakota.Data;
using Dakota.Renderables;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Space
{
public class SpaceHud : RenderableComponent, IUpdatable
{
private const int FrameSize = 30;
private VectorText _acceleration;
private VectorText _primary;
private VectorText _spaceCoords;
private VectorText _velocity;
private VectorText _objective;
private VectorText _zoneCoords;
public override float Width => 280;
public override float Height => 720;
public void Update()
{
var scene = (SpaceScene) Entity.Scene;
var obj = scene.Player.GetComponent<SpaceObject>();
_primary.Text = scene.Primary.Name;
_objective.Text = scene.CurrentMission.GetMissionStatus();
_zoneCoords.Text = $"Z: {scene.CurrentZone.UniversalX} {scene.CurrentZone.UniversalY}";
_spaceCoords.Text = $"P: {scene.Player.Position.X:0} {scene.Player.Position.Y:0}";
_velocity.Text = $"V: {obj.Velocity.X:0} {obj.Velocity.Y:0}";
_acceleration.Text = $"A: {obj.Acceleration.X:0} {obj.Acceleration.Y:0}";
}
public override void OnAddedToEntity()
{
RenderLayer = GameConstants.UiRenderLayerBg;
var map = Entity.AddComponent(new SpaceHudMap());
map.LocalOffset = new Vector2(40, 500);
map.RenderLayer = GameConstants.UiRenderLayerBg;
var line = Entity.AddComponent(new VectorText("PRIMARY", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 40);
_primary = line = Entity.AddComponent(new VectorText("", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 60);
line = Entity.AddComponent(new VectorText("SECONDARY", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 100);
line = Entity.AddComponent(new VectorText("SMART BOMB", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 120);
line = Entity.AddComponent(new VectorText("WARP CORE", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 200);
line = Entity.AddComponent(new VectorText("DISABLED", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 220);
line = Entity.AddComponent(new VectorText("OBJECTIVE", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 250);
_objective = line = Entity.AddComponent(new VectorText("", 6, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 270);
line = Entity.AddComponent(new VectorText("COORDINATES", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 350);
_zoneCoords = line = Entity.AddComponent(new VectorText("", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 370);
_spaceCoords = line = Entity.AddComponent(new VectorText("", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 390);
_velocity = line = Entity.AddComponent(new VectorText("", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 410);
_acceleration = line = Entity.AddComponent(new VectorText("", 12, GameConstants.SpaceHudFontColor));
line.LocalOffset = new Vector2(40, 430);
}
public override void Render(Batcher batcher, Camera camera)
{
batcher.DrawRect(Entity.Position, Width, Height, GameConstants.ColorBlack);
batcher.DrawHollowRect(Entity.Position, Width, Height, GameConstants.SpaceUiColor);
batcher.DrawHollowRect(
Entity.Position + new Vector2(FrameSize, FrameSize),
Width - FrameSize * 2, Height - FrameSize * 2,
GameConstants.SpaceUiColor);
batcher.DrawLine(
Entity.Position,
Entity.Position + new Vector2(FrameSize, FrameSize),
GameConstants.SpaceUiColor);
batcher.DrawLine(
Entity.Position + new Vector2(0, Height),
Entity.Position + new Vector2(FrameSize, Height - FrameSize),
GameConstants.SpaceUiColor);
batcher.DrawLine(
Entity.Position + new Vector2(Width, Height),
Entity.Position + new Vector2(Width - FrameSize, Height - FrameSize),
GameConstants.SpaceUiColor);
batcher.DrawLine(
Entity.Position + new Vector2(Width, 0),
Entity.Position + new Vector2(Width - FrameSize, FrameSize),
GameConstants.SpaceUiColor);
}
}
}

View File

@ -0,0 +1,79 @@
using System.Reflection;
using Dakota.Data;
using Nez;
namespace Dakota.Space
{
public class SpaceHudMap : RenderableComponent, IUpdatable
{
private const int Regions = 5;
private int[,] _regionCount;
private int _playerRegionX;
private int _playerRegionY;
public override float Width => 100;
public override float Height => 100;
// Rudimentary
// System Scanner
// System Scanner+
public void Update()
{
var scene = (SpaceScene) Entity.Scene;
_regionCount = new int[Regions, Regions];
var xDiv = scene.CurrentZone.Width / Regions;
var yDiv = scene.CurrentZone.Height / Regions;
_playerRegionX = (int) (scene.Player.Position.X / xDiv);
_playerRegionY = (int) (scene.Player.Position.Y / yDiv);
// reset asteroid counts
for (var i = 0; i < Regions; i++)
for (var j = 0; j < Regions; j++)
_regionCount[i, j] = 0;
// count asteroids
foreach (var asteroid in scene.FindComponentsOfType<Asteroid>())
{
var x = (int) (asteroid.Entity.Position.X / xDiv);
var y = (int) (asteroid.Entity.Position.Y / yDiv);
if (x < 0 || x >= Regions || y < 0 || y >= Regions)
continue;
_regionCount[x, y] += 1;
}
}
public override void Render(Batcher batcher, Camera camera)
{
var unitSize = (Height - 1) / Regions;
batcher.DrawHollowRect(Entity.Position.X + LocalOffset.X,
Entity.Position.Y + LocalOffset.Y,
Width,
Height,
GameConstants.SpaceHudFontColor);
for (var i = 0; i < Regions; i++)
for (var j = 0; j < Regions; j++)
{
var color = GameConstants.ColorBlack;
if (_regionCount[i, j] >= 1)
color = GameConstants.AsteroidColor;
batcher.DrawRect(
Entity.Position.X + LocalOffset.X + unitSize * i,
Entity.Position.Y + LocalOffset.Y + unitSize * j,
unitSize,
unitSize,
color);
}
batcher.DrawRect(
Entity.Position.X + LocalOffset.X + unitSize * _playerRegionX + 5,
Entity.Position.Y + LocalOffset.Y + unitSize * _playerRegionY + 5,
unitSize - 10,
unitSize - 10,
GameConstants.ShipColor);
}
}
}

View File

@ -0,0 +1,77 @@
using System;
using Dakota.Utils;
using Microsoft.Xna.Framework;
using Nez;
namespace Dakota.Space
{
public class SpaceObject : Component, IUpdatable
{
private Mover _mover;
public float TurnVelocity;
public Vector2 Velocity;
public Vector2 Acceleration;
public SpaceObject()
{
Velocity = new Vector2(0, 0);
Acceleration = new Vector2(0, 0);
}
public void Update()
{
var scene = (SpaceScene) Entity.Scene;
Entity.Rotation += Time.DeltaTime * TurnVelocity;
Velocity += Time.DeltaTime * Acceleration;
_mover.Move(
Time.DeltaTime * Velocity + 0.5f * Time.DeltaTime * Time.DeltaTime * Acceleration,
out _
);
// enforce zone boundaries
var newPos = Entity.Position;
if (Entity.Position.X < 0)
{
if (scene.CurrentZone.IsCurvedX)
newPos.X += scene.CurrentZone.Width;
else if (Entity.Name == "player")
newPos = scene.ZoneShift(-1, 0);
}
else if (Entity.Position.X > scene.CurrentZone.Width)
{
if (scene.CurrentZone.IsCurvedX)
newPos.X -= scene.CurrentZone.Width;
else if (Entity.Name == "player")
newPos = scene.ZoneShift(1, 0);
}
if (Entity.Position.Y < 0)
{
if (scene.CurrentZone.IsCurvedY)
newPos.Y += scene.CurrentZone.Height;
else if (Entity.Name == "player")
newPos = scene.ZoneShift(0, -1);
}
else if (Entity.Position.Y > scene.CurrentZone.Height)
{
if (scene.CurrentZone.IsCurvedY)
newPos.Y -= scene.CurrentZone.Height;
else if (Entity.Name == "player")
newPos = scene.ZoneShift(0, 1);
}
Entity.Position = newPos;
}
public override void OnAddedToEntity()
{
_mover = Entity.AddComponent(new Mover());
}
public void SetAcceleration(float accel)
{
Acceleration = accel * DakotaUtils.VecFromAngle(Entity.Rotation);
}
}
}

View File

@ -0,0 +1,226 @@
using System;
using Dakota.Data;
using Dakota.Missions;
using Dakota.Renderables;
using Dakota.Utils;
using Microsoft.Xna.Framework;
using Nez;
using Nez.Particles;
using Random = Nez.Random;
namespace Dakota.Space
{
internal enum GameMode
{
Active,
Paused
}
public class SpaceScene : Scene
{
private const int HudWidth = 280;
private const int PauseFreezeTag = 100;
// entities
private Entity _galacticMap;
public Entity Player;
public DialogBox DialogBox;
public TimedVectorText CenterText { get; }
public BaddieEmitter AsteroidEmitter;
// game data
private GameMode _mode;
public SpaceMission CurrentMission;
public Zone CurrentZone;
public PrimaryWeapon Primary;
public SpaceScene()
{
// set up screen & camera
SetDesignResolution(1280, 720, SceneResolutionPolicy.ShowAllPixelPerfect);
Screen.SetSize(1280, 720);
ClearColor = GameConstants.ColorBlack;
// render background, then everything else, then UI layers
AddRenderer(new ScreenSpaceRenderer(0, GameConstants.BackgroundRenderLayer));
AddRenderer(new RenderLayerExcludeRenderer(10, GameConstants.UiRenderLayerBg,
GameConstants.BackgroundRenderLayer, GameConstants.UiRenderLayerFg));
AddRenderer(new ScreenSpaceRenderer(100, GameConstants.UiRenderLayerBg, GameConstants.UiRenderLayerFg));
Core.ExitOnEscapeKeypress = false;
if (Environment.GetEnvironmentVariable("DEBUG_RENDERING") != null)
Core.DebugRenderEnabled = true;
// create player and focus camera
Player = CreateEntity("player");
Player.SetTag(PauseFreezeTag);
Player.AddComponent(new PlayerShip());
var follow = Camera.Entity.AddComponent(new FollowCamera(Player));
follow.FocusOffset = new Vector2(-100, 0);
AddSceneComponent(new SpaceControls());
AsteroidEmitter = AddSceneComponent(new BaddieEmitter());
var starField = CreateEntity("StarField").AddComponent(new StarField());
starField.RenderLayer = GameConstants.BackgroundRenderLayer;
_galacticMap = CreateEntity("GalacticMap", new Vector2(10, 10));
_galacticMap.AddComponent<GalacticMap>();
// create UI
var hud = CreateEntity("HUD");
hud.Position = new Vector2(Screen.Width - HudWidth, 0);
hud.AddComponent(new SpaceHud());
DialogBox = CreateEntity("dialog box", new Vector2(1, Screen.Height - 100))
.AddComponent(new DialogBox());
CenterText = CreateEntity("center text", new Vector2(300, 300))
.AddComponent(new TimedVectorText(20, GameConstants.SpaceHudFontColor));
CurrentMission = new Mission1();
AddSceneComponent(CurrentMission);
CurrentMission.OnStart();
_mode = GameMode.Paused;
TogglePause();
}
public void TogglePause()
{
if (_mode == GameMode.Active)
{
_mode = GameMode.Paused;
_galacticMap.Enabled = true;
foreach (var e in FindEntitiesWithTag(PauseFreezeTag))
e.Enabled = false;
}
else
{
_mode = GameMode.Active;
_galacticMap.Enabled = false;
foreach (var e in FindEntitiesWithTag(PauseFreezeTag))
e.Enabled = true;
}
}
public void PlayerHit()
{
CurrentMission.OnPlayerHit();
}
public void PlayerWarpTo(Vector2 pos)
{
Player.Position = pos;
Camera.Position = Player.Position - Camera.Entity.GetComponent<FollowCamera>().FocusOffset;
}
public Vector2 ZoneShift(int xShift, int yShift)
{
if (CurrentMission.ZoneShiftDisabled)
return Player.Position;
var newZone = ZoneData.GetZone(
CurrentZone.UniversalX + xShift,
CurrentZone.UniversalY + yShift
);
var newPos = Player.Position;
// wrap around or scale to new area (so middle = middle)
newPos.X = xShift switch
{
-1 => newZone.Width,
1 => 0,
_ => newPos.X / CurrentZone.Width * newZone.Width
};
newPos.Y = yShift switch
{
-1 => newZone.Height,
1 => 0,
_ => newPos.Y / CurrentZone.Height * newZone.Height
};
CurrentZone = newZone;
return newPos;
}
public Entity AddAsteroid(Vector2 position, AsteroidSize size, Vector2? velocity = null)
{
var asteroid = CreateEntity("asteroid", position);
asteroid.SetTag(PauseFreezeTag);
asteroid.AddComponent(new Asteroid(size));
var so = asteroid.AddComponent(new SpaceObject());
so.TurnVelocity = Random.MinusOneToOne() * 3;
so.Velocity = velocity ?? Random.NextUnitVector() * 20;
return asteroid;
}
public void HitAsteroid(Entity asteroid, Vector2 hitLocation)
{
var cur = asteroid.GetComponent<Asteroid>();
var angle = DakotaUtils.ToAngle(asteroid.Position - hitLocation) + (float) Math.PI;
// ~ 135 degrees
var angle1 = DakotaUtils.VecFromAngle(angle - 2.4f) * 50;
var angle2 = DakotaUtils.VecFromAngle(angle + 2.4f) * 50;
switch (cur.Size)
{
case AsteroidSize.HUGE:
AddAsteroid(asteroid.Position, AsteroidSize.LARGE, angle1);
AddAsteroid(asteroid.Position + angle2, AsteroidSize.LARGE, angle2);
break;
case AsteroidSize.LARGE:
AddAsteroid(asteroid.Position, AsteroidSize.MEDIUM, angle1);
AddAsteroid(asteroid.Position + angle2, AsteroidSize.MEDIUM, angle2);
break;
case AsteroidSize.MEDIUM:
AddAsteroid(asteroid.Position, AsteroidSize.SMALL, angle1);
AddAsteroid(asteroid.Position + angle2, AsteroidSize.SMALL, angle2);
break;
case AsteroidSize.SMALL:
break;
default:
throw new ArgumentOutOfRangeException();
}
var ec = new ParticleEmitterConfig();
ec.SourcePositionVariance = new Vector2(cur.Radius(), cur.Radius());
ec.Speed = 30;
ec.SpeedVariance = 1;
ec.ParticleLifespan = 10;
ec.ParticleLifespanVariance = 1;
ec.Angle = 90;
ec.AngleVariance = 360;
ec.StartColor = GameConstants.AsteroidColor;
ec.FinishColor = Color.Transparent;
ec.StartParticleSize = 4;
ec.FinishParticleSize = 0;
ec.MaxParticles = 200;
ec.EmitterType = ParticleEmitterType.Gravity;
var ee = CreateEntity("dust emitter");
ee.Position = asteroid.Position;
ee.AddComponent(new ParticleEmitter(ec)).Emit(100);
// TODO: ensure this gets removed?
asteroid.Destroy();
CurrentMission.OnAsteroidDestroyed(cur.Size);
}
public void FirePrimary()
{
var playerHeading = DakotaUtils.VecFromAngle(Player.Rotation);
var bullet = CreateEntity("bullet", Player.Position + playerHeading * 20);
bullet.SetTag(PauseFreezeTag);
bullet.AddComponent(new Projectile(Primary.Projectile, true, Primary.Duration));
var so = bullet.AddComponent(new SpaceObject());
so.Velocity = playerHeading * Primary.Speed;
if (Primary.Projectile != ProjectileType.Beam)
so.Velocity += Player.GetComponent<SpaceObject>().Velocity;
}
public void Warp()
{
// TODO
}
}
}

View File

@ -0,0 +1,46 @@
using Microsoft.Xna.Framework;
using Nez;
using Random = Nez.Random;
namespace Dakota.Space
{
public class Star
{
public Vector2 Position;
public Color StarColor;
public Star()
{
Position = new Vector2(Random.NextFloat() * 2, Random.NextFloat() * 2);
var intensity = Random.NextFloat(0.5f) + 0.7f;
StarColor = new Color(intensity, intensity, intensity);
}
}
public class StarField : RenderableComponent
{
private readonly Star[] _stars;
public override float Width => 1000;
public override float Height => 720;
public StarField()
{
_stars = new Star[500];
for (int i = 0; i < _stars.Length; i++)
_stars[i] = new Star();
}
public override void Render(Batcher batcher, Camera camera)
{
var pos = ((SpaceScene) (Entity.Scene)).Player.Position;
// TODO: scale by zone size
pos /= 3000;
// TODO: consider more parallax
foreach (var star in _stars)
{
batcher.DrawPixel((star.Position.X - pos.X) * Width, (star.Position.Y - pos.Y) * Height, star.StarColor);
}
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using Microsoft.Xna.Framework;
namespace Dakota.Utils
{
public static class DakotaUtils
{
public static float ToAngle(Vector2 v)
{
return (float) Math.Atan2(v.Y, v.X) + (float) (Math.PI / 2);
}
public static Vector2 VecFromAngle(float angle)
{
return new Vector2((float) Math.Sin(angle), (float) -Math.Cos(angle));
}
}
}

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Dakota"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor
</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="NUnit" Version="3.13.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dakota\Dakota.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,48 @@
using System;
using Dakota.Utils;
using Microsoft.Xna.Framework;
using NUnit.Framework;
namespace DakotaTests
{
public class DakotaUtilTests
{
[SetUp]
public void Setup()
{
}
private Vector2 UpVector = new(0, -1);
private Vector2 RightVector = new(1, 0);
private Vector2 DownVector = new(0, 1);
private Vector2 LeftVector = new(-1, 0);
private const float Epsilon = 0.00001f;
private const float UpAngle = 0f;
private const float RightAngle = (float) Math.PI / 2f;
private const float DownAngle = (float) Math.PI;
private const float LeftAngle = (float) Math.PI * 1.5f;
[Test]
public void TestToAngle()
{
// going around the clock
Assert.AreEqual(UpAngle, DakotaUtils.ToAngle(UpVector));
Assert.AreEqual(RightAngle, DakotaUtils.ToAngle(RightVector));
Assert.AreEqual(DownAngle, DakotaUtils.ToAngle(DownVector));
Assert.AreEqual(LeftAngle, DakotaUtils.ToAngle(LeftVector));
}
[Test]
public void TestFromAngle()
{
Assert.AreEqual(UpVector.X, DakotaUtils.VecFromAngle(UpAngle).X, Epsilon);
Assert.AreEqual(UpVector.Y, DakotaUtils.VecFromAngle(UpAngle).Y, Epsilon);
Assert.AreEqual(RightVector.X, DakotaUtils.VecFromAngle(RightAngle).X, Epsilon);
Assert.AreEqual(RightVector.Y, DakotaUtils.VecFromAngle(RightAngle).Y, Epsilon);
Assert.AreEqual(DownVector.X, DakotaUtils.VecFromAngle(DownAngle).X, Epsilon);
Assert.AreEqual(DownVector.Y, DakotaUtils.VecFromAngle(DownAngle).Y, Epsilon);
Assert.AreEqual(LeftVector.X, DakotaUtils.VecFromAngle(LeftAngle).X, Epsilon);
Assert.AreEqual(LeftVector.Y, DakotaUtils.VecFromAngle(LeftAngle).Y, Epsilon);
}
}
}

Binary file not shown.

5
Inky/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

3
Inky/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Nez"]
path = Nez
url = git@github.com:prime31/Nez.git

11
Inky/.idea/.idea.Inky/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,11 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/modules.xml
/.idea.Inky.iml
/contentModel.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
Inky/.idea/.idea.Inky/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

22
Inky/Inky.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inky", "Inky\Inky.csproj", "{807420D8-9B51-4BB4-9C79-B07CF1FB27A4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.MG38", "Nez\Nez.Portable\Nez.MG38.csproj", "{4DEC583E-A7C7-4671-B977-EA999AE58C50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{807420D8-9B51-4BB4-9C79-B07CF1FB27A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{807420D8-9B51-4BB4-9C79-B07CF1FB27A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{807420D8-9B51-4BB4-9C79-B07CF1FB27A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{807420D8-9B51-4BB4-9C79-B07CF1FB27A4}.Release|Any CPU.Build.0 = Release|Any CPU
{4DEC583E-A7C7-4671-B977-EA999AE58C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DEC583E-A7C7-4671-B977-EA999AE58C50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DEC583E-A7C7-4671-B977-EA999AE58C50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DEC583E-A7C7-4671-B977-EA999AE58C50}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,15 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#

48
Inky/Inky/DemoControls.cs Normal file
View File

@ -0,0 +1,48 @@
using Microsoft.Xna.Framework.Input;
using Nez;
namespace Inky
{
public class DemoControls : SceneComponent, IUpdatable
{
private VirtualButton _left;
private VirtualButton _right;
private float _eyeDirection = 1;
public DemoControls()
{
_left = new VirtualButton();
_left.Nodes.Add(new VirtualButton.KeyboardKey(Keys.Left));
_right = new VirtualButton();
_right.Nodes.Add(new VirtualButton.KeyboardKey(Keys.Right));
}
public override void Update()
{
var lanky = Scene.Entities.FindEntity("inky").GetComponent<Lanky>();
if (_left.IsDown)
{
lanky.LegAlignment = Alignment.Left;
lanky.ArmAlignment = Alignment.Left;
lanky.HeadShift -= 1f * Time.DeltaTime;
}
else if (_right.IsDown)
{
lanky.LegAlignment = Alignment.Right;
lanky.ArmAlignment = Alignment.Right;
lanky.HeadShift += 1f * Time.DeltaTime;
}
else
{
lanky.EyeShift += _eyeDirection * Time.DeltaTime;
if (lanky.EyeShift < -0.99) _eyeDirection = 1;
else if (lanky.EyeShift > 0.99) _eyeDirection = -1;
lanky.MouthShift += _eyeDirection * Time.DeltaTime;
lanky.LegWobble += _eyeDirection * Time.DeltaTime;
lanky.LegAlignment = Alignment.Center;
lanky.ArmAlignment = Alignment.Center;
}
}
}
}

13
Inky/Inky/Game1.cs Normal file
View File

@ -0,0 +1,13 @@
using Nez;
namespace Inky
{
public class Game1 : Core
{
protected override void Initialize()
{
base.Initialize();
Scene = new InkyScene();
}
}
}

View File

@ -0,0 +1,11 @@
using Microsoft.Xna.Framework;
namespace Inky
{
public class GameConstants
{
public const int UiRenderLayerBg = 910;
public const int UiRenderLayerFg = 900;
public const int BackgroundRenderLayer = 50;
}
}

BIN
Inky/Inky/Icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
Inky/Inky/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

33
Inky/Inky/Inky.csproj Normal file
View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="Content\Content.mgcb" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nez\Nez.Portable\Nez.MG38.csproj" />
</ItemGroup>
</Project>

36
Inky/Inky/InkyScene.cs Normal file
View File

@ -0,0 +1,36 @@
using System;
using Microsoft.Xna.Framework;
using Nez;
namespace Inky
{
public class InkyScene : Scene
{
public InkyScene()
{
// set up screen & camera
SetDesignResolution(1280, 720, SceneResolutionPolicy.ShowAllPixelPerfect);
Screen.SetSize(1280, 720);
ClearColor = Color.White;
// render background, then everything else, then UI layers
AddRenderer(new ScreenSpaceRenderer(0, GameConstants.BackgroundRenderLayer));
AddRenderer(new RenderLayerExcludeRenderer(10, GameConstants.UiRenderLayerBg,
GameConstants.BackgroundRenderLayer, GameConstants.UiRenderLayerFg));
AddRenderer(new ScreenSpaceRenderer(100, GameConstants.UiRenderLayerBg, GameConstants.UiRenderLayerFg));
Core.ExitOnEscapeKeypress = false;
if (Environment.GetEnvironmentVariable("DEBUG_RENDERING") != null)
Core.DebugRenderEnabled = true;
var inky1 = CreateEntity("inky");
inky1.AddComponent<Lanky>().Color = Color.Black;
inky1.Position = new Vector2(300, 300);
var worm = CreateEntity("worm");
//worm.AddComponent<Skeletron.Skeletron>().Color = Color.Black;
worm.AddComponent<Lanky2>();
worm.Position = new Vector2(600, 400);
AddSceneComponent<DemoControls>();
}
}
}

156
Inky/Inky/Lanky.cs Normal file
View File

@ -0,0 +1,156 @@
using System;
using Nez;
using Random = Nez.Random;
namespace Inky
{
public enum Alignment
{
Left,
Right,
Center
}
public class Lanky : RenderableComponent
{
public override float Height => BodyHeight + HeadHeight + LegLength;
public override float Width => BodyWidth;
public readonly int LegLength;
public readonly int ArmLength;
public readonly int BodyWidth;
public readonly int BodyHeight;
public readonly int HeadWidth;
public readonly int HeadHeight;
public Alignment LegAlignment;
public Alignment ArmAlignment;
private float _headShift;
public float HeadShift
{
get => _headShift;
set => _headShift = Math.Clamp(value, -1, 1);
}
private float _eyeShift;
public float EyeShift
{
get => _eyeShift;
set => _eyeShift = Math.Clamp(value, -1, 1);
}
private float _mouthShift;
public float MouthShift
{
get => _mouthShift;
set => _mouthShift = Math.Clamp(value, -1, 1);
}
private float _mouthWidth;
public float MouthWidth
{
get => _mouthWidth;
set => _mouthWidth = Math.Clamp(value, 0, 1);
}
private float _legWobble;
public float LegWobble
{
get => _legWobble;
set => _legWobble = Math.Clamp(value, -1, 1);
}
public Lanky()
{
// readonly
BodyHeight = 100;
LegLength = (int)((Random.NextFloat(0.6f) + 0.6f) * BodyHeight);
ArmLength = (int)((Random.NextFloat(0.3f) + 0.3f) * BodyHeight);
BodyWidth = (int)((Random.NextFloat(0.5f) + 0.5f) * BodyHeight);
HeadWidth = 40;
HeadHeight = 40;
LegAlignment = Alignment.Center;
ArmAlignment = Alignment.Center;
MouthWidth = 0.5f;
}
public override void Render(Batcher batcher, Camera camera)
{
var thickness = 3f;
// body
batcher.DrawHollowRect(
Entity.Position.X - BodyWidth/2f,
Entity.Position.Y - BodyHeight/2f,
BodyWidth, BodyHeight, Color, thickness
);
// legs
var legInset = BodyWidth * 0.15f;
var legBodyY = Entity.Position.Y + BodyHeight / 2f;
// center positions
var leftLegX = Entity.Position.X - BodyWidth / 2f + legInset;
var rightLegX = Entity.Position.X + BodyWidth / 2f - legInset;
if (LegAlignment == Alignment.Left)
rightLegX = leftLegX + legInset;
else if (LegAlignment == Alignment.Right)
leftLegX = rightLegX - legInset;
var leftWobble = LegWobble * LegLength * 0.1f;
var rightWobble = -LegWobble * LegLength * 0.1f;
batcher.DrawLine(leftLegX, legBodyY, leftLegX, legBodyY + LegLength + leftWobble, Color);
batcher.DrawLine(rightLegX, legBodyY, rightLegX, legBodyY + LegLength + rightWobble, Color);
// arms
var armShift = 10;
var armY = Entity.Position.Y - BodyHeight / 2f + armShift;
float leftArmX = 0;
float rightArmX = 0;
switch (ArmAlignment)
{
case Alignment.Left:
leftArmX = Entity.Position.X - BodyWidth / 2f + armShift;
rightArmX = leftArmX + armShift;
break;
case Alignment.Right:
leftArmX = Entity.Position.X + BodyWidth / 2f - armShift * 2;
rightArmX = leftArmX + armShift;
break;
case Alignment.Center:
leftArmX = Entity.Position.X - armShift * 2;
rightArmX = Entity.Position.X + armShift * 2;
break;
}
batcher.DrawLine(leftArmX, armY, leftArmX, armY + ArmLength, Color);
batcher.DrawLine(rightArmX, armY, rightArmX, armY + ArmLength, Color);
// head
var headX = Entity.Position.X + (BodyWidth / 2f) * HeadShift - HeadWidth/2f;
var headY = Entity.Position.Y - BodyHeight / 2f - HeadHeight;
batcher.DrawHollowRect(
headX,
Entity.Position.Y - BodyHeight/2f - HeadHeight,
HeadWidth, HeadHeight, Color, thickness
);
var eyeInset = EyeShift * (HeadWidth * 0.3f);
var eyeSpace = HeadWidth * 0.15f;
var eyeWidth = 2;
batcher.DrawHollowRect(headX + HeadWidth/2f + eyeInset - eyeSpace - eyeWidth, headY + eyeSpace, eyeWidth, eyeWidth, Color, thickness);
batcher.DrawHollowRect(headX + HeadWidth/2f + eyeInset + eyeSpace - eyeWidth, headY + eyeSpace, eyeWidth, eyeWidth, Color, thickness);
var mouthCenterX = HeadWidth / 2f + MouthShift * HeadWidth / 2f;
var halfMouth = (HeadWidth * MouthWidth) / 2f;
batcher.DrawLine(
Math.Max(headX + mouthCenterX - halfMouth, headX),
headY + HeadHeight * 0.8f ,
Math.Min(headX + mouthCenterX + halfMouth, headX + HeadWidth),
headY + HeadHeight * 0.8f ,
Color
);
}
}
}

89
Inky/Inky/Lanky2.cs Normal file
View File

@ -0,0 +1,89 @@
using System;
using Inky.Skeletron;
using Microsoft.Xna.Framework;
using Nez;
using Edge = Inky.Skeletron.Edge;
using Random = Nez.Random;
namespace Inky
{
public class Lanky2 : RenderableComponent
{
public override float Height => 100;
public override float Width => 100;
public readonly int LegLength;
public readonly int ArmLength;
public readonly int BodyWidth;
public readonly int BodyHeight;
public readonly int HeadWidth;
public readonly int HeadHeight;
public Alignment LegAlignment;
public Alignment ArmAlignment;
private float _headShift;
public float HeadShift
{
get => _headShift;
set => _headShift = Math.Clamp(value, -1, 1);
}
private float _eyeShift;
public float EyeShift
{
get => _eyeShift;
set => _eyeShift = Math.Clamp(value, -1, 1);
}
private float _mouthShift;
public float MouthShift
{
get => _mouthShift;
set => _mouthShift = Math.Clamp(value, -1, 1);
}
private float _mouthWidth;
public float MouthWidth
{
get => _mouthWidth;
set => _mouthWidth = Math.Clamp(value, 0, 1);
}
private float _legWobble;
public float LegWobble
{
get => _legWobble;
set => _legWobble = Math.Clamp(value, -1, 1);
}
public Skeletron.Rectangle _body;
public Lanky2()
{
BodyHeight = (int) ((Random.NextFloat(0.5f) + 0.5f) * 100);
_body = new Skeletron.Rectangle(100, BodyHeight);
var _head = new Skeletron.Rectangle(40, 40);
_body.Attach(Edge.Top, _head);
// readonly
LegLength = (int)((Random.NextFloat(0.6f) + 0.6f) * BodyHeight);
_body.Attach(Edge.Bottom, new Line(LegLength, true), 0.4f);
_body.Attach(Edge.Bottom, new Line(LegLength, true), -0.4f);
ArmLength = (int)((Random.NextFloat(0.3f) + 0.3f) * BodyHeight);
_body.Attach(Edge.Left, new Line(ArmLength, true), 0.4f);
_body.Attach(Edge.Right, new Line(ArmLength, true), -0.4f);
LegAlignment = Alignment.Center;
ArmAlignment = Alignment.Center;
MouthWidth = 0.5f;
}
public override void Render(Batcher batcher, Camera camera)
{
_body.Draw(batcher, Entity.Position.X, Entity.Position.Y, Color.Black);
}
}
}

14
Inky/Inky/Program.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
namespace Inky
{
public static class Program
{
[STAThread]
static void Main()
{
using (var game = new Game1())
game.Run();
}
}
}

View File

@ -0,0 +1,7 @@
namespace Inky.Skeletron
{
public class Head
{
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.Xna.Framework;
using Nez;
namespace Inky.Skeletron
{
public class Line : Shape
{
public override int HalfHeight => IsVertical ? Length / 2 : 1;
public override int HalfWidth => IsVertical ? 1 : Length / 2;
public int Length;
public bool IsVertical;
public Line(int length, bool isVertical)
{
Length = length;
IsVertical = true;
}
public override void Draw(Batcher batcher, float x, float y, Color color)
{
if(IsVertical)
batcher.DrawLine(x, y-Length/2f, x, y+Length/2f, color);
else
batcher.DrawLine(x-Length/2f, y, x+Length/2f, y, color);
DrawChildren(batcher, x, y, Color.Black);
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.Xna.Framework;
using Nez;
namespace Inky.Skeletron
{
public class Rectangle : Shape
{
public override int HalfHeight => Height/2;
public override int HalfWidth => Width/2;
public int Width;
public int Height;
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
public override void Draw(Batcher batcher, float x, float y, Color color)
{
batcher.DrawHollowRect(x - Width/2f,y - Height/2f, Width, Height, color, 2f);
DrawChildren(batcher, x, y, Color.Black);
}
}
}

View File

@ -0,0 +1,70 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Nez;
namespace Inky.Skeletron
{
public enum Edge
{
Top,
Bottom,
Left,
Right
}
public class EdgeAttachment
{
public Edge OnEdge;
public float XOffset;
public float YOffset;
public Shape Shape;
}
public abstract class Shape
{
public abstract int HalfHeight { get; }
public abstract int HalfWidth { get; }
private List<EdgeAttachment> _attachments;
protected Shape()
{
_attachments = new List<EdgeAttachment>();
}
public abstract void Draw(Batcher batcher, float x, float y, Color color);
public EdgeAttachment Attach(Edge on, Shape shape, float xOffset = 0, float yOffset = 0)
{
var ea = new EdgeAttachment() { OnEdge = on, Shape = shape, XOffset = xOffset, YOffset = yOffset};
_attachments.Add(ea);
return ea;
}
protected void DrawChildren(Batcher batcher, float x, float y, Color color)
{
foreach (var att in _attachments)
{
var childX = x;
var childY = y;
switch (att.OnEdge)
{
case Edge.Top:
childY -= att.Shape.HalfHeight + HalfHeight;
break;
case Edge.Bottom:
childY += att.Shape.HalfHeight + HalfHeight;
break;
case Edge.Left:
childX -= att.Shape.HalfWidth + HalfWidth;
break;
case Edge.Right:
childX += att.Shape.HalfWidth + HalfWidth;
break;
}
att.Shape.Draw(batcher, childX + att.XOffset * HalfWidth, childY + att.YOffset * HalfHeight, color);
}
}
}
}

View File

@ -0,0 +1,37 @@
using Microsoft.Xna.Framework;
using Nez;
namespace Inky.Skeletron
{
public class Skeletron : RenderableComponent, IUpdatable
{
public override float Height => 100;
public override float Width => 100;
public Shape _body;
private EdgeAttachment _neckJoint;
public Skeletron()
{
_body = new Rectangle(80, 200);
(_body as Rectangle).Attach(Edge.Left, new Rectangle(30, 10));
(_body as Rectangle).Attach(Edge.Right, new Rectangle(60, 10));
(_body as Rectangle).Attach(Edge.Right, new Rectangle(60, 10), 0, 0.3f);
var head = new Rectangle(80, 80);
head.Attach(Edge.Top, new Rectangle(100, 5), 0, 0);
_neckJoint = (_body as Rectangle).Attach(Edge.Top, head, -1, 0);
(_body as Rectangle).Attach(Edge.Bottom, new Line(40, true), -0.5f, 0);
(_body as Rectangle).Attach(Edge.Bottom, new Line(40, true), 0.5f, 0);
}
public void Update()
{
_neckJoint.XOffset += Time.DeltaTime;
}
public override void Render(Batcher batcher, Camera camera)
{
_body.Draw(batcher, Entity.Position.X, Entity.Position.Y, Color.Black);
}
}
}

43
Inky/Inky/app.manifest Normal file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Inky"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

20
Inky/newproj.txt Normal file
View File

@ -0,0 +1,20 @@
- new monogame cross platform
- add Nez as submodule
git submodule add git@github.com:prime31/Nez.git Nez
- SLN -> add existing projeectt -> Nez.Portable.MG38
- Proj -> add reference -> Nez
- change Game1.cs to
using Nez;
namespace Dakota
{
public class Game1 : Core
{
protected override void Initialize()
{
base.Initialize();
Scene = new SomeScene();
}
}
}

5
UPWG/.gitignore vendored Executable file
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

BIN
UPWG/Content/jason.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

39
UPWG/Data/moves.csv Executable file
View File

@ -0,0 +1,39 @@
Name,Type,Rank,PartsUtilized,PartsRestrained,BaseChance,BaseOffense,BasePopularity
Chop 1,Strike,1,Arms,0,0.8,3,1
Chop 2,Strike,2,Arms,0,0.85,6,2
Chop 3,Strike,3,Arms,0,0.9,9,3
Kick 1,Strike,1,Legs,0,0.7,4,1
Kick 2,Strike,2,Legs,0,0.8,8,3
Kick 3,Strike,3,Legs,0,0.85,12,5
Headbutt 1,Strike,1,Head,0,0.8,5,1
Headbutt 2,Strike,2,Head,0,0.9,9,1
Headbutt 3,Strike,3,Head,0,1.0,12,3
Bodystrike 1,Strike,1,All,0,0.75,6,1
Bodystrike 2,Strike,2,All,0,0.85,8,2
Bodystrike 3,Strike,3,All,0,0.9,10,3
Arm Hold 1,Hold,1,All,Arms,0.4,5,1
Arm Hold 2,Hold,2,All,Arms,0.5,8,2
Arm Hold 3,Hold,3,All,Arms,0.6,10,3
Leg Hold 1,Hold,1,All,Legs,0.4,5,1
Leg Hold 2,Hold,2,All,Legs,0.5,8,2
Leg Hold 3,Hold,3,All,Legs,0.6,10,3
Head Hold 1,Hold,1,All,Head,0.3,5,1
Head Hold 2,Hold,2,All,Head,0.5,8,2
Head Hold 3,Hold,3,All,Head,0.6,10,3
Body Hold 1,Hold,1,All,Body,0.5,5,1
Body Hold 2,Hold,2,All,Body,0.6,8,2
Body Hold 3,Hold,3,All,Body,0.7,10,3
Aerial Arm 1,Aerial,1,All,0,0.5,8,3
Aerial Arm 2,Aerial,2,All,0,0.6,12,4
Aerial Arm 3,Aerial,3,All,0,0.7,14,5
Aerial Leg 1,Aerial,1,All,0,0.4,8,3
Aerial Leg 2,Aerial,2,All,0,0.5,12,4
Aerial Leg 3,Aerial,3,All,0,0.6,14,5
Aerial Body 1,Aerial,1,All,0,0.4,9,4
Aerial Body 2,Aerial,2,All,0,0.5,14,5
Aerial Body 3,Aerial,3,All,0,0.7,17,6
Pin,Pin,1,All,0,0.3,0,1
Arms Pin,Pin,2,All,Arms,0.4,0,3
Legs Pin,Pin,2,All,Legs,0.4,0,3
Body Pin,Pin,2,All,Body,0.4,0,3
Super Pin,Pin,3,All,All,0.5,0,5
1 Name Type Rank PartsUtilized PartsRestrained BaseChance BaseOffense BasePopularity
2 Chop 1 Strike 1 Arms 0 0.8 3 1
3 Chop 2 Strike 2 Arms 0 0.85 6 2
4 Chop 3 Strike 3 Arms 0 0.9 9 3
5 Kick 1 Strike 1 Legs 0 0.7 4 1
6 Kick 2 Strike 2 Legs 0 0.8 8 3
7 Kick 3 Strike 3 Legs 0 0.85 12 5
8 Headbutt 1 Strike 1 Head 0 0.8 5 1
9 Headbutt 2 Strike 2 Head 0 0.9 9 1
10 Headbutt 3 Strike 3 Head 0 1.0 12 3
11 Bodystrike 1 Strike 1 All 0 0.75 6 1
12 Bodystrike 2 Strike 2 All 0 0.85 8 2
13 Bodystrike 3 Strike 3 All 0 0.9 10 3
14 Arm Hold 1 Hold 1 All Arms 0.4 5 1
15 Arm Hold 2 Hold 2 All Arms 0.5 8 2
16 Arm Hold 3 Hold 3 All Arms 0.6 10 3
17 Leg Hold 1 Hold 1 All Legs 0.4 5 1
18 Leg Hold 2 Hold 2 All Legs 0.5 8 2
19 Leg Hold 3 Hold 3 All Legs 0.6 10 3
20 Head Hold 1 Hold 1 All Head 0.3 5 1
21 Head Hold 2 Hold 2 All Head 0.5 8 2
22 Head Hold 3 Hold 3 All Head 0.6 10 3
23 Body Hold 1 Hold 1 All Body 0.5 5 1
24 Body Hold 2 Hold 2 All Body 0.6 8 2
25 Body Hold 3 Hold 3 All Body 0.7 10 3
26 Aerial Arm 1 Aerial 1 All 0 0.5 8 3
27 Aerial Arm 2 Aerial 2 All 0 0.6 12 4
28 Aerial Arm 3 Aerial 3 All 0 0.7 14 5
29 Aerial Leg 1 Aerial 1 All 0 0.4 8 3
30 Aerial Leg 2 Aerial 2 All 0 0.5 12 4
31 Aerial Leg 3 Aerial 3 All 0 0.6 14 5
32 Aerial Body 1 Aerial 1 All 0 0.4 9 4
33 Aerial Body 2 Aerial 2 All 0 0.5 14 5
34 Aerial Body 3 Aerial 3 All 0 0.7 17 6
35 Pin Pin 1 All 0 0.3 0 1
36 Arms Pin Pin 2 All Arms 0.4 0 3
37 Legs Pin Pin 2 All Legs 0.4 0 3
38 Body Pin Pin 2 All Body 0.4 0 3
39 Super Pin Pin 3 All All 0.5 0 5

11
UPWG/Elite/Elite.csproj Executable file
View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
</ItemGroup>
</Project>

81
UPWG/Elite/Engine.cs Executable file
View File

@ -0,0 +1,81 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Elite
{
public class Engine : Game
{
public static Engine Instance;
private GraphicsDeviceManager _graphicsDeviceManager;
private int _width;
private int _height;
private Color _clearColor;
private Scene _currentScene;
private Scene _nextScene;
private float _elapsed;
public static Scene Scene
{
get => Instance._currentScene;
set
{
if (Instance._currentScene != null)
Instance._nextScene = value;
else
Instance._currentScene = value;
}
}
public static float Elapsed => Instance._elapsed;
public Engine(int width, int height, Color clearColor)
{
Instance = this;
_graphicsDeviceManager = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
IsFixedTimeStep = false;
_clearColor = clearColor;
_width = width;
_height = height;
}
protected override void Initialize()
{
base.Initialize();
_graphicsDeviceManager.PreferredBackBufferWidth = _width;
_graphicsDeviceManager.PreferredBackBufferHeight = _height;
_graphicsDeviceManager.ApplyChanges();
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
_elapsed = (float) gameTime.ElapsedGameTime.TotalSeconds;
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
_currentScene?.Update(_elapsed);
if (_nextScene != null)
{
_currentScene = _nextScene;
_nextScene = null;
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(_clearColor);
_currentScene.Draw(_elapsed);
}
}
}

23
UPWG/Elite/Entity.cs Executable file
View File

@ -0,0 +1,23 @@
namespace Elite
{
public class Component
{
public Entity Entity;
}
public interface IUpdateable
{
void Update();
}
public interface
public class Entity
{
private static uint _nextId;
public string Name;
public readonly int Id;
private readonly FastList<Component
}
}

56
UPWG/Elite/Scene.cs Executable file
View File

@ -0,0 +1,56 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Elite
{
public class Scene
{
public static int DefaultHeight = 800;
public static int DefaultWidth = 600;
public readonly int Width;
public readonly int Height;
public float Scale;
private SpriteBatch _batch;
private RenderTarget2D _target;
public Scene(int width, int height)
{
Width = width;
Height = height;
_batch = new SpriteBatch(Engine.Instance.GraphicsDevice);
_target = new RenderTarget2D(Engine.Instance.GraphicsDevice, Width, Height);
}
public Scene() : this(DefaultWidth, DefaultHeight)
{
}
public virtual void Draw(float elapsed)
{
Engine.Instance.GraphicsDevice.SetRenderTarget(_target);
Engine.Instance.GraphicsDevice.Clear(Color.SeaGreen);
/*
SpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
foreach (var drawable in DrawList)
{
drawable.Draw(SpriteBatch);
}
SpriteBatch.End();
_graphicsDevice.SetRenderTarget(null);
SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
SpriteBatch.Draw(_target, Vector2.Zero, null, Color.LightBlue, 0.0f, Vector2.Zero, _scale,
SpriteEffects.None,
0.0f);
SpriteBatch.End();*/
}
public virtual void Update(float elapsed)
{
}
}
}

23
UPWG/Elite/Sprite.cs Executable file
View File

@ -0,0 +1,23 @@
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Elite
{
public class Sprite
{
private Texture2D _texture;
public Sprite(GraphicsDevice device, string filename)
{
var fileStream = new FileStream(filename, FileMode.Open);
_texture = Texture2D.FromStream(device, fileStream);
fileStream.Dispose();
}
public void Draw(SpriteBatch batch)
{
batch.Draw(_texture, Vector2.Zero, Color.White);
}
}
}

23
UPWG/Elite/TextElement.cs Executable file
View File

@ -0,0 +1,23 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Elite
{
public class TextElement
{
public string Text;
public Vector2 Position;
public Color Color;
public TextElement(string text, Vector2 position, Color color)
{
Text = text;
Position = position;
Color = color;
}
public void Draw(SpriteBatch batch)
{
}
}
}

33
UPWG/Manhattan/Manhattan.cs Executable file
View File

@ -0,0 +1,33 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Elite;
namespace Manhattan
{
public class ManhattanGame : Engine
{
public ManhattanGame(int width, int height, Color clearColor) : base(width, height, clearColor)
{
}
protected override void Initialize()
{
base.Initialize();
Scene = new Flying();
}
}
public class Flying : Scene
{
public override void Draw(float elapsed)
{
base.Update(elapsed);
}
public override void Update(float elapsed)
{
base.Update(elapsed);
}
}
}

33
UPWG/Manhattan/Manhattan.csproj Executable file
View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico"/>
<None Remove="Icon.bmp"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico"/>
<EmbeddedResource Include="Icon.bmp"/>
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="Content\Content.mgcb"/>
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641"/>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Elite\Elite.csproj"/>
</ItemGroup>
</Project>

16
UPWG/Manhattan/Program.cs Executable file
View File

@ -0,0 +1,16 @@
using System;
using Elite;
using Microsoft.Xna.Framework;
namespace Manhattan
{
public static class Program
{
[STAThread]
static void Main()
{
using (var game = new ManhattanGame(1280, 720, Color.Bisque))
game.Run();
}
}
}

43
UPWG/Manhattan/app.manifest Executable file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Manhattan"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

367
UPWG/UPWG.Core/Battle.cs Executable file
View File

@ -0,0 +1,367 @@
using System;
using System.Collections.Generic;
namespace UPWG.Core
{
public enum WrestlerPosition
{
InRing,
OnRopes,
OutsideRing,
}
public enum MomentumLevel
{
None = 0,
Low = 1,
Medium = 2,
High = 3,
}
public enum HitResult
{
Miss,
Hit,
Critical,
}
public class MoveResult
{
public HitResult Result;
// what did this do to the recipient?
public uint RecipientDamage;
public int RecipientMomentumDelta;
public BodyParts RecipientRestrained;
// and what did this do to us?
public uint SelfDamage;
public int SelfMomentumDelta;
public int SelfPopularityDelta;
public MoveResult(
HitResult result,
uint recipientDamage,
int recipientMomentumDelta = 0,
BodyParts restrained = 0,
uint selfDamage = 0,
int selfMomentumDelta = 0,
int selfPopularityDelta = 0
)
{
Result = result;
RecipientDamage = recipientDamage;
RecipientMomentumDelta = recipientMomentumDelta;
RecipientRestrained = restrained;
SelfDamage = selfDamage;
SelfMomentumDelta = selfMomentumDelta;
SelfPopularityDelta = selfPopularityDelta;
}
}
interface IGoal
{
public void ProcessMove(Move move, MoveResult result);
public bool IsComplete();
}
class MaxMomentumGoal : IGoal
{
public int GoalMomentum { get; }
private int _maxMomentum;
private int _curMomentum;
MaxMomentumGoal(int goalMomentum)
{
GoalMomentum = goalMomentum;
}
public void ProcessMove(Move move, MoveResult result)
{
_curMomentum += result.SelfMomentumDelta;
if (_curMomentum > _maxMomentum)
_maxMomentum = _curMomentum;
}
public bool IsComplete()
{
return _maxMomentum >= GoalMomentum;
}
}
public enum MatchStatus
{
InProgress,
Pinfall,
Submission,
CountOut,
Disqualification,
}
public class MoveOptions
{
// this class represents the available moves
public string Strike { get; set; }
public string Grapple { get; set; }
public string Other { get; set; }
public string Special { get; set; }
}
public class Battle
{
private static Random _random = new Random();
public enum ParticipantRole
{
LeftSingle,
RightSingle,
LeftTag1,
LeftTag2,
RightTag1,
RightTag2,
}
public struct Participant
{
public Wrestler Wrestler;
public WrestlerPosition Position;
public BodyParts Restrained;
public BodyParts Injured;
public MomentumLevel Momentum;
public uint MaxFatigue;
public uint CurFatigue;
public Participant(Wrestler wrestler)
{
Wrestler = wrestler;
Position = WrestlerPosition.InRing;
Restrained = 0;
Injured = 0;
Momentum = MomentumLevel.None;
CurFatigue = MaxFatigue = wrestler.Fortitude * 10;
}
}
private uint _turnClock;
private ParticipantRole _playerRole;
public Dictionary<ParticipantRole, Participant> Participants { get; }
public MatchStatus Status { get; private set; }
public ParticipantRole[] UpcomingTurns { get; set; }
public MoveOptions CurrentMoveOptions { get; private set; }
private void InitializeState()
{
_turnClock = 1;
Status = MatchStatus.InProgress;
UpcomingTurns = new ParticipantRole[5];
CalcUpcomingTurns();
CurrentMoveOptions = new MoveOptions();
CalcPlayerMoveOptions();
}
public Battle(Wrestler leftWrestler, Wrestler rightWrestler)
{
Participants = new Dictionary<ParticipantRole, Participant>
{
[ParticipantRole.LeftSingle] = new Participant(leftWrestler),
[ParticipantRole.RightSingle] = new Participant(rightWrestler)
};
_playerRole = ParticipantRole.LeftSingle;
InitializeState();
}
public Battle(Wrestler leftOne, Wrestler leftTwo, Wrestler rightOne, Wrestler rightTwo)
{
Participants = new Dictionary<ParticipantRole, Participant>
{
[ParticipantRole.LeftTag1] = new Participant(leftOne),
[ParticipantRole.LeftTag2] = new Participant(leftTwo),
[ParticipantRole.RightTag1] = new Participant(rightOne),
[ParticipantRole.RightTag2] = new Participant(rightTwo)
};
_playerRole = ParticipantRole.LeftTag1;
InitializeState();
}
// Player Interaction
public void CalcPlayerMoveOptions()
{
// TODO: revisit for other match types
var player = Participants[_playerRole];
var target = Participants[ParticipantRole.RightSingle];
// TODO: revisit for other move types
CurrentMoveOptions.Strike = GetBestAvailableMove(player, MoveType.Strike, target);
CurrentMoveOptions.Grapple = GetBestAvailableMove(player, MoveType.Aerial, target);
CurrentMoveOptions.Special = "Pin";
CurrentMoveOptions.Other = "Enzugiri **";
}
public MoveResult ApplyMove(string moveName)
{
var move = MoveDatabase.Lookup(moveName);
return ApplyMove(_playerRole, move, ParticipantRole.RightSingle);
}
public bool IsPlayerTurn()
{
return UpcomingTurns[0] == _playerRole;
}
public void EndTurn()
{
_turnClock += 1;
}
// CPU Control
public void GetCpuMove(out string move, out ParticipantRole target)
{
move = "Chop 1";
target = ParticipantRole.LeftSingle;
}
// Internals
private MoveResult ApplyMove(ParticipantRole performerPos, Move move, ParticipantRole recipientPos)
{
var performer = Participants[performerPos];
var recipient = Participants[recipientPos];
// can this move be done?
if (!MoveIsValid(performer, move, recipient))
throw new InvalidMoveException();
var hitResult = CheckForHit(performer, move, recipient);
// if move misses, no damage
if (hitResult == HitResult.Miss)
return new MoveResult(hitResult, 0);
uint damage = 0;
uint selfDamage = 0;
switch (move.Type)
{
case MoveType.Strike:
damage = (uint) (move.BaseOffense * performer.Wrestler.DamageMult);
break;
case MoveType.Aerial:
damage = (uint) (move.BaseOffense * performer.Wrestler.DamageMult);
selfDamage = 5;
break;
case MoveType.Hold:
break;
case MoveType.Throw:
damage = (uint) (move.BaseOffense * performer.Wrestler.DamageMult);
break;
case MoveType.Pin:
break;
}
// TODO: how does momentum/popularity work?
return new MoveResult(hitResult, damage, 0, 0, selfDamage, 0, 0);
}
private void CalcUpcomingTurns()
{
for (var i = 0; i < UpcomingTurns.Length; i++)
{
// TODO: use speed to determine turn order
if ((_turnClock + i) % 2 == 1)
{
UpcomingTurns[i] = ParticipantRole.LeftSingle;
}
else
{
UpcomingTurns[i] = ParticipantRole.RightSingle;
}
}
}
private static readonly double[] HitMod = {0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4};
private static readonly double[] EvadeMod = {-0.1, -0.1, -0.05, -0.05, 0, 0.05, 0.05, 0.1, 0.1, 0.15};
private static HitResult CheckForHit(Participant performer, Move move, Participant recipient)
{
var critChance = 0.05;
uint attackStat = 0;
switch (move.Type)
{
case MoveType.Strike:
attackStat = performer.Wrestler.Strength;
break;
case MoveType.Aerial:
attackStat = performer.Wrestler.Agility;
break;
case MoveType.Pin:
attackStat = performer.Wrestler.Strength > performer.Wrestler.Agility
? performer.Wrestler.Strength
: performer.Wrestler.Agility;
break;
case MoveType.Hold:
attackStat = performer.Wrestler.Grappling;
break;
case MoveType.Throw:
attackStat = performer.Wrestler.Grappling;
break;
}
var hitChance = move.BaseChance * HitMod[attackStat] - EvadeMod[recipient.Wrestler.Agility];
var hitRoll = _random.NextDouble();
if (hitRoll < critChance)
return HitResult.Critical;
else if (hitRoll <= hitChance)
return HitResult.Hit;
else
return HitResult.Miss;
}
private static bool MoveIsValid(Participant performer, Move move, Participant recipient)
{
// TODO: check position of performer and recipient
// is there an issue affecting the required body part
var requiredPartsRestrained = performer.Restrained & move.PartsUtilized;
if (requiredPartsRestrained != 0)
return false;
// does wrestler have momentum?
if (performer.Momentum < (MomentumLevel) (move.Rank - 1))
return false;
return true;
}
private static string GetBestAvailableMove(Participant participant, MoveType type, Participant recipient)
{
List<Move> best = new();
var bestRank = -1;
foreach (var (moveName, expertise) in participant.Wrestler.MoveSet)
{
var move = MoveDatabase.Lookup(moveName);
// accumulate list of best valid moves of the type
if (move.Type == type && MoveIsValid(participant, move, recipient))
{
// for now just use rank, eventually this may be dynamic
if (move.Rank > bestRank)
{
bestRank = (int) move.Rank;
best.Clear();
best.Add(move);
}
else if (move.Rank == bestRank)
{
best.Add(move);
}
}
}
return best[_random.Next(best.Count)].Name;
}
}
}

78
UPWG/UPWG.Core/Moves.cs Executable file
View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CsvHelper;
namespace UPWG.Core
{
public class InvalidMoveException : Exception
{
public InvalidMoveException()
{
}
public InvalidMoveException(string message) : base(message)
{
}
}
public enum MoveType
{
Strike,
Aerial,
Hold,
Throw,
Pin,
}
[Flags]
public enum BodyParts
{
Arms = 1,
Legs = 2,
Head = 4,
Body = 8,
All = Arms | Legs | Head | Body,
}
public class Move
{
public string Name { get; set; }
public MoveType Type { get; set; }
public uint Rank { get; set; }
// can it be done?
public double BaseChance { get; set; }
//public MomentumLevel RequiredMomentum { get; set; }
public BodyParts PartsRestrained { get; set; }
public BodyParts PartsUtilized { get; set; }
// what does it do?
public int BasePopularity { get; set; }
public int BaseOffense { get; set; }
}
public static class MoveDatabase
{
public static readonly Dictionary<string, Move> Moves = new();
public static void Initialize()
{
using var reader = new StreamReader("Data/moves.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
var records = csv.GetRecords<Move>();
foreach (var record in records)
{
Moves[record.Name] = record;
}
}
public static Move Lookup(string name)
{
return Moves[name];
}
}
}

45
UPWG/UPWG.Core/StateMachine.cs Executable file
View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace UPWG.Core
{
public class StateMachine<T>
where T : Enum
{
public T CurrentState { get; private set; }
public double TimeInState { get; private set; }
private Dictionary<T, (double, T)> _transitions;
public StateMachine(T initial)
{
CurrentState = initial;
TimeInState = 0;
_transitions = new Dictionary<T, (double, T)>();
}
public void AddTransition(T from, T to, double after = 0)
{
_transitions[from] = (after, to);
}
public void SetState(T newState)
{
CurrentState = newState;
TimeInState = 0;
}
public void Update(double elapsed)
{
TimeInState += elapsed;
if (!_transitions.ContainsKey(CurrentState))
return;
var (maxTime, nextState) = _transitions[CurrentState];
if (TimeInState > maxTime)
{
SetState(nextState);
}
}
}
}

11
UPWG/UPWG.Core/UPWG.Core.csproj Executable file
View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="27.1.1" />
</ItemGroup>
</Project>

61
UPWG/UPWG.Core/Wrestler.cs Executable file
View File

@ -0,0 +1,61 @@
using System.Collections.Generic;
namespace UPWG.Core
{
public enum WeightClass
{
Light,
Normal,
Heavy,
}
public class Wrestler
{
public string Name { get; }
public uint Strength { get; } // used
public uint Grappling { get; }
public uint Agility { get; }
public uint Fortitude { get; }
public uint Charisma { get; }
public WeightClass Weight { get; }
public Dictionary<string, uint> MoveSet;
public Wrestler(string name, uint strength, uint grappling, uint agility, uint fortitude, uint charisma,
WeightClass weight
)
{
Name = name;
Strength = strength;
Grappling = grappling;
Agility = agility;
Fortitude = fortitude;
Charisma = charisma;
Weight = weight;
MoveSet = new Dictionary<string, uint>();
foreach (var (move, _) in MoveDatabase.Moves)
{
MoveSet[move] = 0;
}
}
public double DamageMult
{
get
{
switch (Strength)
{
case <= 2: return 0.5;
case <= 4: return 1.0;
case <= 6: return 1.2;
case <= 8: return 1.4;
default: return 1.7;
}
}
}
public uint GetExpertise(string moveName)
{
return MoveSet.ContainsKey(moveName) ? MoveSet[moveName] : 0;
}
}
}

160
UPWG/UPWG.Main/Animation.cs Executable file
View File

@ -0,0 +1,160 @@
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Elite;
namespace UPWG.Main
{
internal enum MovementType
{
Run,
Jump,
Flip,
}
internal enum RingPosition
{
// these use cardinal directions (picture a compass rose laid over the ring)
// they will be flipped when animations are reversed
SouthWest,
West,
NorthWest,
North,
NorthEast,
East,
SouthEast,
South,
Center,
}
abstract class BattleAnimation
{
protected double ElapsedSeconds;
protected readonly double RunSeconds;
protected BattleAnimation(double runSeconds)
{
ElapsedSeconds = 0;
RunSeconds = runSeconds;
}
public bool Done()
{
return ElapsedSeconds > RunSeconds;
}
public abstract void Update(double elapsed, ref Vector2 pos, ref float rotation);
}
class Run : BattleAnimation
{
private Vector2 _start;
private Vector2 _end;
public Run(double runSeconds, RingPosition from, RingPosition to) : base(runSeconds)
{
_start = RingPositionToVector2(from);
_end = RingPositionToVector2(to);
}
public override void Update(double elapsed, ref Vector2 pos, ref float rotation)
{
ElapsedSeconds += elapsed;
pos = Vector2.Lerp(_start, _end, (float) (ElapsedSeconds / RunSeconds));
}
private const float EastRopesX = 200;
private const float WestRopesX = 500;
private const float CenterX = (EastRopesX + WestRopesX) / 2;
private const float NorthRopesY = 100;
private const float SouthRopesY = 300;
private const float CenterY = (NorthRopesY + SouthRopesY) / 2;
public static Vector2 RingPositionToVector2(RingPosition position)
{
return position switch
{
RingPosition.North => new Vector2(CenterX, NorthRopesY),
RingPosition.NorthEast => new Vector2(EastRopesX, NorthRopesY),
RingPosition.East => new Vector2(EastRopesX, CenterY),
RingPosition.SouthEast => new Vector2(EastRopesX, SouthRopesY),
RingPosition.South => new Vector2(CenterX, SouthRopesY),
RingPosition.SouthWest => new Vector2(WestRopesX, SouthRopesY),
RingPosition.West => new Vector2(WestRopesX, CenterY),
RingPosition.NorthWest => new Vector2(WestRopesX, NorthRopesY),
RingPosition.Center => new Vector2(CenterX, CenterY),
_ => throw new ArgumentOutOfRangeException(nameof(position))
};
}
}
class Spin : BattleAnimation
{
private float _angleFrom;
private float _angleTo;
public Spin(double runSeconds, float angleFrom, float angleTo) : base(runSeconds)
{
_angleFrom = angleFrom;
_angleTo = angleTo;
}
public override void Update(double elapsed, ref Vector2 pos, ref float rotation)
{
ElapsedSeconds += elapsed;
rotation = MathHelper.Lerp(_angleFrom, _angleTo, (float) (ElapsedSeconds / RunSeconds));
}
}
public class BattleSprite : IBatchDrawable
{
private const int Width = 128;
private const int Height = 128;
private Texture2D _texture;
private Vector2 _origin;
private Vector2 _pos;
private float _rotation;
private BattleAnimation[] _animations;
private int _animationNum;
public BattleSprite(GraphicsDevice graphicsDevice, string filename)
{
var fileStream = new FileStream("Content/jason.jpg", FileMode.Open);
_texture = Texture2D.FromStream(graphicsDevice, fileStream);
fileStream.Dispose();
_pos = new Vector2(100, 200);
_origin = new Vector2(_texture.Width / 2, _texture.Height / 2);
_animations = new BattleAnimation[]
{
new Run(1, RingPosition.West, RingPosition.East),
new Run(1, RingPosition.East, RingPosition.West),
//new Run(1, RingPosition.West, RingPosition.East),
//new Run(1, RingPosition.East, RingPosition.Center),
//new Run(0.2, RingPosition.Center, RingPosition.Center),
new Spin(4, 0, 3.14f),
};
_animationNum = 0;
}
public void Update(double elapsedSeconds)
{
if (_animationNum < _animations.Length)
{
_animations[_animationNum].Update(elapsedSeconds, ref _pos, ref _rotation);
if (_animations[_animationNum].Done())
_animationNum += 1;
}
}
public void Draw(SpriteBatch batch)
{
batch.Draw(_texture, new Rectangle((int) _pos.X, (int) _pos.Y, Width, Height), null, Color.White,
_rotation, _origin, SpriteEffects.None, 0);
}
}
}

197
UPWG/UPWG.Main/BattleTest.cs Executable file
View File

@ -0,0 +1,197 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using UPWG.Core;
using Elite;
namespace UPWG.Main
{
public enum TurnState
{
WaitingForInput,
PlayerMoveAnimation,
PlayerMoveResult,
OpponentMoveAnimation,
OpponentMoveResult,
}
public class BattleTest : Game
{
private GraphicsDeviceManager _graphicsDeviceManager;
private SpriteFont _spriteFont;
private Wrestler _p1;
private Wrestler _p2;
private Battle _match;
private StateMachine<TurnState> _turnState;
private BattleSprite _sprite1;
private BattleSprite _sprite2;
private ScaledRenderTarget _target;
private Sprite _ring;
public BattleTest()
{
_graphicsDeviceManager = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
MoveDatabase.Initialize();
_turnState = new StateMachine<TurnState>(TurnState.WaitingForInput);
_turnState.AddTransition(TurnState.PlayerMoveAnimation, TurnState.PlayerMoveResult, 1);
_turnState.AddTransition(TurnState.PlayerMoveResult, TurnState.OpponentMoveAnimation, 1);
_turnState.AddTransition(TurnState.OpponentMoveAnimation, TurnState.OpponentMoveResult, 1);
_turnState.AddTransition(TurnState.OpponentMoveResult, TurnState.WaitingForInput, 1);
_p1 = new Wrestler("CM Punk", 7, 9, 5, 8, 10, WeightClass.Normal);
_p2 = new Wrestler("John Cena", 8, 8, 5, 8, 8, WeightClass.Normal);
_match = new Battle(_p1, _p2);
}
protected override void Initialize()
{
_graphicsDeviceManager.PreferredBackBufferWidth = 1281;
_graphicsDeviceManager.PreferredBackBufferHeight = 720;
_graphicsDeviceManager.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
_spriteFont = Content.Load<SpriteFont>("Arial");
_target = new ScaledRenderTarget(GraphicsDevice, 640, 360, 2.0f, _spriteFont);
_sprite1 = new BattleSprite(GraphicsDevice, "");
_sprite2 = new BattleSprite(GraphicsDevice, "");
_ring = new Sprite(GraphicsDevice, "Content/oga/ring_7.png");
_target.DrawList.Add(_ring);
_target.DrawList.Add(_sprite1);
_target.DrawList.Add(_sprite2);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
var keyboardState = Keyboard.GetState();
MoveResult moveResult;
_turnState.Update(gameTime.ElapsedGameTime.TotalSeconds);
_sprite1.Update(gameTime.ElapsedGameTime.TotalSeconds);
_sprite2.Update(gameTime.ElapsedGameTime.TotalSeconds);
if (keyboardState.IsKeyDown(Keys.Escape))
Exit();
if (_match.IsPlayerTurn() && _turnState.CurrentState == TurnState.WaitingForInput)
{
if (keyboardState.IsKeyDown(Keys.A))
{
moveResult = _match.ApplyMove(_match.CurrentMoveOptions.Strike);
_turnState.SetState(TurnState.PlayerMoveAnimation);
}
else if (keyboardState.IsKeyDown(Keys.S))
{
moveResult = _match.ApplyMove(_match.CurrentMoveOptions.Grapple);
_turnState.SetState(TurnState.PlayerMoveAnimation);
}
else if (keyboardState.IsKeyDown(Keys.D))
{
moveResult = _match.ApplyMove(_match.CurrentMoveOptions.Other);
_turnState.SetState(TurnState.PlayerMoveAnimation);
}
else if (keyboardState.IsKeyDown(Keys.F))
{
moveResult = _match.ApplyMove(_match.CurrentMoveOptions.Special);
_turnState.SetState(TurnState.PlayerMoveAnimation);
}
}
else
{
_match.GetCpuMove(out var move, out var target);
moveResult = _match.ApplyMove(move);
}
base.Update(gameTime);
}
private void DrawWrestler(Battle.ParticipantRole role, Battle.Participant participant)
{
int x, y;
switch (role)
{
case Battle.ParticipantRole.LeftSingle:
x = 100;
y = 100;
break;
default:
x = 1280 - 300;
y = 100;
break;
}
_target.DrawString(
_spriteFont, $"{participant.Wrestler.Name}",
new Vector2(x, y), Color.Pink
);
_target.DrawString(
_spriteFont, $"Momentum: {participant.Momentum}",
new Vector2(x, y + 20), Color.Pink
);
_target.DrawString(
_spriteFont, $"Restrained: {participant.Restrained} Injured: {participant.Injured}",
new Vector2(x, y + 40), Color.Pink
);
_target.DrawString(
_spriteFont, $"{participant.CurFatigue} / {participant.MaxFatigue}",
new Vector2(x, y + 60), Color.Pink
);
}
private void DrawMoveOptions(MoveOptions moveOptions)
{
_target.DrawString(_spriteFont, $"A: {moveOptions.Strike}",
new Vector2(200, 200), Color.Yellow);
_target.DrawString(_spriteFont, $"S: {moveOptions.Grapple}",
new Vector2(200, 210), Color.Yellow);
_target.DrawString(_spriteFont, $"D: {moveOptions.Special}",
new Vector2(200, 220), Color.Yellow);
_target.DrawString(_spriteFont, $"F: {moveOptions.Other}",
new Vector2(200, 230), Color.Yellow);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Red);
const int x = 300;
var y = 300;
var n = 1;
_target.Draw(gameTime);
_target.SpriteBatch.Begin();
foreach (var (key, value) in _match.Participants)
{
DrawWrestler(key, value);
}
_target.DrawString(_spriteFont, $"{_turnState.CurrentState}", new Vector2(_target.Width / 2, 0),
Color.White);
foreach (var turn in _match.UpcomingTurns)
{
_target.DrawString(_spriteFont, $"{n}: {turn}", new Vector2(x, y), Color.Green);
n += 1;
y += 12;
}
if (_match.IsPlayerTurn())
DrawMoveOptions(_match.CurrentMoveOptions);
_target.SpriteBatch.End();
base.Draw(gameTime);
}
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Arial</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>12</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<!-- <DefaultCharacter>*</DefaultCharacter> -->
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View File

@ -0,0 +1,20 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:Windows
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin Arial.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Compressed
/build:Arial.spritefont

BIN
UPWG/UPWG.Main/Icon.bmp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
UPWG/UPWG.Main/Icon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

14
UPWG/UPWG.Main/Program.cs Executable file
View File

@ -0,0 +1,14 @@
using System;
namespace UPWG.Main
{
public static class Program
{
[STAThread]
static void Main()
{
using (var game = new BattleTest())
game.Run();
}
}
}

36
UPWG/UPWG.Main/UPWG.Main.csproj Executable file
View File

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
<PackageId>UPWG.Main</PackageId>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico"/>
<None Remove="Icon.bmp"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico"/>
<EmbeddedResource Include="Icon.bmp"/>
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="Content\Content.mgcb"/>
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641"/>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Elite\Elite.csproj"/>
<ProjectReference Include="..\UPWG.Core\UPWG.Core.csproj"/>
<ProjectReference Include="..\UPWG.Utils\UPWG.Utils.csproj"/>
</ItemGroup>
</Project>

43
UPWG/UPWG.Main/app.manifest Executable file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="UPWG.BattleTest"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

34
UPWG/UPWG.sln Executable file
View File

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UPWG.Core", "UPWG.Core\UPWG.Core.csproj", "{C8358627-AEAF-473B-B7B9-FD670A366095}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UPWG.Main", "UPWG.Main\UPWG.Main.csproj", "{4D7C34FD-5B50-454C-93ED-E805F261F48B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elite", "Elite\Elite.csproj", "{090DD346-EFA7-4907-8ACB-757D63F9F4B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Manhattan", "Manhattan\Manhattan.csproj", "{9FD7026A-D69B-40D8-AC7B-B77023CF5444}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C8358627-AEAF-473B-B7B9-FD670A366095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8358627-AEAF-473B-B7B9-FD670A366095}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8358627-AEAF-473B-B7B9-FD670A366095}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8358627-AEAF-473B-B7B9-FD670A366095}.Release|Any CPU.Build.0 = Release|Any CPU
{4D7C34FD-5B50-454C-93ED-E805F261F48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D7C34FD-5B50-454C-93ED-E805F261F48B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D7C34FD-5B50-454C-93ED-E805F261F48B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D7C34FD-5B50-454C-93ED-E805F261F48B}.Release|Any CPU.Build.0 = Release|Any CPU
{090DD346-EFA7-4907-8ACB-757D63F9F4B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{090DD346-EFA7-4907-8ACB-757D63F9F4B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{090DD346-EFA7-4907-8ACB-757D63F9F4B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{090DD346-EFA7-4907-8ACB-757D63F9F4B5}.Release|Any CPU.Build.0 = Release|Any CPU
{9FD7026A-D69B-40D8-AC7B-B77023CF5444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FD7026A-D69B-40D8-AC7B-B77023CF5444}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FD7026A-D69B-40D8-AC7B-B77023CF5444}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FD7026A-D69B-40D8-AC7B-B77023CF5444}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal