Tiles can now be obstacles (in the foreground) or decorations (in the background).

Updated Levels to show off some of these.

GitOrigin-RevId: d8d04410c15dd36218d5a1504dd842827082180f
This commit is contained in:
Colin McMillen 2020-02-20 12:25:46 -05:00
parent 08a31231e9
commit f1b71ca87d
3 changed files with 79 additions and 60 deletions

View File

@ -12,15 +12,15 @@
5 5
6 6
7 7
8 <===X===> <======================> 8 <=X=X=X=> <=============> (__________)
9 9 / \
0 0 | |
1 1 | |
2 2 | |
3 dfffxfffxfffb 3 dfffxfffxfffb dfffxfffxfffb v v
===================> <=============> <================================================================================================ =================> <=============> <================================================================================================
...................] [..............^^^^................................................................................................. ..................~`~`~`...............^^^^.................................................................................................
....................~`~`...................................................................................................................."; ..................======....................................................................................................................";
public const string ROCKS = @" public const string ROCKS = @"

View File

@ -76,17 +76,17 @@ namespace SemiColinGames {
// Set up transformation matrix for drawing world objects. // Set up transformation matrix for drawing world objects.
Matrix transform = Matrix.CreateTranslation(-camera.Left, -camera.Top, 0); Matrix transform = Matrix.CreateTranslation(-camera.Left, -camera.Top, 0);
spriteBatch.Begin(
SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null, null, transform);
// Draw background tiles.
world.DrawBackground(spriteBatch);
// Draw player. // Draw player.
spriteBatch.Begin(
SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null, null, transform);
player.Draw(spriteBatch); player.Draw(spriteBatch);
spriteBatch.End();
// Draw foreground tiles. // Draw foreground tiles.
spriteBatch.Begin( world.DrawForeground(spriteBatch);
SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null, null, transform);
world.Draw(spriteBatch);
spriteBatch.End(); spriteBatch.End();
// Draw debug rects & lines on top. // Draw debug rects & lines on top.

View File

@ -5,25 +5,49 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace SemiColinGames { namespace SemiColinGames {
enum Terrain { class Terrain {
Grass,
GrassL, public static Terrain FromSymbol(char symbol) {
GrassR, if (mapping.ContainsKey(symbol)) {
Rock, return mapping[symbol];
RockL, } else {
RockR, return null;
WaterL, }
WaterR, }
Block,
Spike, private static Dictionary<char, Terrain> mapping = new Dictionary<char, Terrain>();
Wood,
WoodL, public static Terrain Grass = new Terrain('=', true);
WoodR, public static Terrain GrassL = new Terrain('<', true);
WoodVert, public static Terrain GrassR = new Terrain('>', true);
FenceL, public static Terrain Rock = new Terrain('.', true);
Fence, public static Terrain RockL = new Terrain('[', true);
FencePost, public static Terrain RockR = new Terrain(']', true);
FenceR, public static Terrain WaterL = new Terrain('~', false);
public static Terrain WaterR = new Terrain('`', false);
public static Terrain Block = new Terrain('X', true);
public static Terrain Spike = new Terrain('^', true);
public static Terrain Wood = new Terrain('_', true);
public static Terrain WoodL = new Terrain('(', true);
public static Terrain WoodR = new Terrain(')', true);
public static Terrain WoodVert = new Terrain('|', false);
public static Terrain WoodVertL = new Terrain('/', false);
public static Terrain WoodVertR = new Terrain('\\', false);
public static Terrain WoodBottom = new Terrain('v', false);
public static Terrain FenceL = new Terrain('d', false);
public static Terrain Fence = new Terrain('f', false);
public static Terrain FencePost = new Terrain('x', false);
public static Terrain FenceR = new Terrain('b', false);
public bool IsObstacle { get; private set; }
private Terrain(char symbol, bool isObstacle) {
if (mapping.ContainsKey(symbol)) {
throw new ArgumentException("already have a terrain with symbol " + symbol);
}
IsObstacle = isObstacle;
mapping[symbol] = this;
}
} }
class TileFactory { class TileFactory {
@ -56,6 +80,9 @@ namespace SemiColinGames {
{ Terrain.WoodL, GetTextureSource(Textures.Grassland, 9, 3) }, { Terrain.WoodL, GetTextureSource(Textures.Grassland, 9, 3) },
{ Terrain.WoodR, GetTextureSource(Textures.Grassland, 12, 3) }, { Terrain.WoodR, GetTextureSource(Textures.Grassland, 12, 3) },
{ Terrain.WoodVert, GetTextureSource(Textures.Grassland, 9, 5) }, { Terrain.WoodVert, GetTextureSource(Textures.Grassland, 9, 5) },
{ Terrain.WoodVertL, GetTextureSource(Textures.Grassland, 9, 4) },
{ Terrain.WoodVertR, GetTextureSource(Textures.Grassland, 12, 4) },
{ Terrain.WoodBottom, GetTextureSource(Textures.Grassland, 10, 5) },
{ Terrain.FenceL, GetTextureSource(Textures.Grassland, 5, 4) }, { Terrain.FenceL, GetTextureSource(Textures.Grassland, 5, 4) },
{ Terrain.Fence, GetTextureSource(Textures.Grassland, 6, 4) }, { Terrain.Fence, GetTextureSource(Textures.Grassland, 6, 4) },
{ Terrain.FencePost, GetTextureSource(Textures.Grassland, 7, 4) }, { Terrain.FencePost, GetTextureSource(Textures.Grassland, 7, 4) },
@ -98,6 +125,7 @@ namespace SemiColinGames {
public const int TileSize = 16; public const int TileSize = 16;
readonly Tile[] tiles; readonly Tile[] tiles;
readonly Tile[] decorations;
// Size of World in terms of tile grid. // Size of World in terms of tile grid.
private readonly int tileWidth; private readonly int tileWidth;
@ -112,31 +140,10 @@ namespace SemiColinGames {
get { return tileHeight * TileSize; } get { return tileHeight * TileSize; }
} }
private static readonly Dictionary<char, Terrain> charToTerrain =
new Dictionary<char, Terrain>() {
{ '=', Terrain.Grass },
{ '<', Terrain.GrassL },
{ '>', Terrain.GrassR },
{ '.', Terrain.Rock },
{ '[', Terrain.RockL },
{ ']', Terrain.RockR },
{ '~', Terrain.WaterL },
{ '`', Terrain.WaterR },
{ 'X', Terrain.Block },
{ '^', Terrain.Spike },
{ '_', Terrain.Wood },
{ '(', Terrain.WoodL },
{ ')', Terrain.WoodR },
{ '|', Terrain.WoodVert },
{ 'd', Terrain.FenceL },
{ 'f', Terrain.Fence },
{ 'x', Terrain.FencePost },
{ 'b', Terrain.FenceR },
};
public World(string levelSpecification) { public World(string levelSpecification) {
TileFactory factory = new TileFactory(); TileFactory factory = new TileFactory();
var tilesList = new List<Tile>(); var tilesList = new List<Tile>();
var decorationsList = new List<Tile>();
string[] worldDesc = levelSpecification.Split('\n'); string[] worldDesc = levelSpecification.Split('\n');
tileWidth = worldDesc.AsQueryable().Max(a => a.Length); tileWidth = worldDesc.AsQueryable().Max(a => a.Length);
tileHeight = worldDesc.Length; tileHeight = worldDesc.Length;
@ -145,15 +152,21 @@ namespace SemiColinGames {
for (int j = 0; j < tileHeight; j++) { for (int j = 0; j < tileHeight; j++) {
if (i < worldDesc[j].Length) { if (i < worldDesc[j].Length) {
char key = worldDesc[j][i]; char key = worldDesc[j][i];
if (charToTerrain.ContainsKey(key)) { Terrain terrain = Terrain.FromSymbol(key);
Terrain terrain = charToTerrain[key]; if (terrain != null) {
var position = new Rectangle(i * TileSize, j * TileSize, TileSize, TileSize); var position = new Rectangle(i * TileSize, j * TileSize, TileSize, TileSize);
tilesList.Add(factory.MakeTile(terrain, position)); Tile tile = factory.MakeTile(terrain, position);
if (tile.Terrain.IsObstacle) {
tilesList.Add(tile);
} else {
decorationsList.Add(tile);
}
} }
} }
} }
} }
tiles = tilesList.ToArray(); tiles = tilesList.ToArray();
decorations = decorationsList.ToArray();
// Because we added tiles from left to right, the CollisionTargets are sorted by x-position. // Because we added tiles from left to right, the CollisionTargets are sorted by x-position.
// We maintain this invariant so that it's possible to efficiently find CollisionTargets that // We maintain this invariant so that it's possible to efficiently find CollisionTargets that
@ -176,7 +189,13 @@ namespace SemiColinGames {
new Vector2(Width + 1, 0), new Vector2(1, float.MaxValue)); new Vector2(Width + 1, 0), new Vector2(1, float.MaxValue));
} }
public void Draw(SpriteBatch spriteBatch) { public void DrawBackground(SpriteBatch spriteBatch) {
foreach (Tile t in decorations) {
t.Draw(spriteBatch);
}
}
public void DrawForeground(SpriteBatch spriteBatch) {
foreach (Tile t in tiles) { foreach (Tile t in tiles) {
t.Draw(spriteBatch); t.Draw(spriteBatch);
} }