Got rid of previous material system, now uses enumerators and item ids. Also imported QuadTree.cs so we can have entity collision.

This commit is contained in:
2020-06-21 20:17:59 -06:00
parent e25f4d70eb
commit 69c93ea427
25 changed files with 510 additions and 195 deletions

View File

@@ -181,7 +181,7 @@ public class InputController : IRestrictions
}
if (mouseState.RightButton == ButtonState.Pressed)
{
Chunks.PlaceBlock(playerMouse.GetSelectedXTile(),playerMouse.GetSelectedYTile(),"wood");
Chunks.PlaceBlock(playerMouse.GetSelectedXTile(),playerMouse.GetSelectedYTile(),Blocks.BlockWood);
}
}

View File

@@ -1,8 +0,0 @@
public class Block {
public string Name { get; }
public Block(string name) {
Name = name;
}
}

View File

@@ -1,32 +0,0 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Collector.Dimension
{
public static class BlockMaterials {
public static readonly Dictionary<string,Block> Materials = new Dictionary<string, Block>();
public static readonly Dictionary<string,Texture2D> Textures = new Dictionary<string, Texture2D>();
//Private so the singleton can't be instantiated
static BlockMaterials() {}
public static void Initialize(ContentManager content){
Materials.Add("grass",new Block("grass"));
Materials.Add("wood",new Block("wood"));
Materials.Add("water",new Block("water"));
Materials.Add("stone",new Block("stone"));
Materials.Add("snow",new Block("snow"));
Materials.Add("sand",new Block("sand"));
Materials.Add("air",new Block("air"));
Materials.Add("roof",new Block("roof"));
Materials.Add("wall",new Block("wall"));
foreach (var name in Materials.Keys)
{
Textures.Add(name,content.Load<Texture2D>(name));
}
}
}
}

View File

@@ -0,0 +1,15 @@
namespace Collector.Dimension
{
public enum Blocks
{
BlockAir,
BlockGrass,
BlockWood,
BlockStone,
BlockSnow,
BlockSand,
BlockRoof,
BlockWall,
BlockWater
}
}

View File

@@ -3,38 +3,39 @@
using System;
using System.Collections.Generic;
using Collector.ThirdPartyCode;
using Microsoft.Xna.Framework.Graphics;
namespace Collector.Dimension
{
public class Chunks: IRestrictions {
public static Dictionary<Tuple<int, int, int>, Block> LoadedChunks { get; } = new Dictionary<Tuple<int, int, int>, Block>();
private static readonly Dictionary<Tuple<int, int, int>, Block> SavedChunks = new Dictionary<Tuple<int, int, int>, Block>();
public static class Chunks
{
public static Dictionary<Tuple<int, int, int>, Blocks> LoadedChunks { get; } = new Dictionary<Tuple<int, int, int>, Blocks>();
private static readonly Dictionary<Tuple<int, int, int>, Blocks> SavedChunks = new Dictionary<Tuple<int, int, int>, Blocks>();
private static readonly OpenSimplexNoise Gen1 = new OpenSimplexNoise(IRestrictions.Seed+ 1);
private static readonly OpenSimplexNoise Gen2 = new OpenSimplexNoise(IRestrictions.Seed);
public static void CreateStructures() {
const int i = 10;
SetBlock(3 + i, 2,1,"wall");
SetBlock(4 + i, 2,1,"wall");
SetBlock(3 + i, 3,1, "roof");
SetBlock(4 + i, 3,1,"roof");
SetBlock(3 + i, 2,1,Blocks.BlockWall);
SetBlock(4 + i, 2,1,Blocks.BlockWall);
SetBlock(3 + i, 3,1, Blocks.BlockRoof);
SetBlock(4 + i, 3,1,Blocks.BlockRoof);
}
private static void SetBlock(int x, int y, int z, string name) {
LoadedChunks[new Tuple<int,int,int>(x, y, z)] = BlockMaterials.Materials[name];
SavedChunks[new Tuple<int,int,int>(x, y, z)] = BlockMaterials.Materials[name];
private static void SetBlock(int x, int y, int z, Blocks name)
{
LoadedChunks[new Tuple<int, int, int>(x, y, z)] = name;
SavedChunks[new Tuple<int,int,int>(x, y, z)] = name;
}
public static void PlaceBlock(int x, int y, string name)
public static void PlaceBlock(int x, int y, Blocks name)
{
var triple = new Tuple<int, int, int>(x, y, 1);
if (LoadedChunks.ContainsKey(triple))
if (!LoadedChunks.ContainsKey(triple)) return;
if (LoadedChunks[triple].Equals(Blocks.BlockAir))
{
if (LoadedChunks[triple].Name.Equals("air"))
{
SetBlock(x, y, 1, name);
}
SetBlock(x, y, 1, name);
}
}
@@ -42,10 +43,10 @@ namespace Collector.Dimension
var triple = new Tuple<int, int, int>(x, y, 1);
if (!LoadedChunks.ContainsKey(triple)) return;
if (LoadedChunks[triple].Name.Equals("air")) return;
if (LoadedChunks[triple].Equals(Blocks.BlockAir)) return;
LoadedChunks[triple] = BlockMaterials.Materials["air"];
SavedChunks[triple] = BlockMaterials.Materials["air"];
LoadedChunks[triple] = Blocks.BlockAir;
SavedChunks[triple] = Blocks.BlockAir;
}
public static void UngenerateChunk(int x, int y) {
@@ -99,8 +100,8 @@ namespace Collector.Dimension
}
}
private static Block GetBlocks(int x, int y, int z) {
return SavedChunks.GetValueOrDefault(new Tuple<int, int, int>(x, y, z), new Block("air"));
private static Blocks GetBlocks(int x, int y, int z) {
return SavedChunks.GetValueOrDefault(new Tuple<int, int, int>(x, y, z), Blocks.BlockAir);
}
private static double Noise1(double nx, double ny) {
@@ -111,7 +112,7 @@ namespace Collector.Dimension
return Gen2.Evaluate(nx, ny) / 2 + 0.5;
}
private static Block GetTerrain(int x, int y) {
private static Blocks GetTerrain(int x, int y) {
const double scale = 0.01;
var nx = x * scale;
var ny = y * scale;
@@ -134,26 +135,26 @@ namespace Collector.Dimension
return GetBiomeBlock(moisture, elevation);
}
private static Block GetBiomeBlock(double moisture, double elevation) {
private static Blocks GetBiomeBlock(double moisture, double elevation) {
var biome = GetBiome(moisture, elevation);
if (biome.Equals("Tundra")) return BlockMaterials.Materials["snow"];
if (biome.Equals("Taiga")) return BlockMaterials.Materials["snow"];
if (biome.Equals("Snow")) return BlockMaterials.Materials["snow"];
if (biome.Equals("Tundra")) return Blocks.BlockSnow;
if (biome.Equals("Taiga")) return Blocks.BlockSnow;
if (biome.Equals("Snow")) return Blocks.BlockSnow;
if (biome.Equals("Grassland")) return BlockMaterials.Materials["grass"];
if (biome.Equals("Shrubland")) return BlockMaterials.Materials["grass"];
if (biome.Equals("TemperateDeciduousForest")) return BlockMaterials.Materials["grass"];
if (biome.Equals("Grassland")) return Blocks.BlockGrass;
if (biome.Equals("Shrubland")) return Blocks.BlockGrass;
if (biome.Equals("TemperateDeciduousForest")) return Blocks.BlockGrass;
if (biome.Equals("TemperateRainForest")) return BlockMaterials.Materials["grass"];
if (biome.Equals("TropicalSeasonalForest")) return BlockMaterials.Materials["grass"];
if (biome.Equals("TropicalForest")) return BlockMaterials.Materials["grass"];
if (biome.Equals("TropicalRainForest")) return BlockMaterials.Materials["grass"];
if (biome.Equals("TemperateRainForest")) return Blocks.BlockGrass;
if (biome.Equals("TropicalSeasonalForest")) return Blocks.BlockGrass;
if (biome.Equals("TropicalForest")) return Blocks.BlockGrass;
if (biome.Equals("TropicalRainForest")) return Blocks.BlockGrass;
if (biome.Equals("Beach")) return BlockMaterials.Materials["sand"];
if (biome.Equals("Bare")) return BlockMaterials.Materials["sand"];
if (biome.Equals("Scorched")) return BlockMaterials.Materials["sand"];
if (biome.Equals("TemperateDesert")) return BlockMaterials.Materials["sand"];
return biome.Equals("SubtropicalDesert") ? BlockMaterials.Materials["sand"] : BlockMaterials.Materials["water"];
if (biome.Equals("Beach")) return Blocks.BlockSand;
if (biome.Equals("Bare")) return Blocks.BlockSand;
if (biome.Equals("Scorched")) return Blocks.BlockSand;
if (biome.Equals("TemperateDesert")) return Blocks.BlockSand;
return biome.Equals("SubtropicalDesert") ? Blocks.BlockSand : Blocks.BlockWater;
}
private static string GetBiome(double moisture, double elevation) {

View File

@@ -11,11 +11,7 @@ public class Inventory {
public void SetInventory(LinkedList<ItemStack> inventory) {
this.inventory = inventory;
}
public void AddItem(Block block){
inventory.AddFirst((ItemStack) block);
}
public void RemoveItem(ItemStack itemStack){
inventory.Remove(itemStack);
}

View File

@@ -1,11 +1,11 @@
namespace Collector.Dimension
{
public class ItemStack: Block {
public class ItemStack {
int value;
int quantity;
public ItemStack(string name, int value, int quantity) : base(name)
public ItemStack(Blocks id, int value, int quantity)
{
this.value = value;
this.quantity = quantity;

View File

@@ -1,7 +1,6 @@
using System.Linq;
using Collector.Character;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Collector.Dimension
@@ -23,10 +22,10 @@ namespace Collector.Dimension
private static void DrawWorld(SpriteBatch batch, int layer)
{
foreach (var chunkpair in Chunks.LoadedChunks.Keys.Where(chunkpair => chunkpair.Item3 == layer))
foreach (var chunkpair in Chunks.LoadedChunks.Keys.Where(chunkpair => layer==chunkpair.Item3))
{
batch.Draw(
BlockMaterials.Textures[Chunks.LoadedChunks[chunkpair].Name],
Main.Materials[Chunks.LoadedChunks[chunkpair]],
new Rectangle(
chunkpair.Item1 << IRestrictions.TileShift,
chunkpair.Item2 << IRestrictions.TileShift,
@@ -40,10 +39,11 @@ namespace Collector.Dimension
public void Draw(GameTime gameTime)
{
//Higher means draws in a lower layer
DrawWorld(_spriteBatch, 0);
DrawWorld(_spriteBatch,0);
DrawWorld(_spriteBatch,1);
_inputController.Draw();
_inputController.PlayerInput(_main,_playerMouse,gameTime);
DrawWorld(_spriteBatch, 1);
DrawWorld(_spriteBatch,2);
}
}
}

View File

@@ -0,0 +1,320 @@
using System;
using System.Collections.Generic;
using System.Linq;
//Quadtree code
//https://github.com/futurechris/QuadTree
namespace QuadTree
{
public class QuadTree<T>
{
private static Stack<Branch> branchPool = new Stack<Branch>();
private static Stack<Leaf> leafPool = new Stack<Leaf>();
private readonly Branch _root;
private readonly int _splitCount;
private readonly int _depthLimit;
private readonly Dictionary<T, Leaf> _leafLookup = new Dictionary<T, Leaf>();
public QuadTree(int splitCount, int depthLimit, ref Quad region)
{
_splitCount = splitCount;
_depthLimit = depthLimit;
_root = CreateBranch(this, null, 0, ref region);
}
public QuadTree(int splitCount, int depthLimit, Quad region)
: this(splitCount, depthLimit, ref region)
{
}
public QuadTree(int splitCount, int depthLimit, float x, float y, float width, float height)
: this(splitCount, depthLimit, new Quad(x, y, x + width, y + height))
{
}
public void Clear()
{
_root.Clear();
_root.Tree = this;
_leafLookup.Clear();
}
public static void ClearPools()
{
branchPool = new Stack<Branch>();
leafPool = new Stack<Leaf>();
}
private void Insert(T value, ref Quad quad)
{
if (!_leafLookup.TryGetValue(value, out var leaf))
{
leaf = CreateLeaf(value, ref quad);
_leafLookup.Add(value, leaf);
}
_root.Insert(leaf);
}
public void Insert(T value, Quad quad)
{
Insert(value, ref quad);
}
public void Insert(T value, float x, float y, float width, float height)
{
var quad = new Quad(x, y, x + width, y + height);
Insert(value, ref quad);
}
private bool SearchArea(ref Quad quad, ref List<T> values)
{
if (values != null)
values.Clear();
else
values = new List<T>();
_root.SearchQuad(ref quad, values);
return values.Count > 0;
}
public bool SearchArea(Quad quad, ref List<T> values)
{
return SearchArea(ref quad, ref values);
}
public bool SearchArea(float x, float y, float width, float height, ref List<T> values)
{
var quad = new Quad(x, y, x + width, y + height);
return SearchArea(ref quad, ref values);
}
public bool SearchPoint(float x, float y, ref List<T> values)
{
if (values != null)
values.Clear();
else
values = new List<T>();
_root.SearchPoint(x, y, values);
return values.Count > 0;
}
public bool FindCollisions(T value, ref List<T> values)
{
if (values != null)
values.Clear();
else
values = new List<T>(_leafLookup.Count);
if (!_leafLookup.TryGetValue(value, out var leaf)) return false;
var branch = leaf.Branch;
//Add the leaf's siblings (prevent it from colliding with itself)
if (branch.Leaves.Count > 0)
foreach (var t in branch.Leaves)
if (leaf != t && leaf.Quad.Intersects(ref t.Quad))
values.Add(t.Value);
//Add the branch's children
if (branch.Split)
for (var i = 0; i < 4; ++i)
if (branch.Branches[i] != null)
branch.Branches[i].SearchQuad(ref leaf.Quad, values);
//Add all leaves back to the root
branch = branch.Parent;
while (branch != null)
{
if (branch.Leaves.Count > 0)
foreach (var t in branch.Leaves)
if (leaf.Quad.Intersects(ref t.Quad))
values.Add(t.Value);
branch = branch.Parent;
}
return false;
}
public int CountBranches()
{
var count = 0;
CountBranches(_root, ref count);
return count;
}
private static void CountBranches(Branch branch, ref int count)
{
++count;
if (!branch.Split) return;
for (var i = 0; i < 4; ++i)
if (branch.Branches[i] != null)
CountBranches(branch.Branches[i], ref count);
}
private static Branch CreateBranch(QuadTree<T> tree, Branch parent, int branchDepth, ref Quad quad)
{
var branch = branchPool.Count > 0 ? branchPool.Pop() : new Branch();
branch.Tree = tree;
branch.Parent = parent;
branch.Split = false;
branch.Depth = branchDepth;
var midX = quad.MinX + (quad.MaxX - quad.MinX) * 0.5f;
var midY = quad.MinY + (quad.MaxY - quad.MinY) * 0.5f;
branch.Quads[0].Set(quad.MinX, quad.MinY, midX, midY);
branch.Quads[1].Set(midX, quad.MinY, quad.MaxX, midY);
branch.Quads[2].Set(midX, midY, quad.MaxX, quad.MaxY);
branch.Quads[3].Set(quad.MinX, midY, midX, quad.MaxY);
return branch;
}
private static Leaf CreateLeaf(T value, ref Quad quad)
{
var leaf = leafPool.Count > 0 ? leafPool.Pop() : new Leaf();
leaf.Value = value;
leaf.Quad = quad;
return leaf;
}
public class Branch
{
internal QuadTree<T> Tree;
internal Branch Parent;
internal readonly Quad[] Quads = new Quad[4];
internal readonly Branch[] Branches = new Branch[4];
internal readonly List<Leaf> Leaves = new List<Leaf>();
internal bool Split;
internal int Depth;
internal void Clear()
{
Tree = null;
Parent = null;
Split = false;
for (var i = 0; i < 4; ++i)
{
if (Branches[i] == null) continue;
branchPool.Push(Branches[i]);
Branches[i].Clear();
Branches[i] = null;
}
foreach (var t in Leaves)
{
leafPool.Push(t);
t.Branch = null;
t.Value = default;
}
Leaves.Clear();
}
internal void Insert(Leaf leaf)
{
//If this branch is already split
if (Split)
{
for (var i = 0; i < 4; ++i)
{
if (!Quads[i].Contains(ref leaf.Quad)) continue;
Branches[i] ??= CreateBranch(Tree, this, Depth + 1, ref Quads[i]);
Branches[i].Insert(leaf);
return;
}
Leaves.Add(leaf);
leaf.Branch = this;
}
else
{
//Add the leaf to this node
Leaves.Add(leaf);
leaf.Branch = this;
//Once I have reached capacity, split the node
if (Leaves.Count >= Tree._splitCount && Depth < Tree._depthLimit)
{
Split = true;
}
}
}
internal void SearchQuad(ref Quad quad, List<T> values)
{
if (Leaves.Count > 0)
foreach (var t in Leaves)
if (quad.Intersects(ref t.Quad))
values.Add(t.Value);
for (var i = 0; i < 4; ++i)
if (Branches[i] != null)
Branches[i].SearchQuad(ref quad, values);
}
internal void SearchPoint(float x, float y, List<T> values)
{
if (Leaves.Count > 0) values.AddRange(from t in Leaves where t.Quad.Contains(x, y) select t.Value);
for (var i = 0; i < 4; ++i)
if (Branches[i] != null)
Branches[i].SearchPoint(x, y, values);
}
}
internal class Leaf
{
internal Branch Branch;
internal T Value;
internal Quad Quad;
}
}
public struct Quad
{
public float MinX;
public float MinY;
public float MaxX;
public float MaxY;
public Quad(float minX, float minY, float maxX, float maxY)
{
MinX = minX;
MinY = minY;
MaxX = maxX;
MaxY = maxY;
}
public void Set(float minX, float minY, float maxX, float maxY)
{
MinX = minX;
MinY = minY;
MaxX = maxX;
MaxY = maxY;
}
public bool Intersects(ref Quad other)
{
return MinX < other.MaxX && MinY < other.MaxY && MaxX > other.MinX && MaxY > other.MinY;
}
public bool Contains(ref Quad other)
{
return other.MinX >= MinX && other.MinY >= MinY && other.MaxX <= MaxX && other.MaxY <= MaxY;
}
public bool Contains(float x, float y)
{
return x > MinX && y > MinY && x < MaxX && y < MaxY;
}
}
}