If class something like this:
public enum Facing {
vertical, horizontal
}
class Sprite {
public Texture2D texmap; // reference to texture map
public Vector2 pos;
}
class MazePart : Sprite {
public Facing facing = Facing.vertical;
public Rectangle source_rect;
// C O N S T R U C T / I N I T
public MazePart(int x, int y, Facing _facing, Texture2D refer_texture) //CONSTRUCTOR -- TAKES X AND Y FROM INPUT
{
texmap = refer_texture; // point to the texture map to use that's already loaded
pos = new Vector2(x, y); // set part in a position
facing = _facing; // set the source to copy image from:
SetRect();
}
// S E T R E C T
public void SetRect()
{
switch (facing)
{
case Facing.vertical: source_rect = new Rectangle(30, 96, 12, 24); break;
case Facing.horizontal: source_rect = new Rectangle(0, 102, 24, 12); break;
}
}
// D R A W
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texmap, pos, source_rect, Color.White);
}
} // End MazePart Class
And then in Game 1 something with editor and loader like this:
namespace Mazer {
public class Game1 : Game {
const string LEVEL_NAME = @"Content\\lev1.txt";
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont font;
KeyboardState kb, okb;
bool edit_mode = false;
Point edit_pos;
Vector2 player_start_pos;
Texture2D images;
List<MazePart> mazeParts;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
// I N I T
protected override void Initialize()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
player_start_pos = new Vector2(6, 6);
base.Initialize();
}
// L O A D
protected override void LoadContent()
{
font = Content.Load<SpriteFont>("Font");
images = Content.Load<Texture2D>("SpriteSheet");
mazeParts = new List<MazePart>();
LoadMap(LEVEL_NAME); // returns if doesn't exist
}
protected override void UnloadContent() { }
// O C C U P I E D:
bool Occupied(bool Delete=false) {
int i = 0;
while(i<mazeParts.Count)
{
if ((mazeParts[i].pos.X == edit_pos.X) && (mazeParts[i].pos.Y == edit_pos.Y)) {
if (Delete) mazeParts.RemoveAt(i);
return true;
}
i++;
}
return false;
}
// U P D A T E
public bool KeyPress(Keys k) { if (kb.IsKeyDown(k) && okb.IsKeyUp(k)) return true; else return false; }
protected override void Update(GameTime gameTime)
{
okb = kb;
kb = Keyboard.GetState();
if (kb.IsKeyDown(Keys.Escape)) Exit();
if (KeyPress(Keys.E)) {
edit_mode = !edit_mode; // toggle between edit mode and play mode
if (!edit_mode) SaveMap();
}
if (edit_mode)
{
if (KeyPress(Keys.Right)) { edit_pos.X += 12; }
if (KeyPress(Keys.Left)) { edit_pos.X -= 12; }
if (KeyPress(Keys.Down)) { edit_pos.Y += 12; }
if (KeyPress(Keys.Up)) { edit_pos.Y -= 12; }
MathHelper.Clamp(edit_pos.X, 0, GraphicsDevice.Viewport.Width -24);
MathHelper.Clamp(edit_pos.Y, 0, GraphicsDevice.Viewport.Height-24);
if (KeyPress(Keys.H)) {
if (!Occupied()) mazeParts.Add(new MazePart(edit_pos.X, edit_pos.Y, Facing.horizontal, images));
}
if (KeyPress(Keys.V)) {
if (!Occupied()) mazeParts.Add(new MazePart(edit_pos.X, edit_pos.Y, Facing.vertical, images));
}
if (KeyPress(Keys.Delete)) { if (Occupied(Delete: true)); }
}
base.Update(gameTime);
}
// D R A W
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.TransparentBlack);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, null, null);
if (edit_mode) {
spriteBatch.Draw(images, edit_pos.ToVector2(), new Rectangle(0, 102, 8, 8), Color.White);
spriteBatch.DrawString(font, "Press H or V to add walls (arrows to move)", new Vector2(10, 100), Color.LimeGreen);
spriteBatch.DrawString(font, "Press E to go back to play mode (auto saves)", new Vector2(10, 200), Color.LimeGreen);
} else {
spriteBatch.DrawString(font, "Press E to enter toggle edit mode", new Vector2(10, 10), Color.LimeGreen);
}
int i = 0;
while(i<mazeParts.Count) {
mazeParts[i].Draw(spriteBatch);
i++;
}
spriteBatch.End();
base.Draw(gameTime);
} // Draw
// S A V E M A P
void SaveMap()
{
if (File.Exists(LEVEL_NAME)) File.Copy(LEVEL_NAME, @"Content\\backup.txt", true); // in case you want a backup
using (StreamWriter writer = new StreamWriter(LEVEL_NAME))
{
writer.WriteLine(player_start_pos.X.ToString() + "," + player_start_pos.Y.ToString() + ",");
int i = 0; Console.WriteLine(mazeParts.Count);
while (i<mazeParts.Count)
{
writer.WriteLine("PART_XY," + mazeParts[i].pos.X.ToString()+","+mazeParts[i].pos.Y.ToString() + ",");
writer.WriteLine("PART_TYPE," + ((int)mazeParts[i].facing).ToString() + ",");
i++;
}
}
} // SaveMap
// L O A D M A P
void LoadMap(string level_name)
{
if (!File.Exists(level_name)) return;
mazeParts.Clear();
using (StreamReader reader = new StreamReader(level_name))
{
string line = reader.ReadLine();
string[] parts = line.Split(','); // split into strings at each comma
player_start_pos.X = Convert.ToSingle(parts[0]); // Vector2 uses float = SINGLE
player_start_pos.Y = Convert.ToSingle(parts[1]);
int i = -1;
while (reader.EndOfStream != true)
{
line = reader.ReadLine();
parts = line.Split(',');
switch (parts[0]) // first string should contain a tag telling it what the data is for
{
case "PART_XY":
// need to make a new one:
MazePart m_part = new MazePart(Convert.ToInt32(parts[1]), Convert.ToInt32(parts[2]), Facing.horizontal, images); // temporarily say it's horizontal
// add it to the list (and edit later):
mazeParts.Add(m_part);
i++; // update the index so we modify the current one as we load more data
break;
case "PART_TYPE":
// modify the current part:
mazeParts[i].facing = (Facing)(Convert.ToInt32(parts[1]));
mazeParts[i].SetRect(); // fix the rectangle sources, now that the orientation is corrected
break;
}
}
}
} // LoadMap
}
}