Tuesday, September 6, 2011

Connecting the map editor and the tile selector



Walking into a late-nite session, the mission is to enable the
selection and placement of tiles into a dungeon, using the tile
selection panel created and placed in the designer.


To accomlish this, the initial plan was to, first, add logic to the
RHD_MapDisplay, which would allow replacent of tiles on the
map. The next step would be to adjust the mouse listeners for
RHD_MapDisplay, which would call the tile replacement
routine.


Some design flaws were discovered with the Dungeon class, as there
were no methods attached to allow the replacement of an individual
tile at a given point. This and other minor adjustments were made
while preparing to write the tile replacement method.


With the minor touch ups made, creating the method within the
RHD_MapDisplay was a breeze.


protected void replaceTile(Point position, Tile newTile) {

dungeon.replaceTile(position, newTile);
}


Problems struck soon after authoring this method. Because the two
components, RHD_MapDisplay and the RHD_TileList,
were not direct communicators with one another (though they share the
designer form). Some way had to be found to allow replacements
onto the map display, using the tile list.


The plan involved in the response to this problem involved the catch-all
'everything manager' for the game designer, RHD_StateManager.
A new property was added to the state manager to keep track of the 'currently
selected' Tile. Whenever the user chose a tile from the
RHD_TileList, it would now call RHD_StateManger.setTileInMemory
(tile)
.


With a mechanism in place to keep track of the users desired tile,
it was now possible to call the tile replacement routine without any fuss.
Callers would simply invoke the RHD_StateMangager.getTileInMemory()
method when calling the tile replacement method.



There was mixed success when the work was first done.
For some reason, new tiles were being represented by white, empty
squares. By simply adding a command to reload the dungeon map, this
problem was solved.


It later was made clear that relaoding what may
become a very large dungeon map, each time a single tile was replaced,
was probably not a wise plan. A much more efficent means of map updating
was found by simply checking to see if the current tile's image
resided in the map's memory. If it did not, it was added to the memory
bank (a HashMap) where it could be referenced in the
future.



protected void replaceTile(Point position, Tile newTile) {

dungeon.replaceTile(position, newTile);

// Load the tile image into the imagemap, if its not there
// already.

if (!imagemap.containsKey(newTile.getImagepath()))
{
try {
imagemap.put(newTile.getImagepath(),
FileBroker.readImage(newTile.getImagepath()));
}
catch (IOException ex) {
Logger.getLogger(RHD_MapDisplay.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}


The results, for about an hour or less worth of work, were stunningly
successful. With the capability to plug tiles in willy-nilly with the
click of a mouse, this project just picked up a lot more power than it
had when it started.



There is still a whole ton to do, just to get mapping system done, both
mechanically and in the UI. The UI will receive added functionality
to place entities within tiles. Then the polish will start to be added
into the user interface, allowing use to navigate using menus like any
other decent software. The next step will be to get off of the 'test' start
crutch, and to store our game envrions and entities in files.


Be sure to check in for further updates! And don't forget to check out
the code site! http://
code.google.com/p/project-hardin
is the place to check out source
code and get project details.


Happy Coding!


Timon




Monday, September 5, 2011

Setting up a List for tile selection within the dungeon editor

The mission on this run was to create and install a list of tiles to the user on the map designer. These tiles represent the tiles that can be used to edit the map on the display.

The list in question is build, specifically, to be used in conjunction with the display made during the last run (see the most recent blog), so it would have to be displayed convieniently on the same form as the map editor display.

The actual functionality of this component was not a goal of this coding run, simply to create a list that displayed the tiles in a desirable way, and to get it onto the display form in a convienient, extensible fashion.

The first step was to figure out how to create a list whose style I could control. After a little reasearch looking up the javadoc for JList http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JList.html

it only took a minute to the contraption that Sun/Oracle had designed to allow coders to accomplish the very task I set out to do. I simply had create a new class to act as the cell renderer for this list.

While the JList object is complicated, and has layers of controls deeper than what's needed here, one needed only to grasp how the JList organizes its data, as well as how it displays that same data. Here is the essential breakdown of the JList, for purposes of this task: displaying customized data in a sane, rational way.

The JList basically uses an internal data structure that can use any type of Object as it's data member - of course, each of these data members must be of the same type - but as long as they derive from Object (duh), you're golden.

After loading in your objects (which can be done in the JList constructor, feeding in a simple Object[]), all that remains is to create the JList's cell renderer to interpret these objects in whatever way pleases you.

The following describes the procedure used for accomplishing this task, as well as displaying the new list on the main display:

EXTEND JLIST

By simply extending JList into a new class (RHD_TileList), a space was created to create the cell renderer, exclusive to this list, and add any other specialized members or methods for this specifiic list. It also allowed for customized stylization of the list itself, within the constructor body.

Next, within the RHD_TileList class, and Inner Class was created that implemented ListCellRenderer (the object responsible for turning each data item in the JList into a selectable display item) and extended JLabel. JLabel was used as an extension to simply display within the list - this will be explianed in more detail shortly.

The ListCellRenderer uses only one method that must be overwritten, public Component getListCellRendererComponent(), which returns the Component which will be used to represent each given list item. This method is called once for each object within the JList, so the code within this method must be able to generate Components dynamically based on their content.

JLabel was extended into ListCellRenderer because this made it easy to generate the entire Component within the context of JLabel (an ideal Component model for display on a list), and then return 'this' to the JList when finished.

Because of the way this method was designed, it is possible to know whether or not the list is enabled, the list-item in question is selected by the user, as well as having access to the parent list itself and the object representing the data.

Here, with full documentation, is the code used to represent this new extension of JList:

/** * A specialized JList offering a selection of tiles to the user * for map making. * * @author timon */ public class RHD_TileList extends JList{ /** * CONSTRUCTOR (default) * * Makes a call to parent (JList) */ public RHD_TileList() { super(); init(); } /** * CONSTRUCTOR * * Makes a call to parent (JList), and loads in the array of tiles * as the data. * * @param tiles * An array of tiles */ public RHD_TileList(Tile[] tiles) { super(tiles); init(); } private void init() { setCellRenderer(new TileListCellRenderer()); setEnabled(true); setFont(new Font("Arial", Font.PLAIN, 11)); setPreferredSize(new Dimension(150,400)); setBackground(Color.WHITE); setBorder(new LineBorder(Color.black)); } class TileListCellRenderer extends JLabel implements ListCellRenderer { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { // Get the tile from the parameters Tile tile = (Tile) value; ImageIcon icon = new ImageIcon(); // The display icon //Get the display name from the tile String displayMessage = tile.getTileName(); // Get the icon from the tile try { icon = (ImageIcon) FileBroker.readTileIcon(tile.getImagepath()); } catch (IOException ex) { } // Set the displayed text setText(displayMessage); // Set the displayed icon setIcon(icon); // Enable this selection setEnabled(list.isEnabled()); // Draw a border according to this item's selection status if (isSelected) { // Set blue border around selected item setBorder(new LineBorder(Color.blue)); // Set background to blue highlight on selected item setBackground(new Color(220,220,235)); } else { // Set border to match list background on un-selected item setBorder(new LineBorder(list.getBackground())); // Set background to match list background on un-selected // item setBackground(list.getBackground()); } // Share the same font with the rest of the list setFont(list.getFont()); // Set the preferred size of the list as a display setPreferredSize(new Dimension(100,20)); // Set opacity to true to allow background colors to take hold setOpaque(true); // Return this item back to the list manager return this; } } }

Finally, in terms of placing this new List on the designer display, it was decided that a new Tab Panel would be placed to the right of the map editor on the same form. A blank panel was added to the tab panel, creating a new 'tab page' (NetBeans knows to do this automatically). Within this tab page, I placed a JScrollPane.

After this point, there was an attempt to extend the list into a bean, and then place that Tile List Bean within the scroll pane. After complications and time consumption that came with waiting for the bean to load, inappropriate settings, etc, a change in plan was made, and probably for the better.

It was very simple just to use the JScrollPane.setViewportView(Component view) method, for both initialization and updating. An extra method was added to the designer: public void loadTileList(Tile[] tiles). Another method was added to the state manager (in charge of delegating commands througout the Map Designer): public static void loadAvailableTiles(Tile[] tiles). Now with these methods, the state manager can be called from anywhere and load in a new set of tiles into the program memory, and hence into the list being displayed on the designer.

After these updates, a new test start garnered the following visual results:

The new list can be seen within the tab panel labeled "Basic" on the right of the map designer display.

Friday, September 2, 2011

Setting up the Map Display user interface - Session 1


I started the day with the idea that I would make the tile listeners for my map designer.  The map designer, which allows the user to create customized dungeon maps, needs an additional layer that makes each tile able to react to user interaction.



My first inclination seemed reasonable, and I began coding on it pretty fast.  Tile-unit sized panels would be made with a mouse motion listener and mouse click listener.



After the building of the listener progressed for a while, it started to become apparent that this plan might not be as feasable as once thought.  Because of all of the listening threads I'd constantly be running, the program would cause irresponsible, even if insignificant, strain on the system.

The next idea involved creating one listener, matching the size of the map it overlies, that is intelligent enough to know which tile the mouse is pointing at.  After all, this was a much more rational, and managable, approach.




The first step was to extend my MapDisplay Panel.  (The MapDisplay is in charge of displaying the game map.)  The next step would be to make a special version of this map, exclusively for the map designer.  This specialized MapDisplay would hold the one huge listener mentioned above, and process the map it was holding.

Before rip-roaring into this module, the first step was to figure out which utilities were likely to be used again.  The decision was made to add conversion utilities to a standard utility class RH_Utilities that would convert pixel-unit spaces into grid-coordinates, and vice versa.


With these conversions made on the fly, the focus returned to the new specialized MapDisplay (called RHD_MapDisplay ).  After building the methods to do the math, it was a breeze having the graphics layer paint a green tile around the currently selected mouse area, with a little simple math.

protected void paintComponent(Graphics g) { super.paintComponent(g); if (!(activatedTile == new Point(-1,-1))) { // Draw a green sqaure around the currently selected tile g.setColor(Color.GREEN); g.drawRect( activatedTile.x * rougehack.RougeHack.getGridWidth(), activatedTile.y * rougehack.RougeHack.getGridHeight(), rougehack.RougeHack.getGridWidth()-2, rougehack.RougeHack.getGridHeight()-2); } }

With that routine finished, the next step was to add the listener to update the current grid-point in focus, and to keep that grid point as a property - in case in comes in handy in the future.

At this point, the setup was *almost* done.  Because this new smart-panel was placed inside of a JScrollPane , the *scroll pane* was the active listener, and muted the new smart panel.  Luckily, this was not difficult to get around.

By adding a listener onto the scroll pane, and then creating a public method in RHD_MapDisplay which would allow outside entities to invoke RHD_MapDisplay's mouse listener, the scroll pane allowed the user to get right through to the smart panel, by calling the smart panel's mouse listener through it's own.  This worked better than expected (some extra work was anticipated allowing the user to scroll and still be accurate about the mouse conversion - luckily there was no such work needed).


After some tweaking of the calculations used to determine where to put that blasted green box, the end result came out nicely:



This is where my progress for this portion of Issue 13 (Upgrade User UI to accept mouse input) , which is still in progress, ceases for the moment.

Thursday, September 1, 2011

Introduction to Project Hardin

Project Hardin is a software entertainment tool, allowing paper-and-pencil rpg players to take their games online, in a fully customizable, fully randomizable, dynamic, simple and fun environment.  The project is written in Java, and while it will it may extend to the browser via J2EE someday, for today, it is console based with a planned p2p connection.

Initial requirements overview may be found here: http://code.google.com/p/project-hardin/wiki/Requirements?ts=1314896955&updated=Requirements

The project itself can be found at http://code.google.com/p/project-hardin/

My name is Timon Davis.  I am a 4th year student of Software Development in Seattle, Wa.  I started Project Hardin with the intention of making something cool that I think people will use.  I also started this project for the experience of moving through the SDLC.  Budding java developers are encouraged to join the team.

The project bears the name of Sydney's cultish accomplice in Square Soft's Vagrant Story, John Hardin, for no particular reason.