Skip to content

Commit

Permalink
Merge pull request #9 from SneakyTactician/TileBasedDev
Browse files Browse the repository at this point in the history
	[Version 0.0.0.3]
		### Features
			*End turn button is now rendered
		#### API
			*Support for creature movement
		### Tweaks
			*Changed many data structures under the hood
  • Loading branch information
TBye101 authored Feb 1, 2018
2 parents dfdaedd + f4bdddb commit 3f0457b
Show file tree
Hide file tree
Showing 44 changed files with 1,154 additions and 97 deletions.
23 changes: 10 additions & 13 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
SneakyTactician <[email protected]>
[Version 0.0.0.3]
### Features
*End turn button is now rendered
#### API
*Support for creature movement
### Tweaks
*Changed many data structures under the hood
### Bugs
*

[Version 0.0.0.2]
### Features
Expand All @@ -7,22 +16,10 @@
#### API
*Living creatures are now supported

### Tweaks
*

### Bugs
*

[Version 0.0.0.1]

### Features
*The world displays when told to generate a new world

#### API
*World generates properly

### Tweaks
*

### Bugs
*
*World generates properly
4 changes: 4 additions & 0 deletions Credit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Credit for things I used that I didn't make:

Libraries:
https://github.com/agabani/DijkstraAlgorithm optimal pathfinding algorithm
12 changes: 12 additions & 0 deletions EarthWithMagic.sln
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{09293283-6E6D-4652-A633-5B70452244DA}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.txt = CHANGELOG.txt
Credit.txt = Credit.txt
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicalLifeAPI", "MagicalLifeAPI\MagicalLifeAPI.csproj", "{FE8400A7-9DC8-4AB4-8C54-AC5F36BF7639}"
Expand All @@ -14,6 +15,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicalLifeGUI", "MagicalLi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicalLifeRenderEngine", "MagicalLifeRenderEngine\MagicalLifeRenderEngine.csproj", "{C1553F02-E940-4F5E-8C8C-DD6184922D86}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Snippets", "Snippets", "{EE5F9F76-E1DE-4746-BEC3-4D63543E0F68}"
ProjectSection(SolutionItems) = preProject
TilesEnumeration.snippet = TilesEnumeration.snippet
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicalLifeSettings", "MagicalLifeSettings\MagicalLifeSettings.csproj", "{76B12B63-DF5D-40FD-8E90-03395095DD71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -32,6 +40,10 @@ Global
{C1553F02-E940-4F5E-8C8C-DD6184922D86}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1553F02-E940-4F5E-8C8C-DD6184922D86}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1553F02-E940-4F5E-8C8C-DD6184922D86}.Release|Any CPU.Build.0 = Release|Any CPU
{76B12B63-DF5D-40FD-8E90-03395095DD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76B12B63-DF5D-40FD-8E90-03395095DD71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76B12B63-DF5D-40FD-8E90-03395095DD71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76B12B63-DF5D-40FD-8E90-03395095DD71}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Binary file added Libs/DijkstraAlgorithm.dll
Binary file not shown.
49 changes: 49 additions & 0 deletions MagicalLifeAPI/DataTypes/Point3D.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MagicalLifeAPI.DataTypes
{
/// <summary>
/// A 3 dimensional point class.
/// </summary>
public class Point3D : Object
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }

public Point3D(int x, int y, int z)
{
this.X = x;
this.Y = y;
this.Z = z;
}

public Point3D(string str)
{
string[] delimiter = new string[] { ", " };
string[] numbers = str.Split(delimiter, 3, StringSplitOptions.RemoveEmptyEntries);

int x;
int y;
int z;

int.TryParse(numbers[0], out x);
int.TryParse(numbers[1], out y);
int.TryParse(numbers[2], out z);

this.X = x;
this.Y = y;
this.Z = z;
}

public override string ToString()
{
return this.X.ToString() + ", " + this.Y.ToString() + ", " + this.Z.ToString();
}
}
}
11 changes: 10 additions & 1 deletion MagicalLifeAPI/Entities/Living.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using MagicalLifeAPI.Entities.Util;
using System.Collections.Generic;
using DijkstraAlgorithm.Pathing;
using System.Collections.Concurrent;
using System.Collections;
using MagicalLifeAPI.Entities.Util;
using MagicalLifeAPI.Universal;

namespace MagicalLifeAPI.Entities
Expand All @@ -8,6 +12,11 @@ namespace MagicalLifeAPI.Entities
/// </summary>
public abstract class Living : Unique
{
/// <summary>
/// A queue that holds the queued movement steps up for this living creature.
/// </summary>
public Queue<PathSegment> QueuedMovement { get; set; } = new Queue<PathSegment>();

/// <summary>
/// How many hit points this creature has.
/// </summary>
Expand Down
57 changes: 57 additions & 0 deletions MagicalLifeAPI/Entities/Movement/EntityWorldMovement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Security.Cryptography;
using DijkstraAlgorithm.Pathing;
using MagicalLifeAPI.World;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MagicalLifeAPI.Entities.Util.Modifier_Remove_Conditions;

namespace MagicalLifeAPI.Entities.Movement
{
/// <summary>
/// Used to move entities.
/// </summary>
public static class EntityWorldMovement
{
/// <summary>
/// Moves an entity from it's current position to as close to it's target destination as it can get. This will appear like teleporting.
/// </summary>
/// <param name="entity"></param>
public static void MoveEntity(ref Living entity)
{
Queue<PathSegment> path = entity.QueuedMovement;
while (entity.MovementSpeed.GetValue() > 0 && path.Count > 0)
{
PathSegment destination = path.Dequeue();
Tile sourceTile = WorldUtil.GetTileByID(World.World.mainWorld.Tiles, destination.Origin.Id);
Tile destinationTile = WorldUtil.GetTileByID(World.World.mainWorld.Tiles, destination.Destination.Id);
string modifierReason = "Moved onto a " + destinationTile.GetName() + " tile";
entity.MovementSpeed.AddModifier(new Tuple<long, IModifierRemoveCondition, string>(-1 * destinationTile.MovementCost, new TimeRemoveCondition(1), modifierReason));
World.World.mainWorld.Tiles[sourceTile.Location.X, sourceTile.Location.Y, sourceTile.Location.Z].Living.RemoveAt(EntityWorldMovement.GetIndexOfEntity(sourceTile.Living, entity));
World.World.mainWorld.Tiles[destinationTile.Location.X, destinationTile.Location.Y, destinationTile.Location.Z].Living.Add(entity);
}
}

/// <summary>
/// Finds the index of the living creature in the list. Returns -1 if it doesn't exist anymore.
/// </summary>
/// <param name="living"></param>
/// <param name="target"></param>
/// <returns></returns>
private static int GetIndexOfEntity(List<Living> living, Living target)
{
int length = living.Count;
for (int i = 0; i < length; i++)
{
if (living[i].ID == target.ID)
{
return i;
}
}

return -1;
}
}
}
177 changes: 177 additions & 0 deletions MagicalLifeAPI/Entities/Movement/StandardPathFinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
using DijkstraAlgorithm.Graphing;
using DijkstraAlgorithm.Pathing;
using MagicalLifeAPI.World;
using System.Linq;

namespace MagicalLifeAPI.Entities.Movement
{
/// <summary>
/// A class that handles the construction of the graph used to do optimal pathfinding.
/// </summary>
public static class StandardPathFinder
{
/// <summary>
/// Holds data that describes which tiles connect to which tiles.
/// This graph contains data used to pathfind for the standard movement.
/// </summary>
private static GraphBuilder tileConnectionGraph = new GraphBuilder();

private static Graph builtGraph;

/// <summary>
/// Used to determine the fastest route between two points.
/// </summary>
private static PathFinder pathFinder;

/// <summary>
/// Returns the fastest route between the source and destination tiles.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Path GetFastestPath(Tile source, Tile destination)
{
Path path = pathFinder.FindShortestPath(
StandardPathFinder.builtGraph.Nodes.Single(node => node.Id == source.Location.ToString()),
StandardPathFinder.builtGraph.Nodes.Single(node => node.Id == destination.Location.ToString()));
return path;
}

/// <summary>
/// Populates the <see cref="tileConnectionGraph"/> with data.
/// This should be called once after the world is generated.
/// </summary>
/// <param name="world"></param>
public static void BuildPathGraph(World.World world)
{
StandardPathFinder.AddNodes(world);
StandardPathFinder.AddLinkes(world);
StandardPathFinder.builtGraph = StandardPathFinder.tileConnectionGraph.Build();
StandardPathFinder.pathFinder = new PathFinder(StandardPathFinder.builtGraph);
}

/// <summary>
/// Creates connections between tiles in the <see cref="tileConnectionGraph"/>.
/// </summary>
/// <param name="world"></param>
private static void AddLinkes(World.World world)
{
Tile[,,] tiles = world.Tiles;
int xSize = tiles.GetLength(0);
int ySize = tiles.GetLength(1);
int zSize = tiles.GetLength(2);

int x = 0;
int y = 0;
int z = 0;

//Iterate over each row.
for (int i = 0; i < xSize; i++)
{
//Iterate over each column
for (int ii = 0; ii < ySize; ii++)
{
//Iterate over the depth of each tile in the z axis.
for (int iii = 0; iii < zSize; iii++)
{
//Each tile can be accessed by the xyz coordinates from this inner loop properly.
StandardPathFinder.AddNeighborLink(1, 0, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(-1, 0, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(0, 1, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(0, -1, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(1, 1, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(1, -1, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(-1, 1, 0, tiles, tiles[x, y, z]);
StandardPathFinder.AddNeighborLink(-1, -1, 0, tiles, tiles[x, y, z]);
z++;
}
y++;
z = 0;
}
y = 0;
x++;
}
}

/// <summary>
/// Adds a link to a neighboring tile if the tile exists/is in bounds.
/// </summary>
/// <param name="xChange"></param>
/// <param name="yChange"></param>
/// <param name="zChange"></param>
private static void AddNeighborLink(int xChange, int yChange, int zChange, Tile[,,] tiles, Tile source)
{
int x = (int)source.Location.X;
int y = (int)source.Location.Y;
int z = (int)source.Location.Z;

if (x + xChange > -1 && x + xChange < tiles.GetLength(0))
{
x += xChange;
}
else
{
//The neighboring tile didn't exist.
return;
}

if (y + yChange > -1 && y + yChange < tiles.GetLength(1))
{
y += yChange;
}
else
{
//The neighboring tile didn't exist.
return;
}

if (z + zChange > -1 && z + zChange < tiles.GetLength(2))
{
z += zChange;
}
else
{
//The neighboring tile didn't exist.
return;
}

StandardPathFinder.tileConnectionGraph.AddLink(source.Location.ToString(), tiles[x, y, z].Location.ToString(), 101 - tiles[x, y, z].MovementCost);
}

/// <summary>
/// Adds tiles as nodes into the <see cref="tileConnectionGraph"/>.
/// </summary>
/// <param name="world"></param>
private static void AddNodes(World.World world)
{
Tile[,,] tiles = world.Tiles;
int xSize = tiles.GetLength(0);
int ySize = tiles.GetLength(1);
int zSize = tiles.GetLength(2);

int x = 0;
int y = 0;
int z = 0;

//Iterate over each row.
for (int i = 0; i < xSize; i++)
{
//Iterate over each column
for (int ii = 0; ii < ySize; ii++)
{
//Iterate over the depth of each tile in the z axis.
for (int iii = 0; iii < zSize; iii++)
{
//Each tile can be accessed by the xyz coordinates from this inner loop properly.
StandardPathFinder.tileConnectionGraph.AddNode(tiles[x, y, z].Location.ToString());
z++;
}
y++;
z = 0;
}
y = 0;
x++;
}
}
}
}
Loading

0 comments on commit 3f0457b

Please sign in to comment.