Thursday, January 9, 2025

It's Time to Resume the Game

Hey, everyone!  I'm back!  It's really me and I'm not a ghost.

I wanted to tell the story of why I was away for so long and what happened to derail my game development career, but I don't feel like writing that much and I doubt more than a handful of people would read it anyway, so I'll just tell you the short form.

The short version: After presenting at a symposium in 2014, I put my game dev work on pause while I returned to graduate school to pursue a Ph.D. in software engineering. I got through all of my coursework quickly and successfully (straight A!), and then I started my dissertation. Around that same time, my employer at the time went through a rather tumultuous reorganization. I ended up being promoted into an impossible and thankless administrative position which made it extremely difficult to work on my dissertation.  So I left that job and took another one which promised more time, flexibility, and support to complete my degree.  However, after only being there for a few months, I was promoted into a leadership role that once again ate up all of my time and energy, leaving none for my research...or anything else.

In a nutshell, I paused my game dev work to get a Ph.D., and then abandoned that, too, so I was left with neither.

But last summer, exactly ten years since my last post to this blog, I decided to return to my passion. Like pressing the trusty Continue button, I'm resuming my life and work as a game developer.  Last summer, I went through a major growth sprint as I started rebuilding MHFramework from the ground up. Now, on winter break, I continued building that foundation AND started my first actual game project in over a decade.  More on that later!

The past ten years have been a journey, filled with personal growth, teaching, and exploring other avenues. Along the way, I’ve gained fresh perspectives and ideas that I can’t wait to bring into my game development projects.

Deep down, I always knew I’d come back.  I had to.  I just had to figure out how.  

Now let's get on with this!


Saturday, May 17, 2014

LIME Status Report (05/17/2014)

Ladies and gentlemen, LIME 4 is go for alpha!  Version 4.0.01A has been released to a small group of testers, and I hope to recruit more as we go.  This will probably be the last of this sort of status report because the focus of the project is now shifting from growth to hardening.

If you'd like to volunteer as a tester, post a comment on this blog entry or email me.

If you're already a tester, here are some important links for your convenience:


Here's a little peek at the current alpha release.
Longtime followers of my work may recognize the assets from the Beltzhian Marauders
gameplay prototypes from ten freakin' years ago!  Am I getting too old for this yet?

Accomplishments
  • Corrected the save location of the New Map dialog.
  • Implemented isometric map modes in both diamond and staggered varieties.
  • Added a function to automatically populate the tile set selector with the tile sets available.
  • Officially reached code complete and entered the alpha testing phase.

Sunday, April 20, 2014

LIME Status Report (04/20/2014)

I should have known better than to congratulate myself on being ahead of schedule last month.  Life got in the way, as it often does, and slowed my progress.  Nevertheless, progress was made, and LIME 4 is now at the point where I wanted it to be three weeks ago.  I'm not going to complain, though, because I'm pretty happy with the way it's turning out.  There are bugs to address, testing to do, some refactoring and optimization to consider, and a couple more requirements to implement, but it's gradually turning into the product I envisioned.

For now, my son, my cat, and myself are the actors, but we're good enough to show that it works!



Accomplishments
  • Designed and implemented the Actor palette.
  • Added a toggle button to the View panel for actors.
  • Modified the high-level file I/O classes to support reading and writing of actor lists.
  • Began to reconsider the relationship between the actor lists and the tile maps.  In short, the tile map view only needs the actor list for rendering, and therefore a composition relationship is unnecessary and undesirable.  Instead, the actor list could be passed as a parameter to the tile map view's render function.  This does add one complication though -- how to load the actor file for a game world.
  • Optimized the core game loop by enhancing the game timer and moving some initialization outside of the loop.

Known Issues
  • Functionality Issues
    • The New Map dialog creates the map files in the app root rather than the data directory.
    • Full-screen mode quit working as soon as I started porting functionality from MHF 2 to MHF 3.  Gotta find out why.
  • Usability Issues
    • If the layer currently being edited is hidden, the view panel gets out of sync with the edit panel.
    • The buttons on the New Map screen's cycle controls are occasionally unresponsive.
    • The tile map view's anchor space doesn't always scale correctly when resizing the editor pane.  I've had trouble reproducing this on command, but it happens occasionally.
  • Performance Issues
    • When the tile ID view option is turned on for large tile sets, the frame rate drops sharply to the point of being unusable.
  • Supportability Issues
    • The keyboard event handler for the Android platform doesn't seem to work at all.  Testing and troubleshooting are in order.
    • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs or dynamically resize a graphics canvas.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.
Next Steps
  • High Priority:
    • Automatically populate the tile set selector on the New Map dialog.
    • Fix the dependency between the view panel and the edit panel.
    • Make the New Map dialog save map files to the right location.
  • Medium Priority:
    • Implement isometric modes.
    • Improve performance of tile ID renders.
    • Test, test, test!
  • Low Priority:
    • Fix full-screen exclusive mode for the PC platform.
    • Update and test WallTileTransformer.
    • Do more testing on FloorTileTransformer to make sure the vertices are right.

Saturday, March 29, 2014

LIME Status Report (03/29/2014)

It was a rough week for finding time to work on this project.  I only managed to squeeze out a few short hours to devote to LIME 4, so the list of accomplishments is brief.  Important, but brief.

The only major additions remaining, aside from the other map modes, all involve adding actors to a map.  That will be next week's priority.  After that, it's just bug fixes, optimizations, and the isometric modes.

Those buttons to the right of the tile palette scroll the palette up and down.
Is it obvious enough?


Accomplishments
  • The tile palette now scrolls in response to the up and down arrow keys as well as its own pair of buttons.
  • Tried a minor optimization to the tile palette render which seems to have saved me a few frames per second.
  • Corrected a mouse mapping problem on the tile palette.  I think so, anyway.  It requires more testing to be sure.

Known Issues
  • Functionality Issues
    • The New Map dialog creates the map files in the app root rather than the data directory.
    • Full-screen mode quit working as soon as I started porting functionality from MHF 2 to MHF 3.  Gotta find out why.
  • Usability Issues
    • If the layer currently being edited is hidden, the view panel gets out of sync with the edit panel.
    • The buttons on the New Map screen's cycle controls are occasionally unresponsive.
    • The tile map view's anchor space doesn't always scale correctly when resizing the editor pane.  I've had trouble reproducing this on command, but it happens occasionally.
  • Performance Issues
    • When the tile ID view option is turned on for large tile sets, the frame rate drops sharply to the point of being unusable.
  • Supportability Issues
    • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs or dynamically resize a graphics canvas.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.
Next Steps
  • High Priority:
    • Add the actor list to the tile map view classes.
    • Add "Actor Mode" to the palette window.
    • Add an actor toggle to the view panel.
  • Medium Priority:
    • Fix the dependency between the view panel and the edit panel.
    • Automatically populate the tile set selector on the New Map dialog.
    • Make the New Map dialog save map files to the right location.
    • Implement isometric modes.
    • Improve performance of tile ID renders.
  • Low Priority:
    • Fix full-screen exclusive mode for the PC platform.
    • Update and test WallTileTransformer.
    • Do more testing on FloorTileTransformer to make sure the vertices are right.

Saturday, March 22, 2014

LIME Status Report (03/22/2014)

Happy birthday to me!  Let it be known that this status report shall be the extent of my work efforts today because I'm taking a day off for playtime and indulgent food.

The main thing I can say about this week's accomplishments is that my testing efforts paid off in a good, long list of defects.  This is a good thing -- it means that my testing accomplished exactly what it should have.

However, I am going to resist jumping in to fix these defects at this point.  I have learned that focus is very important, so I am going to continue to focus on development tasks rather than maintenance tasks for the time being.  That is why my priorities under the Next Steps section are laid out the way they are -- the priority for now is to finish the current growth sprint and put the finishing touches on the user interface.  Once that is accomplished, I will turn my attention to fixing bugs.  Then, finally, I will implement the isometric modes and LIME 4 will be complete at last.

May as well post a screen shot though.  This shows that the tile palette is sort of working correctly, but not entirely.

Look!  Different tile set!


Accomplishments
  • Implemented an intrinsic Open File dialog in the engine and then utilized it in LIME.
  • Tested the tile palette with a different tile set.  It mostly works, but mouse mapping appears to be slightly off and the view doesn't scroll.
  • Updated the TileRipper program to remove dependency on the old MHF and add customization through command line arguments.
  • Used TileRipper to create a large tile set for testing.
  • Did a lot of testing and uncovered a list of issues which are categorized below.

Known Issues
  • Functionality Issues
    • The New Map dialog creates the map files in the app root rather than the data directory.
    • Full-screen mode quit working as soon as I started porting functionality from MHF 2 to MHF 3.  Gotta find out why.
  • Usability Issues
    • If the layer currently being edited is hidden, the view panel gets out of sync with the edit panel.
    • The buttons on the New Map screen's cycle controls are occasionally unresponsive.
    • The tile map view's anchor space doesn't always scale correctly when resizing the editor pane.  I've had trouble reproducing this on command, but it happens occasionally.
  • Performance Issues
    • When the tile ID view option is turned on for large tile sets, the frame rate drops sharply to the point of being unusable.
  • Supportability Issues
    • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs or dynamically resize a graphics canvas.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.
Next Steps
  • High Priority:
    • Automatically populate the tile set selector on the New Map dialog.
    • Add "Actor Mode" to the palette window.
    • Add the actor list to the tile map view classes.
    • Make the tile palette scroll.
  • Medium Priority:
    • Test and fix mouse mapping in the tile palette.
    • Fix the dependency between the view panel and the edit panel.
    • Make the New Map dialog save map files to the right location.
    • Implement isometric modes.
    • Improve performance of tile ID renders.
    • Finish updating the old command-line tile utilities.
  • Low Priority:
    • Fix full-screen exclusive mode for the PC platform.
    • Update and test WallTileTransformer.
    • Do more testing on FloorTileTransformer to make sure the vertices are right.

Saturday, March 15, 2014

LIME Status Report (03/15/2014)

I almost have the entire UI finished!  The to-do list for LIME 4 is shrinking rapidly.  Here is the list of essential must-haves before I can call it finished.

  • Fix a bug in the dependency between the view and edit layer settings.  (Details below.)
  • Finish the tile palette by adding Actor Mode and making it scroll when larger tile sets are loaded.
  • Implement the Open File dialog for opening map files.
  • Implement the diamond isometric mode, and hopefully staggered and hexagonal, too.
  • Update the command line utilities with the new engine, and maybe even add a couple more.

The Map Info dialog isn't pretty, but it gets the job done.

Accomplishments
  • Finished programming the view panel buttons.
  • Finished programming the edit panel buttons.
  • Implemented the eraser tool.
  • Implemented the tile ID display toggle.
  • Corrected a bug in the grid line display.
  • Implemented the tile picker tool.
  • Implemented the Map Info dialog.

Known Issues
  • Functionality Issues
    • Full-screen mode quit working as soon as I started porting functionality from MHF 2 to MHF 3.  Gotta find out why.
    • If the layer currently being edited is hidden, the view panel gets out of sync with the edit panel.
  • Usability Issues
    • The buttons on the New Map screen's cycle controls are occasionally unresponsive.
    • The tile map view's anchor space doesn't always scale correctly when resizing the editor pane.  I've had trouble reproducing this on command, but it happens occasionally.
  • Portability Issues
    • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs or dynamically resize a graphics canvas.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.

    Next Steps
    • High Priority:
      • Fix the dependency between the view panel and the edit panel.
      • Implement the Open File dialog.
      • Add "Actor Mode" to the palette window.
      • Test the tile palette with larger tile sets and different tile sizes.
    • Medium Priority:
      • Implement isometric modes.
      • Update the old command-line tile utilities.
    • Low Priority:
      • Fix full-screen exclusive mode for the PC platform.

    Saturday, March 8, 2014

    LIME Status Report (03/08/2014)

    This week I finally forced myself to take a break from my regular job and focus solely on LIME for a couple of days.  The result is perhaps the most productive single week I've ever had on a project.  I need to blow off the rest of my life more often!


    The LIME 4 user interface now features scroll buttons that appear when necessary, a data overlay on the editor pane, and slide-out panels for layer selection.

    When all of the slide-outs are closed, the editor pane expands to offer the maximum working space.

    Accomplishments
    • Finished implementing file I/O for saving maps.
    • Corrected the size of text boxes on the input dialogs.
    • Implemented the functionality behind the New Map dialog.
    • Corrected the issue with the grid lines and mouse cursor appearing in the full screen renders.
    • Changed the scrolling controls to use buttons rather than mouse-over zones.
    • Implemented the slide-outs for the viewing and editing controls.
    • Discovered and fixed a miscalculation in the game timer.
    • Discovered and fixed a scaling bug in the full map render.
    • Implemented a data display overlay for map data.
    • Added rotation and a redimensioning function to the MHPCImage class.
    Known Issues
    • Functionality Issues
      • Full-screen mode quit working as soon as I started porting functionality from MHF 2 to MHF 3.  Gotta find out why.
    • Usability Issues
      • The buttons on the New Map screen's cycle controls are occasionally unresponsive.
      • The tile map view's anchor space doesn't always scale correctly when resizing the editor pane.  I've had trouble reproducing this on command, but it happens occasionally.
    • Portability Issues
      • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs or dynamically resize a graphics canvas.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.

    Next Steps
    • High Priority:
      • Implement the Open File dialog.
      • Implement the Map Info dialog.
      • Finish programming the toolbox buttons.
        • Eraser Tool
        • Tile Picker Tool
        • Tile ID Toggle
      • Finish programming the view panel buttons.
      • Finish programming the edit panel buttons.
    • Medium Priority:
      • Add "Actor Mode" to the palette window.
      • Test the tile palette with larger tile sets and different tile sizes.
    • Low Priority:
      • Implement the MHBitmapImage.rotate() method for the Android platform.
      • Following the rotate example, implement other capabilities like scaling, image filtering, color blending, and alpha composites.
      • Implement isometric modes.

    Saturday, March 1, 2014

    LIME Status Report (03/01/2014)

    Despite being bogged down with final exams, tutoring, meetings, administrative tasks, and all of the other things that accompany the end of a session, I was still able to accomplish quite a bit in the last couple of weeks.  I created icons for the user interface, added them to components on the screen, and made some important decisions regarding the user interface.

    Truth be told, I can't take all the credit.  The main reason I was able to find any time whatsoever for myself this week was because my mother was visiting and looking after my son while I did what I needed to do.  And the design decisions I made were the result of a productive meeting with Professor Steve Santello.  Naturally, I must give credit where it's due, so thanks Mom and Steve!

    Here are the icons I made:

    Tile Palette Mode Selector
    Tiles: Show tiles in the palette pane.
    Actors: Show actors in the palette pane.
    Toolbox Buttons
    Eraser: Erase tiles from the map.
    Pick Tool: Select a tile already on the map.
    Toggle Grid: Show or hide grid lines.
    Toggle IDs: Show or hide tile identifiers.

    Here's a picture of them in their original homes based on my brainstorm sketches.



    And finally, here is a picture of them in what are likely their final resting places guided by the input of veteran game developer Steve Santello.




    Accomplishments
    • Created icons for tile palette controls and toolbox buttons.
    • Added buttons for palette mode selection.
    • Added the toolbox and moved it to a more ergonomic position.
    • Worked on file I/O for saving game world metadata and tile maps.
    • Made some major design decisions regarding the scrolling problem, toolbox location, and palette mode functionality.
      • Scrolling will be accomplished by buttons.  The mouse scrolling functionality will be removed.
      • The toolbox has been relocated to the bottom left rather than the bottom right to improve workflow productivity.
      • The palette modes will be selectable independently of the layer being edited, so that any layer can conceivably contain tiles and actors both.  (Not fully committed to this idea yet.)

    Known Issues
    • Functionality Issues
      • If the grid line display is turned on, the lines show up in the full render of the map.  The mouse cursor does too.  The full render should show just the contents of the map, and not user interface elements.
    • Usability Issues
      • There is no visible indication of where the view space is positioned in the world.  This may get disorienting when working on large maps.  It has been advised to add a mini-map showing the location of the view space in the context of the entire map.
      • The text boxes on the input dialogs have gotten fat.  I'd bet money that it's a side-effect of a performance optimization I made to the MHLabel class a couple of weeks ago.
    • Portability Issues
      • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs.  Currently a low priority since this tool is intended to be used on a developer's PC, but something that needs to be addressed eventually.

    Next Steps
    • High Priority:
      • Add new scroll controls to the editor pane.
      • Test the Save and Save As commands to make sure the exported data format is unchanged from that which is read in.
      • Add "Actor Mode" to the palette window.
      • Finish programming the toolbox buttons.
        • Eraser Tool
        • Tile Picker Tool
        • Tile ID Toggle
      • Create a slide-out panel for the layer view controls.
      • Create a slide-out panel for the layer edit controls.
      • Parameterize the slide-out panels so the position of their tabs can be specified -- top, bottom, left, or right edge of the panel.
    • Medium Priority:
      • Port the file dialog classes from the old engine into the new one.  Make appropriate updates to match the style of the new engine's user and software interfaces.
      • Test the tile palette with larger tile sets and different tile sizes.
      • Add a rotate method to the MHBitmapImage interface that takes an angle of rotation and returns a copy of the image rotated by the input angle.
    • Low Priority:
      • Correct the bugs in the full map render view mentioned above.
      • Implement the MHBitmapImage.rotate() method for the Android platform.
      • Following the rotate example, implement other capabilities like scaling, image filtering, color blending, and alpha composites.
      • Implement isometric modes.

    Saturday, February 15, 2014

    LIME Status Report (02/15/2014)

    Don't you hate it when you find a great way to do something and then forget all about it when you need it again?  That's exactly what I did with my project status tracking.  When I was working on Team Laser Combat, I posted weekly progress reports detailing recent accomplishments, issues encountered, and other tasks on the radar for the near future.  It was a simple but incredibly effective way to keep track of where I was in the project, what my next priorities should be, and what issues needed to be addressed along the way.  I'm going to do something similar for LIME from now on.

    Since this is the first post toward this effort, I suppose it would be wise to document the state of the system as it stands right now.  I've been working on it periodically as time allows for a couple of months, and I have a pretty good start on it.  I have the main screen layout done, most of the commands accessed from the menu bar are done, the tile palette is working in a basic form (though it's untested for larger tile sets), and the editor pane can have tiles placed on it and scroll around.  The fill command fills the currently selected layer with the selected tile, the clear command erases all of the tiles from the current layer, the full map view and export features are working, some of the custom dialog boxes are done, the grid toggle works, and the context-sensitive mouse cursor is working for the functions that are implemented so far.

    The LIME 4 editor screen as it appears now.  The tiles used for testing are from 2002's CTG 2 project.

    Recent Accomplishments
    • Added a slide-out panel class to the engine as a built-in GUI container.  LIME 4 will use these for quick access to layer toggles.
    • Started adding support for state buttons like check boxes and radio buttons.  LIME 4 will use radio buttons to indicate which layer is selected for editing and check boxes to indicate which layers are visible.
    • Documented more of the methods in the UI package.  This doesn't directly affect LIME as a product but it is important to the future of MHFramework.

    Known Issues
    • Functionality Issues
      • If the grid line display is turned on, the lines show up in the full render of the map.  The mouse cursor does too.  The full render should show just the contents of the map, and not user interface elements.
    • Usability Issues
      • The editor pane scrolls when the mouse reaches the edge of the view space, so it scrolls every time the user goes to select a tile from the palette, click on the menu bar, or open the slide-out panels.
      • There is no visible indication of where the view space is positioned in the world.  This may get disorienting when working on large maps.
    • Portability Issues
      • The Android platform layer doesn't yet have the ability to rotate the captions for the slide-out tabs.  Currently a low priority since this tool is intended to be used on a developer's PC workstation, but something that needs to be addressed eventually.

    Next Steps

    The priority right now is to finish the features that are critical to my current project (which I am not at liberty to discuss) so that the lead game designer and I can create levels more quickly.  Therefore, I'll divide the list of steps into categories based on that priority.
    • High Priority:
      • Test the Save and Save As commands to make sure the exported data format is unchanged from that which is read in.
      • Port the file dialog classes from the old engine into the new one.  Make appropriate updates to match the style of the new engine's user and software interfaces.
      • Finish putting tabs on the slide-out panels.  Parameterize them so their position can be specified -- top, bottom, left, or right edge of the panel.
    • Medium Priority:
      • Create a slide-out panel for the layer view controls.
      • Create a slide-out panel for the layer edit controls.
      • Decide where to put the toolbox and then put it there.
      • Add a rotate method to the MHBitmapImage interface that takes an angle of rotation and returns a copy of the image rotated by the input angle.
      • Make a decision regarding what to do about the mouse scrolling issue mentioned above.
    • Low Priority:
      • Correct the bugs in the full map render view mentioned above.
      • Implement the MHBitmapImage.rotate() method for the Android platform.
      • Following the rotate example, implement other capabilities like scaling, image filtering, color blending, and alpha composites.
      • Implement isometric modes.

    Thursday, January 2, 2014

    LIME 4 Data File Formats

    One thing that I've had to reference repeatedly in developing LIME 4 is the file format for opening and saving map data files.  I figure that if I, the creator, can't remember it, then my users probably won't either.  Therefore, even though this information is in the API documentation, I'm going to post it here too.

    Just as in previous versions of LIME, the data is separated into multiple files.  However, the content and structure of the files has changed to be more flexible and force fewer assumptions upon level designers.

    Both file types are tab-delimited as specified by the constant MHMapFileInfo.MAP_FILE_DELIMITER.

    The file types are as follows:

    File TypeExtensionDescription
    Game World Metadata.LIMESummary data required to open, initialize, modify, and save game world data in a format recognized by LIME and MHFramework.  This is the file type given to MHWorldLoader.loadGameWorld() and also the type that is opened by LIME's File | Open command.
    Tile Map.LTMA file containing the data for a single tile map, which may stand alone or as a layer in a layered tile map. This is the file type given to MHWorldLoader.loadTileMap() and also the type expected in the file name properties of a .LIME file.

    Game World Metadata (.LIME) File Format

    • Map width (columns) : int
    • Map height (rows) : int
    • Tile width (pixels) : int
    • Tile height (pixels) : int
    • Tile set ID : String
    • Floor map file name : String
    • Floor details file name : String
    • Wall map file name : String
    • Wall details file name : String

    Tile Map (.LTM) File Format

    • Number of columns : int
    • Number of rows : int
    • Tile ID grid : int[][]

    Friday, September 27, 2013

    Old vs. New Tile Map Systems

    After some thought experiments and pen-and-paper prototypes, I'm ready to commit to the new tile map data design for MHFramework 3. I'm content that I've found a solution that satisfies the goals of functionality, usability, performance, and supportability. Plus it will allow me to maintain the qualities that I didn't want to lose from the previous versions of LIME, and in fact, will improve upon some of them.

    Differences From Previous Versions

    Other than having a whole new set of layers, there are quite a few differences in the new design, involving the data structures and algorithms both.

    Reversed Relationships in the Data Structure

    The old system consisted of a matrix of MHMapCell objects. A map cell held an array of actors such that there was zero or one actor for each layer. So, technically, the map wasn't layered, but the map cells were.

    Conceptually, the new tile map consists of two coarsely-plotted pairs of layers (a pair for floors and a pair for walls), each with a sparsely populated, semi-transparent overlay layer for adding decorations and other composite effects. The benefits to this change are countless -- performance, memory efficiency, flexibility, more intuitive optimizations, and more.

    So the old system was essentially a matrix of arrays while the new system is an array of matrices.

    Actors Are Not Tiles

    Unlike the previous iterations, actors are not actually stored in the tile grid, but the class will still keep a list of them for rendering, collision detection, and persistence purposes.

    Furthermore, although actors are no longer treated as tiles, tiles can still be actors. We can still have floor switches, teleporter pads, flowing water, blinking runway lights, and so on. The difference is that now they're stored in the actor list rather than a tile grid.  To load these things from map data files, I'll be renaming MHObjectFactory to the more specific name MHActorFactory to better reflect its true purpose.

    More Sophisticated Rendering Algorithm

    The new rendering process will go something like this.
    1. Lay down the section of the floor layer that is visible to the camera.
    2. If a layer of floor decals is present, apply them in a separate pass.
    3. Put all visible actors and wall tiles in a list and sort them on the y values of their base anchor points.
    4. Draw every element in the sorted list.  For each wall tile encountered, check for a decal and render it if present.

    New Collision Rules and Terrain Height Variations

    In the old system, collision detection was straightforward.  If the wall layer in a given map cell was occupied, then it was an obstacle. Though admirably simple and adequate for rectangular tile maps, it's insufficient for representing 2.5D phenomena like projectiles flying over tables or variations in the height of terrains. Therefore, the new collision detection logic for isometric maps needed to be much more sophisticated.

    First, the relevant values are either initialized or calculated.
    • Actor climb = the maximum difference in terrain height between map cells that an actor can traverse.
    • Actor altitude = the actor's height from the ground when falling, jumping, flying, etc.
    • Actor elevation = map cell height + actor's altitude.
    • Obstacle height = height of image - base tile height.
    Then, for all potential obstacles, a collision occurs when:
    1. The obstacle is a wall and the actor's short-range look-ahead vector entered its map cell OR
    2. The actor's and the obstacle's collision geometries intersect AND
    3. The actor's elevation plus its climbing ability is below the obstacle's height.


    Table of Tile Map Layer Properties

    One of the major goals I had for this redesign was to keep the reusability of the tile grid for essentially all tile map types, be they isometric or rectangular, top-down or side-scrolling, diamond or staggered. To this end, the layer ID constants have synonyms to help keep it simple for developers using the engine.

    LayerSynonymCollidableInterlaced
    FLOORBACKGROUNDNoNo
    FLOOR_DECALSBACKGROUND_DECALSNoNo
    WALLSFOREGROUNDYesYes
    WALL_DECALSFOREGROUND_DECALSNo

    Sunday, September 22, 2013

    The History (and Future) of MHFramework's Layered Tile Maps

    The original version of the MHFramework tile map system (circa 2004) consisted of the following layers:
    • Floors
    • Items
    • Walls
    • Ceilings
    The overwhelming task of creating assets for the Beltzhian Marauders world led me to redesign the map structure to cut down on the number of raw assets that need to be created (and also reduce memory consumption in the process).  The evolved version (circa 2008) contained these layers:
    • Floors
    • Floor Decals
    • Items
    • Walls
    • Wall Decals
    • Ceilings
    The lessons learned through creating various games and prototypes in the meantime has made me realize that by aggregating things together and using more sophisticated rendering and collision detection algorithms, the default layers for MHF3 might look something like this:
    • Floors
    • Floor Decals
    • Walls
    • Wall Decals
    • Actors


    Wednesday, August 28, 2013

    Planning for Tool Upgrades

    Considering that the entire engine is being rebuilt from the ground up, it should come as no surprise that the engine tools could also use a redesign.  MHF doesn't have a lot of tools, but the few that it has are useful and worthwhile. Here's the list as it stands right now.

    SpriteTester 2.0:Interactive animation viewer
    LIME 3.6:Layered Isometric Map Editor
    Floor Tile Transformer 1.1:Parameterized command line utility that splits rectangular textures and tile sheets into sets of isometric floor tiles.
    Wall Tile Transformer 1.2:Batch utility that creates and applies shadows to a matching set of isometric walls from a single source image.

    The most sophisticated of these tools is LIME, so it's the lucky recipient of the first redesign. It's also the most frequently used, as evidenced by the advanced version number relative to the other utilities.

    So, What'll it Be?


    I'll brainstorm a wishlist of features I'd like to see in the new LIME.  For starters, I'd like to keep certain features of the current LIME.

    • Support for diamond-rendered isometric maps.
    • Controls for independently toggling the visibility of each layer.
    • File formats that can be edited in other programs, like OpenOffice or Notepad++.
    • Full-screen view mode.
    • File browser for listing, selecting, and opening map files.

    I would also like to incorporate features from the very first map editor I ever made -- the one for CTG 2.

    • Support for rectangular (non-isometric) tile maps.
    • A space-efficient tile palette that shows a large portion of the tile set with minimal scrolling.
    • A single file format for saving map data.
    • Highlight around the selected tile in the palette instead of a "Selected Tile" display.
    • An option for toggling grid lines.
    • An option for viewing tile IDs or perhaps the entire data set.
    • Menu bar with pop-up/drop-down menus to minimize the complexity of the UI and maximize the working area.

    I may even want to bring in some features from the SpriteTester tools.

    • Ability to play, pause, and control the frame rate of animated tiles.
    • Ability to cycle through a set of background colors.

    Finally, I'd like some new features that I have never implemented in any of the previous tools.

    • Support for staggered isometric tile maps.
    • An option for rendering an entire map to an image and saving it to a file.
    • Tile images stored in either a single tile set image or a directory whose name is the tile set name.
    • Context-sensitive mouse cursors (selected tile, tool, etc.)
    • Ability to load a background image instead of just a solid color.
    • A "play" command that drops a playable character into a map and lets you move around inside.
    • Perhaps add a zoom control to the view mode.
    • A mini-map generator showing a rectangular mini-map of the collidable areas.
    • Option for showing elevations of isometric map cells.
    • Object browser for viewing and selecting assets that may be separate from the tile set.

    I'll prioritize those later, and will certainly be elaborating because, of course, I want it all.  For now, let's think about how the application flow might happen and what bits and pieces might be on the screens.







    Wednesday, July 24, 2013

    Proposed Changes and Tasks for MHF 3.0

    As much as I'd love to put the cart before the horse and declare that MHF3 is ready for showtime, the truth is that a number of tasks remain.  I've also been contemplating some changes to the existing code.  This blog entry will document the state of those lists at this moment in time and serve as a checklist of preparations for an upcoming project (which I am not at liberty to discuss due to an anticipated nondisclosure agreement).


    Remaining Tasks for Version 3.0:

    • Android platform functionality must be caught up to the SE-compatible code.
      • When my Android development environment quit working, I continued to work on the PC platform.  It's time to get the Android code up to speed with those advancements.
    • More testing of existing engine cores on all supported platforms is necessary.
      • The current demo program includes a lot, but some of the cores aren't addressed.  Also, it has only been tested on the PC/Windows platform.
    • The configuration management plan needs to be finished and validated.
      • The only reason this isn't done yet is because I've been experimenting with project setup alternatives in an effort to simplify the cross-platform development and testing.
    • Javadoc documentation needs to be completed and made more consistent.
      • Most of the existing engine is documented, but hasn't been updated to reflect recent changes.  Also, the documentation was never very consistent across packages.
    • The rest of the planned features need to be completed or formally moved to a later phase of development.
      • For instance, sprite sheets, textured particles, and predefined physics behaviors are all "wishlist" features that have yet to be implemented.


    Proposed Changes to Existing Code:

    MHGame should be renamed to MHGameLoop (or maybe MHGameCore).  In MHF 2.x and earlier, the MHGame class was a software controller that manipulated user-defined objects to run the game.  In MHF 3, however, the class is responsible only for the concerns of the game loop.  Therefore, it is still the very heart of the engine, but it no longer represents all of the other gameplay support functions such as message pumping.  It also has no direct association with user-created code or assets.

    MHVector's arithmetic functions should apply directly to the vector object instead of always generating a copy.  I originally designed it for maximum flexibility, but the performance of these objects is super critical, and this change in priority demands changes in interface and functionality.

    The steering calculations in the Artificial Intelligence core should be simplified to be more cohesive.  As they are at the moment, they cannot be used in an independent, atomic way, so their reusability is unnecessarily limited.

    The AI core's finite state machine support should be updated to use generics.  This way, the MHState interface could be generalized to eliminate dependency on the rest of the core, allowing states to be used independently of any particular owner without the need for explicit type casting.

    This may not require a change, but the relationship between tile map data classes and viewer classes should be revisited simply because I don't remember exactly how I divided these responsibilities, and this is a crucial element to virtually all upcoming projects.

    Class Structure of the Platform Layer (Updated)

    As a result of the configuration management change mentioned in my previous post, the class structure of the platform layer now looks like the diagram below.  The changes to the diagram are slight, but I updated it anyway because I care about the correctness of my documentation.  Someone will appreciate that someday...maybe.



    Tuesday, May 28, 2013

    Software Design and Configuration Management

    Despite my years of experience, I still occasionally get slapped in the face by things that somehow slip by under the radar until they're close enough to strike.  One such thing that dominated a portion of my weekend is an unforeseen relationship between the design of the platform independence layer and the configuration of the projects in the development environment.  As with many of my posts in this blog, this one is intended to document the issue so that lessons are learned rather than lost.

    MHFramework 1 and 2 were designed to be used as code libraries that existed as a separate project or an external JAR file.  Most of the games built with it simply absorbed the engine binaries into their distributable files.  Most often, they were just packaged into the game's executable JAR file.

    MHFramework 3 introduces a new challenge, however.  One of the main objectives of this version is to add Android as a target platform while still maintaining compatibility with Jave SE platforms.  After a few days of puzzling over this challenge, I came up with a solid design that conforms to a number of object-oriented design principles.  That design is documented here.

    The problem, as usual, is in the implementation details.  I could create a Java SE demo program that hooked into the engine with no trouble whatsoever, but the Android programs weren't so forgiving.  An Android app simply won't deploy if there is any reference whatsoever to SE-only classes.

    My planned solution to this problem was to isolate all the SE stuff into a single package hierarchy that the running app would never encounter.  The problem with this solution is that the platform factory interface couldn't be completely generic.  (For example, mobile apps launch as an Activity while PC apps launch as a JFrame.)  There is no way to have a single branching point that accommodates both platforms because it creates problematic (and unnecessary) dependencies.

    The solution I am attempting now, which seems to work so far, is to break the engine up into multiple projects.  The main engine core is now an Android-compatible library.  This main project contains the cross-platform heart of the engine along with the Android platform layer.  Java SE support has now been moved into a separate project, so now the main engine core is completely free of Java SE elements.  With just a few more alterations, I can completely remove all Android references from the execution path for PC games, and vice versa.

    So, while the class diagrams are only slightly affected, the configuration management has changed dramatically.  Updated documentation to come.

    Important lesson learned!


    Thursday, February 21, 2013

    Designing Cross-Platform Image Buffers

    This post documents a design issue, some rationale, and the chosen solution. 

    The Problem

    As I was porting functionality from the old MHFramework to the new one, I realized that I needed a platform-independent solution for generating images from buffers.  Since the old engine was based entirely on Java's Abstract Window Toolkit (AWT) which isn't available on Android, I needed to find a way to accomplish the same thing for both of those platforms in a consistent manner.

    Proposed Solutions

    The first solution that came to mind was to encapsulate graphics contexts (MHGraphicsCanvas) into the the MHBitmapImage classes just like AWT does.  However, as with all such decisions, it comes with some immediate advantages and disadvantages.

    Pros:

    • Our engine is never going to use a graphics context for anything other than drawing to a buffered bitmap.  Combining these classes would hide the coupling.  This cleans up the class structure of the  platform layer and also greatly simplifies the implementation of more advanced visual effects.
    • AWT and Android sort of reverse the association between bitmaps and canvases, and this would encapsulate those differences internally so we'd have a uniform way to work with image data.  (AWT's Image has Graphics, and Android's Canvas has a Bitmap, so even though they're semantically equivalent, their compositions are inverted.)

    Cons:

    • MHBitmapImage no longer just stores image data.  It now also provides an interface for manipulating that data, so we may be in violation of the Single Responsibility Principle.
    • Not all image data requires a graphics context until it's rendered, so this could incur some memory overhead.
    • HOWEVER, we can solve both problems through composition and lazy instantiation.  Besides, this relationship already exists at the platform level anyway.

    The Chosen Solution

     I decided to keep MHBitmapImage and MHGraphicsCanvas as separate classes, but I removed MHPlatform's factory method for creating a graphics canvas.  Now the only way to retrieve a canvas for drawing is to extract it from the image object.  Now you always have immediate access to the results of every rendering operation.

    For example, the double-buffered rendering now happens by using an MHBitmapImage as the back buffer, and then passing its associated MHGraphicsCanvas to the screen manager.  When the call returns, the bitmap image is presented physically to the screen device.

    I am happy with this solution.  Although I was unable to satisfactorily eliminate a class, I feel very comfortable with the design principles involved and the improvement in general usability of these critical elements.
     

    Tuesday, February 19, 2013

    Getting Started With MHFramework 3

    Though still in the early stages of development, MHFramework 3 is vastly different from its predecessors in a variety of ways.  However, those prior versions had certain strengths that I desperately want to maintain as we go forward with the engine's redesign.  One of those strengths is the simplicity of the initial setup.

    One of the highest priority design goals of MHF3 is cross-platform portability between Android and PC-based platforms.  With this in mind to help guide my design decisions, the initial setup for both platforms follows a simple, three-step process, with only a slight modification to the Android version:
    1. Create at least one screen.  This is done by inheriting from the engine's MHScreen class. (More on this in a future post.)
    2. Define your display settings by initializing an MHVideoSettings object.
    3. Pass those things into the engine along with the window in which your game app will run.  This is accomplished with a call to MHFramework.run().

    Here's a PC-compatible example of a main class that accomplishes these things.

    import javax.swing.JFrame;
    
    import com.mhframework.MHFramework;
    import com.mhframework.MHScreen;
    import com.mhframework.MHVideoSettings;
    
    
    public class PlatformTestPCWindow
    {
        public static void main(String[] args)
        {
            // Step 1:  The screen.
            MHScreen startingScreen = new TestScreen();
            
            // Step 2:  The video settings.
            MHVideoSettings displaySettings = new MHVideoSettings();
            displaySettings.displayWidth = 800;
            displaySettings.displayHeight = 480;
    
            // Step 3:  Run it!
            MHFramework.run(new JFrame(), startingScreen, displaySettings);
        }
    }
    

    The Android version takes a very similar approach, but with a few additional rules:
    1. The main class must inherit from the engine's MHAndroidActivity class, which is a specialization of Android's basic Activity class that adds additional support for MHF3's multithreading requirements. 
    2. Rather than perform those steps in main, your program must override the Activity.onCreate() method. 
    3. Since Android's orientation can be specified as portrait or landscape, this must be specified here as well.  
      • Future versions may simply add the orientation constant as a field in MHVideoSettings and default it to landscape.  This way, the Android version will use the exact same three steps with no additional requirements.

    import android.content.pm.ActivityInfo;
    import android.os.Bundle;
    
    import com.mhframework.MHFramework;
    import com.mhframework.MHScreen;
    import com.mhframework.MHVideoSettings;
    import com.mhframework.platform.android.MHAndroidActivity;
    
    public class PlatformTestAndroid extends MHAndroidActivity
    {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            // Initialize Android-specific properties.
            super.onCreate(savedInstanceState);
            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            
            // Step 1:  The screen.
            MHScreen startingScreen = new TestScreen();
            
            // Step 2:  The video settings.
            MHVideoSettings displaySettings = new MHVideoSettings();
            displaySettings.displayWidth = 800;
            displaySettings.displayHeight = 480;
    
            // Step 3:  Run it!
            MHFramework.run(this, startingScreen, displaySettings);
        }
    }
    


    Thursday, January 3, 2013

    Class Structure of the Platform Layer (Corrected)

    In my previous post, I forgot to include the event handling mechanism, so here's an updated class diagram that accurately shows the static structure of the platform layer.  If you compare it to the architecture diagram I posted awhile back, you'll see that all four elements of the platform layer are now represented.


    Wednesday, January 2, 2013

    Class Structure of the Platform Layer

    The platform independence layer seems to be working beautifully so far.  Here's how it stands right now.




    This is only the abstracted view of the system.  All of the abstract classes and interfaces shown here have been implemented in both PC and Android versions in their own respective packages.