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

View File

@ -76,17 +76,17 @@ namespace SemiColinGames {
// Set up transformation matrix for drawing world objects.
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.
spriteBatch.Begin(
SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null, null, transform);
player.Draw(spriteBatch);
spriteBatch.End();
// Draw foreground tiles.
spriteBatch.Begin(
SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null, null, transform);
world.Draw(spriteBatch);
world.DrawForeground(spriteBatch);
spriteBatch.End();
// Draw debug rects & lines on top.

View File

@ -5,25 +5,49 @@ using System.Collections.Generic;
using System.Linq;
namespace SemiColinGames {
enum Terrain {
Grass,
GrassL,
GrassR,
Rock,
RockL,
RockR,
WaterL,
WaterR,
Block,
Spike,
Wood,
WoodL,
WoodR,
WoodVert,
FenceL,
Fence,
FencePost,
FenceR,
class Terrain {
public static Terrain FromSymbol(char symbol) {
if (mapping.ContainsKey(symbol)) {
return mapping[symbol];
} else {
return null;
}
}
private static Dictionary<char, Terrain> mapping = new Dictionary<char, Terrain>();
public static Terrain Grass = new Terrain('=', true);
public static Terrain GrassL = new Terrain('<', true);
public static Terrain GrassR = new Terrain('>', true);
public static Terrain Rock = new Terrain('.', true);
public static Terrain RockL = new Terrain('[', true);
public static Terrain RockR = new Terrain(']', true);
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 {
@ -56,6 +80,9 @@ namespace SemiColinGames {
{ Terrain.WoodL, GetTextureSource(Textures.Grassland, 9, 3) },
{ Terrain.WoodR, GetTextureSource(Textures.Grassland, 12, 3) },
{ 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.Fence, GetTextureSource(Textures.Grassland, 6, 4) },
{ Terrain.FencePost, GetTextureSource(Textures.Grassland, 7, 4) },
@ -98,6 +125,7 @@ namespace SemiColinGames {
public const int TileSize = 16;
readonly Tile[] tiles;
readonly Tile[] decorations;
// Size of World in terms of tile grid.
private readonly int tileWidth;
@ -112,31 +140,10 @@ namespace SemiColinGames {
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) {
TileFactory factory = new TileFactory();
var tilesList = new List<Tile>();
var decorationsList = new List<Tile>();
string[] worldDesc = levelSpecification.Split('\n');
tileWidth = worldDesc.AsQueryable().Max(a => a.Length);
tileHeight = worldDesc.Length;
@ -145,15 +152,21 @@ namespace SemiColinGames {
for (int j = 0; j < tileHeight; j++) {
if (i < worldDesc[j].Length) {
char key = worldDesc[j][i];
if (charToTerrain.ContainsKey(key)) {
Terrain terrain = charToTerrain[key];
Terrain terrain = Terrain.FromSymbol(key);
if (terrain != null) {
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();
decorations = decorationsList.ToArray();
// 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
@ -176,7 +189,13 @@ namespace SemiColinGames {
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) {
t.Draw(spriteBatch);
}