Showing posts with label dungeon. Show all posts
Showing posts with label dungeon. Show all posts

Tuesday, 28 July 2015

D&D Session 2

This is a couple of months late, as session two of our three player (plus one GM) D&D adventure took place in May.  However, I've been busy and only just got around to reviewing the game I set up and ran.

My players started and remained level 2 throughout, the dungeon started with the group having to solve a simple pattern to visit a certain house (in a small four house village) there they heard about a third party none player character called "Bard", and suddenly they were confronted with "Bard" in a carriage to take the group to his country estate... I gave them the option of "The Easy Way" or "The Hard Way".

However, both options were for the group to be knocked unconscious and to awaken without any gear, two of the group woke in a large stone holding cell, which happened to have a dwarvish door, which could be opened by interpreting the magic runes, so the wizard in the group had to read magic and got the runes saying "I open when wet".  The group struggled with this, and in the end I had to intimate they could spit, or find any other body fluid, to touch the door with.

When it opened the stone unblocked the noise of the third party member being tortured, the free members burst down the door and a hand to hand fight ensued.

Upon beating the two goblins there, they had a dagger and all were free, they used candles to find their way to a store room where they found their gear had been picked over, but was present, but upon picking up their stuff the door behind them opened and two more goblins plus a goblin boss attack them.

The fight ends, when the boss drops, any remaining goblins ran away, or they were all killed.   In the event they concentrated fire on the boss and burned him down very fast, finding a set of keys, opening the door they found they were in a basement sort off, but two cells had been erected and inside was a trembling figure in one bed, and an Elf Wizard was in the other, she had a friend, an armoured Guinea pig, which would fight for her later.  The other figure though was Bard.

The real Bard, he had been duplicated, the group learn now that the creature in the carriage had actually been a doppleganger.

The elf is called "Eluna", along with Bard they join the party, and Bard explains, this is his mansion, bought for through all the concert ticket sales he's made being a... well a Bard.

He explains the evil cult took over and banished him here, but had sent a note just before for help, that was the note the group got at the beginning.

Leading the group into a corridor the group have to fight flesh eating worms in the dark, then they enter the old kitchens and fight a guard, and finally enter the main hall of the mansion, and there fight two twin swordsmen, who both had to die together, the doppleganger and the boss "Bolvier", the cult leader.

A great moment came when the Wizard in our party grasped she could do anything, and came up with using a belt knife to cut down a tapestry and having it float over the heat of one of the twin swordsmen and wrapping him up whilst they fought the other characters.  This was the first time the group benefited from any form of crowd control, and it was epic.

The session ended with the group taken into the mansion to relax and recoup with Bard, Eluna sets off to report her troubles to her Priestess bosses.

The third session was meant to happen last week, but one of our members, the youngest, was not being a very good girl, she was very annoying and not bothering to play Scrabble... And so because she couldn't be arsed to play Scrabble... She wasn't allowed to play D&D.... Despite her moaning "But D&D is the best game ever".... yeah, it would have been if you'd have applied yourself to Scrabble.

Tuesday, 5 May 2015

Pathfinder

There's not a log going on, save to say I've been reading and following the Pathfinder RPG game rules.  Which are essentially D&D v3.5 rules. Message ends.

Friday, 24 April 2015

Dungeon Crawler - C++/SDL - Loading Maps

Very quick update, I've been taking the XML Maps from the Editor in it's current form and loading them into the actual game now, this has required a change of several subsystems inside the Grid/Map loading code.

The most important change has been caching one copy of each image, so minimising memory use, and then customising them at a surface level to add walls, drawing all this once and then just rendering the one single image we hold in RAM, whilst the rest of the images can be dropped out of memory to again free more resources.

Anyway, here's a screen shot of the game (background left) with the map editor open showing the map in design.


Path finding of course routes around the walls, and tiles can be toggles as blocking or not, opening up the ability now to add doors or even hidden/false/magic doors.

Thursday, 23 April 2015

Dungeon Crawler - C++/SDL/C# - Map Editor Updates

So, the Map Editor, I made a brief mention of progress on Tuesday's post, but I've refined a few things, and I'm ready to show you some screenshots of how things look...


Here we see a tile set being imported, and placed down, then I've laid a set of dividers, a divider is a none-crossable wall like structure, but it lets us use a single square as a wall, rather than using a blank gap.


So, hopefully you can see that we can enclose spaces without so much blank black squares.

Which then leads to more complex structures:



The next item I'm literally coding now is a door, which will go into places as highlighted in red here...


Supporting single spans, or double spans...

And of course, once all this is designed into the map editor it's going to be ported into the game itself to give us the basics of the Adventure loading & walk through.


Wednesday, 22 April 2015

Dungeon Crawler - C++/SDL/C# - Representing Stairs Challenge

So, the game, at the moment is totally top down 2D, there are no camera angles, no isometric perspective, it's just all looking straight down at the canvas below.

So, one challenge is how to represent depth, I've seen some art styles showing walls rising from an edge of a square and away to the centre, so it looks as though it's a wall climbing up towards the camera.

And, this effect is built in, not by the game, but by loading the pictures/images from disk, so anyone can draw like that.

One thing I can't do however is I can't draw, not very well, not on a computer.

And the next challenge facing me is how to represent stairs, if I can't do it easily with a single tile, do I need to make stairs which take up several tiles and have isometric effects to them, or do I need to increase the size of the tiles?

You see, there are options, which work to represent top down stairs...



That looks right to me, but it's done with shadows, alpha and importantly to work it all needs more than 70x70 resolution...  The same trick for me, using gradient brushes, at 70x70 comes out like this:



It's not the same is it?... No, I didn't think so.

Other options are to make stairs as I would with a biro on a table top map:



But, again this needs more pixels per tile, and definitely needs more than one tile.

Stairs going down are also a challenge, they need just as good a resolution which my tiles don't provide:



From http://www.cartographersguild.com/showthread.php?t=22407

Suggestions on a postcard please.

Thursday, 16 April 2015

Dungeon Crawler - C++/SDL - VLOG 3

The third VLOG in this on going series, see's me finding I've unexpectedly broken token collision detection.... But I'm; at last; loading maps from the MapEditor.

I've also fixed scaling issues which were causing the map to scale to the screen when it was a map which was intended to be smaller than the view area of the screen.



Update 3.5


Wednesday, 15 April 2015

Dungeon Crawler - C++/SDL/C# - Map Editor

My previous post today said, what have I been doing, You could imagine, not a lot of code, I've not been able to think... But today, I've thrown myself into the development again, and set about sorting out a map editor of some use.

I simply have to do something to distract me from my grief.

So, we can select the size of map we're working on, either from the pre-set sizes, or just entering a number:


Then we can select the brush we're using to draw tiles:


Adding Tiles:


We see the mouse over a tile with the orange surround:


Painting the brush is by pressing "1" for the first brush, and I'm going to add 2, 3, 4, etc. so you can have up to 9 brushes selected, basically the numpad will be key, with the floor tile (or even a random set of tiles) being numpad 5, and the 1 2 3 4 6 7 8 and 9 keys being the corners and walls, letting you quickly build a room or space.


You can also clear a tile with Delete...


The development efforts on this may soon be renamed "Spirit of Dude Development"...

Saturday, 11 April 2015

Dungeon Crawler - C++/SDL - VLOG 2

Today, you see how I have identified a bug in the token drawing (since fixed) and I show you the integrated path finding in the game engine itself.

The rest of today is going to be all about map editing and selecting/loading a map into the engine, rather than that damn blank map of stone slabs.


Friday, 10 April 2015

Dungeon Crawler - Making Tokens Follow Routes

The last two days of game development time have been dedicated to the test bed for routing, and that's all working nicely now.

So, I'm starting to look at the game itself, to decide how best to implement routing into the game.

My first step therefore has been to make the moving game tokens follow a set of steps... Each step being a point within a queue of points, called a route.




Each time the token comes to rest, from the previous step, it looks for a new step to move onto, or it's done moving...


At the moment this is not a proper route, next I need to make the route be calculated, just as it is with the path finding test bed.

But again, I need to load the blocked (adventure) map into the actual program first.

--- Please also note, I just happen to have called this project "Dungeon Crawler", since starting it I've seen videos around of a different project in the same vein... We're not related projects.

Thursday, 9 April 2015

Dungeon Crawler - 2D Path Finding

I've had to create a test-bed piece of code for the path finding, so this means there's been no changes to the game side of the code, all the work I've been doing on things over the last couple of days has been about the path finding and it's been in this test-bed application.


So, the application lets me see the grid (or graph if you're a mathematician), I can select the start point, the end point, set blocked grids and then ask it to calculate a route.

The algorithm I've used is an A* algorithm, but a greedy one, and then I've added back-tracing to allow it to get out of dead-ends (such as in a room with a narrow opening) and finally added simplification to the end result route.

The calculation of the route and back tracing is automatic, the simplification however, I've made a manual operation, so I can see how the routes come out of A* before I alter the list of plotted points.

Without the back tracing this is how it could get stuck:


And now, it back traces to the next best nearest grid point to continue the route without getting stuck or going over the points it's already found got it stuck:


And finally, I can apply a simplification to that solution:


I'm now pushing it further, asking the test-bed to work it's way around simple dungeon style rooms, here we see the route from inside one room, down a set of halls and into a cell within another area...


Simplify this result:


And it's quite neat.

The test-bed needs some more features, such as loading/saving the background blocks, making the start of a rudimentary map editor!

Once I'm more happy with the algorithms and heuristics I'm using, then I'll start to tidy the code and then port it into classes for use in the Dungeon game... And finally I'll start to make the movement routines take the list of points to go between...

Note: Since writing this draft, I've continued the work and testing... Only to find a strange problem, which was working, but I've somehow broke, here we see a grid... The Route can continue, but it just stops...




Hmmm, what have I done wrong?


-- Addition --

Since posting this last night at half six, I worked out the bug resulting in this dead end problem above, here's the result now:


Then simplification run on this route:


The challenge now is to simplify, clean up and better document this code.  Then to port it to clear easy to maintain C++


Wednesday, 8 April 2015

Dungeon Crawler - C++/SDL - VLOG 1

For Part Two, click here.

This is my first VLOG on the topic of my dungeon crawler... Sorry about the echo in the last couple of minutes, no idea how that happened:



My first (ever) VLOG about the development of my 2D Dungeon Crawling Game & supporting classes in C++ with SDL.

Sorry about the echo after around 11 minutes - I have no idea how that started to happen, and I will not let it happen again, it was not spotted until I had uploaded this.

For more information about this project, and other projects I'm working on, the best place to check out is my blog at http://megalomaniacbore.blogspot.com

*Tutorials Used*


*Libraries*

See my other videos for more information on using Boost.


*Pathfinding*


Monday, 6 April 2015

Using Java & Eclipse to Write a Game - Pt 3

The third week of our Java Game Tutorial, and hopefully you've had a lot of time to play with the growing Dots, the 2D draw, maybe you've had a play and made the rendering loop draw other things...

Because this week, we're going to look at something dungeon related, the grid or map, we're going to make our play area.

First things first though, we no longer want the background to react to clicking and go red, so we need remove the "m_LeftButton" flag, and it's used in the mouse pressed & mouse released functions.  Then we need remove it from the rendering loop.


We draw the background all black now, because we can't "see" anything.  In a moment we'll draw a grid of squares, or tiles, which we will move characters around on; but later we'll also be looking at how far those characters can see, and so how much of the black they push back.


Of course, drawing a grid so, we also don't want those seeds to grow, but we'll only stop them planting, so we can go to the mouse pressed function and just comment out the call to "AddSeed".


Commenting out means we leave the code in place, but the compiler when it builds the code into a program will skip that line.  To make it a comment therefore we add "//" at the from.

There are other ways to do comments, but for now stick to this method only, we'll cover the pit falls of other problems.

So, onto the new Grid code, lets create the Grid class....


And give it a name...


And so we get the new text file as a tab to edit...


Next time we create a class, I won't be documenting all these parts of the process again, I'll just say we're creating some named class.

So, what do we need to know about our grid?.. Well a size, so we need a width and a height, then we need to pass these values into the constructor.


To draw the grid we need to pass the Graphics2D context to it, do we'll add that function, and how about an Update function too, so we can animate things on the grid later.


The problem now is what to draw?... Well, we've not defined any data for the Grid yet, so how about we create a new class called a Tile.

Inside the tile, what is is going to represent?.. Well It's going to be a square on our grid... Which characters stand on, lets say they stand on a stone floor, the tile need to have a type inside it, something to tell us it is meant to represent a Stone Slab...


So how do we do this?  Well, there are things called "enums" which are a bit like a new type for us to use, and they are all the same "type" datawise, but they can have different labels inside, so we might have "TileType" and inside "Wall", "Floor" and so forth.


We've already seen one enum used, this was the "java.awt.Color", which has different colours inside.

We'll create our "TileTypes" enum, as follows:


And then we'll just add two types, "Blank" and "UNKNOWN".  We will always keep "UNKNOWN" as the last type in the list.


We can now use the "TileTypes" enum just like any other type in the language, such as "int" or "string" or boolean!

In our code though we also want to draw the tile, and perhaps also update the time, so we'll add those two functions now...


We need to be a little coy now, we can't draw a tile yet, because we don't know where it is on the screen, nor how big it is, but lets say that a tile is going to always be a fixed width and height, we can define those as constants, or finals...


Included in that we now have a top and a left for the tile, and can now define what we draw...


This is a new structure, where we can quickly jump down to the code we want to act upon, based on the value of the TileType.  So, when this is "BLANK" from the enum, we jump to set the colour to black, otherwise the colour is white.

Now we just draw a square...


Jumping back to the grid we now need a set of tiles to draw, for this we'll use a multi dimensional array, so each entry on the first set of the array is another array.... Meaning we can have "m_Tiles[1][3]" and it will go to that tile!


Of course we've just created the space for tiles, we've not gone through and set each tile to any type...


But, we need to know where to place each tile... This is going to be based on the size of the tile... 


The first thing you should see with adding this code change however, is that from inside the "Grid" you can't get at the two constants "c_Width" or "c_Height" inside the "Tile"... How come my code shows no error?

Well, I have gone back to the Tile and I've set those two constants "Static", this means I can access those as values of the type or class without actually needing to be inside a copy of the clas (it means more than that, but for now, roll with it).


Right, then... We have a grid of tiles, the tiles will draw themselves, lets flesh out the grid draw function...


And the update function...


Finally, jumping back to the main window, we now need a grid... lets make it create as a 10 x 6 area... And add a call to draw it...


Then to draw it...

Lets have a look what that looks like...


Everything is black... I've cleared the background to black, and I've made the tiles draw black... Hmmm, what should we do?

Well, I don't want the tiles to worry about drawing their outside or border, I want the grid to draw the borders, so we can turn them on or off later, and so that we can highlight the selected tile on the grid.

Lets jump to the Grid drawing function and make it now draw the borders....


How does that look?...


Was that what you were expecting?... It was what I expected, but perhaps you didn't see this coming?... What's going on?...

Well, as we move across the grid we draw and redraw the tiles, so each tile draws a black square, then the grid draws the border, the next tile then draws it's black and they overlap by a pixel, because we've not spaced them out.

So that black next tile scrubs out the border of the previous drawing.

To get around this we need to do one of two things, or eventually just move the tiles, but for now, we jump back to the grid class and change the border drawing...


So, we draw all the tiles, then draw the borders, this means we go over the loops twice, but does it fix our drawn image?...


Yes!

This is a good lesson to learn, we've done two passes over the same loops, to draw one set of tiles.  Avoiding too many repeats, especially as the data/grid size gets bigger, is important.

Still, our tiles don't look how I really want them, I'd like them to be a bit larger.  This is easy to fix, we just jump to the Tile code and change the width and height constants.

Because we've used constants and made them static for use in all the other classes wanting to know the size of a tile, we can now just change the constants once, rebuild the code, and it'll all fall into place... Lets try some different sizes.

Or...

I like that last size, so we'll stick with that... But we've already got another problem, the tiles to the right and bottom rows are now slipping off the screen.

I'm not going to worry about that directly, we next week we're going to look at scrolling the view around to see huge maps, 100x80 or 1000x800!

However, to help me understand what's happening now, and what might happen when we scale up to scrolling, I'm going to add some text to tell me the index of each tile.  This means drawing text.


First off, from the existing Clear Tiles in the grid, we now want to just tell the Tile the X and Y position, we'll let the tile itself calculate it's intended left and top inside.

And the Tile itself...


Running this code up now, gives us the same as the last run, but now we can jump to the Tile Draw and put the text for the "m_X" and "m_Y" values into the tiles top left corner!


So, we set the colour to yellow, build the coordinates as a string, and draw them just down and slightly to the right inside the tile.


Now, when we come to scrolling the grid around we're fore armed with the numbers of the grid in the tiles so we'll know where we are.

Final code clean ups, I'm going to go into the MainWindow and define two final static constants for the grid size to use, so we'll not have 10 and 8 coded directly into the MainWindow call to "new Grid", instead we'll have these two new constants.

We've changed the size of the tiles, we've can now change the size of the grid... Why not have a few experiments...

We can also go to the Run function and remove the "Starting Run" and "Ending Run" calls.  And the same println call in the main function, just to tidy up our code.  We can remove the rest of the Seed & Dot stuff as well...

---- MainWindow ----

package display.display;

import java.awt.Canvas;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class MainWindow extends Canvas implements MouseListener, WindowListener 
{
// The minimum Resolution Values
private final int c_MinWidth = 800;
private final int c_MinHeight = 600;
// The default grid size
private final int c_GridWidth = 100;
private final int c_GridHeight = 80;
// The master game loop exit flag
private boolean m_GameRunning;
// The seeds of our clicks
private java.util.Queue<java.awt.Dimension> m_Seeds = null;
// The list of expanding dots
private java.util.ArrayList<Dot> m_Dots = null;
// The window frame
private javax.swing.JFrame m_WindowFrame;
// The drawing strategy (refreshing)
private java.awt.image.BufferStrategy m_Strategy;
// The grid
private Grid m_Grid = null;
// Constructor - can be private, we only internal
// members of this class (i.e. main) will be calling
// to create a main window.
private MainWindow ()
{
CreateWindow();
AddPanelAndCanvas();
CreateBufferingStrategy();
m_Grid = new Grid(c_GridWidth, c_GridHeight);
}
// Create the buffering strategy
private void CreateBufferingStrategy()
{
this.setIgnoreRepaint(true);  // Ignore the windows paint event
this.createBufferStrategy(2); // Two buffers, one on and one off screen
m_Strategy = this.getBufferStrategy();
}
// Adds a panel to the JFrame, and this panel
// fills the whole area of the window, into that
// we then add our Canvas, which is "this"
private void AddPanelAndCanvas()
{
// The panel in the middle area
javax.swing.JPanel l_Panel = (javax.swing.JPanel)m_WindowFrame.getContentPane();
l_Panel.setPreferredSize(new java.awt.Dimension(c_MinWidth, c_MinHeight));
l_Panel.setLayout(null);
// Set our Canvas properties of size
this.setBounds(0,  0, c_MinWidth, c_MinHeight);
// Add the canvas to the panel
l_Panel.add(this);
}
// Create the Window - we're going to use Swing
private void CreateWindow()
{
m_WindowFrame = new javax.swing.JFrame("Dungeon"); // This is the window title text 
m_WindowFrame.addWindowListener(this); // Adding "this" to the frame
// means our MainWindow code as
// it is running will receive the
// Window events, like close & move
// Direct the mouse events to the
// canvas itself
this.addMouseListener(this);
m_WindowFrame.setSize(c_MinWidth, c_MinHeight);
m_WindowFrame.setVisible(true);
}
@Override
public void windowActivated(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void windowClosed(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void windowClosing(WindowEvent arg0) 
{
// TODO Auto-generated method stub
m_GameRunning = false;
}

@Override
public void windowDeactivated(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void windowDeiconified(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void windowIconified(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void windowOpened(WindowEvent arg0) 
{
// TODO Auto-generated method stub

}

@Override
public void mouseClicked(MouseEvent arg0)
{
// TODO Auto-generated method stub

}

@Override
public void mouseEntered(MouseEvent arg0)
{
// TODO Auto-generated method stub

}

@Override
public void mouseExited(MouseEvent arg0)
{
// TODO Auto-generated method stub

}

// Adds a seed to the list of places the
// mouse was clicked, since we last
// updated
private void AddSeed(int p_X, int p_Y)
{
if ( m_Seeds == null )
{
m_Seeds = new java.util.LinkedList<java.awt.Dimension>();
}
m_Seeds.add(new java.awt.Dimension(p_X, p_Y));
}
@Override
public void mousePressed(MouseEvent p_Event)
{
// Left click
if ( p_Event.getButton() == MouseEvent.BUTTON1 )
{
//AddSeed(p_Event.getX(), p_Event.getY());
}
}

@Override
public void mouseReleased(MouseEvent p_Event)
{
if ( p_Event.getButton() == MouseEvent.BUTTON1 )
{
}
}
// Add a Dot
private void AddDot(Dot p_newDot)
{
if ( m_Dots == null )
{
m_Dots = new java.util.ArrayList<Dot>();
}
m_Dots.add(p_newDot);
}
// Update the scene
private void Update(long p_Milliseconds)
{
// There are seeds
if ( m_Seeds != null )
{
// if we have seeds, add them
if ( !m_Seeds.isEmpty() )
{
// Dequeue each seed point and
// create a new expanding Dot
java.awt.Dimension l_Location = m_Seeds.remove();
Dot l_newDot = new Dot((int)l_Location.getWidth(), (int)l_Location.getHeight());
// They maybe called Width and Height, but
// really we're using them as two numbers...
AddDot(l_newDot);
}
}
if ( m_Dots != null && !m_Dots.isEmpty() )
{
// For each dot, update them
for (int i = 0; i < m_Dots.size(); ++i)
{
m_Dots.get(i).Update(p_Milliseconds);
}
}
}
// Draw the dots
private void DrawDots(java.awt.Graphics2D p_Graphics)
{
if ( m_Dots != null && !m_Dots.isEmpty())
{
for (int i = 0; i < m_Dots.size(); ++i)
{
m_Dots.get(i).Draw(p_Graphics);
}
}
}
/// The function we "run" from the main
/// function, to go into a loop, rendering
/// the game
private void Run ()
{
m_GameRunning = true;
// Game timing/update delta
long l_Time = System.currentTimeMillis();
long l_now;
long l_delta;
while (m_GameRunning)
{
// Get the time now, and work out the difference
l_now = System.currentTimeMillis();
l_delta = l_now - l_Time;
// Only if we are at the time, draw
if ( l_delta > 33 )
{
Update(l_delta);
// Get the graphics into which
// we can draw
java.awt.Graphics2D l_Graphics = (java.awt.Graphics2D)m_Strategy.getDrawGraphics();
// Clear the map background as black
l_Graphics.setColor(java.awt.Color.black);
l_Graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
// Draw the grid
if ( m_Grid != null )
{
m_Grid.Draw(l_Graphics);
}
// After the update of the background colour,
// call to draw the dots
DrawDots(l_Graphics);
// Show this frame of graphics
// we've drawn
m_Strategy.show();
// because we did a draw, set time to now
l_Time = l_now;
}
Yield();
}
}
// Quick and dirty yield function, to
// release the CPU time whilst in the
// run loop
private void Yield()
{
try
{
Thread.sleep(2);
}
catch (Exception e)
{
System.out.println("Exception [" + e + "]");
}
}
public static void main(String[] args)
{
MainWindow l_Instance = new MainWindow();
l_Instance.Run();
}
}

---- Dot.java ----

package display.display;

public class Dot
{
private final int c_MinimumSize = 1;
private final int c_PixelsPerSecond = 2;
private int m_OriginX, m_OriginY;
private long m_Age;
public Dot(int p_X, int p_Y)
{
m_Age = 0;
m_OriginX = p_X;
m_OriginY = p_Y;
}
public void Update(long p_Delta)
{
m_Age += p_Delta;
}
public void Draw(java.awt.Graphics2D p_Graphics)
{
// Calculate the radius
int l_RadiusInPixels = c_MinimumSize + ((int)(m_Age/1000)*c_PixelsPerSecond);
int l_half = (int)(l_RadiusInPixels / 2);
int l_startX = m_OriginX - l_half;
int l_startY = m_OriginY - l_half;
p_Graphics.setColor(java.awt.Color.pink);
p_Graphics.fillOval(l_startX, l_startY, l_RadiusInPixels, l_RadiusInPixels);
}
}

---- Grid.java ----

package display.display;

public class Grid
{
// Size
private int m_Width, m_Height;
private Tile[][] m_Tiles;
// Draw options
private boolean m_DrawBorders = true;
// Constructor
public Grid(int p_Width, int p_Height)
{
m_Width = p_Width;
m_Height = p_Height;
m_Tiles = new Tile[m_Width][m_Height];
ClearTiles(TileTypes.BLANK);
}
private void ClearTiles(TileTypes p_Type)
{
for (int y = 0; y < m_Height; ++y)
{
for (int x = 0; x < m_Width; ++x)
{
m_Tiles[x][y] = new Tile(p_Type, x, y);
}
}
}
public void Draw(java.awt.Graphics2D p_Graphics)
{
// Just draw the tile contents
for (int y = 0; y < m_Height; ++y)
{
for (int x = 0; x < m_Width; ++x)
{
m_Tiles[x][y].Draw(p_Graphics);
}
}
if ( m_DrawBorders )
{
// Draw all borders
for (int y = 0; y < m_Height; ++y)
{
for (int x = 0; x < m_Width; ++x)
{
// Draw a border
p_Graphics.setColor(java.awt.Color.gray);
int l_Left = x * Tile.c_Width;
int l_Top = y * Tile.c_Height;
p_Graphics.drawRect(l_Left, l_Top, Tile.c_Width, Tile.c_Height);
}
}
}
}
public void Update(long p_Milliseconds)
{
for (int y = 0; y < m_Height; ++y)
{
for (int x = 0; x < m_Width; ++x)
{
m_Tiles[x][y].Update(p_Milliseconds);
}
}
}
}

---- Tile.java ----

package display.display;

public class Tile
{
// The width and height of a tile is fixed
public static final int c_Width = 80;
public static final int c_Height = 80;
// The type of the tile
private TileTypes m_Type;
// The X Y of the tile
private int m_X, m_Y;
// The top left corner position of the tile
private int m_Top, m_Left;
// Constructor
public Tile(TileTypes p_Type, int p_X, int p_Y)
{
m_Type = p_Type;
m_X = p_X;
m_Y = p_Y;
m_Top = m_Y * c_Height;
m_Left = m_X * c_Width;
}
public void Draw (java.awt.Graphics2D p_Graphics)
{
switch (m_Type)
{
case BLANK:
p_Graphics.setColor(java.awt.Color.black);
break;
default:
p_Graphics.setColor(java.awt.Color.white);
}
p_Graphics.fillRect(m_Left,  m_Top, c_Width, c_Height);
// The X Y Text
p_Graphics.setColor(java.awt.Color.yellow);
String l_Coords = "[" + m_X + ", " + m_Y + "]";
p_Graphics.drawString(l_Coords, m_Left + 5, m_Top + 15);
}
public void Update(long p_Milliseconds)
{
}
}

---- TileTypes.java ----

package display.display;

public enum TileTypes
{
BLANK,
UNKNOWN
}