May 20, 2012

Update 5/20

I'm still alive and kicking!  As I mentioned in my last post, I've had a bunch of stuff going on in my life lately.  Just finished a draft of a journal article based on my Master's thesis from 2 years ago, just bought a house a couple weeks ago (and will be moving in ~1 month), had family visit, and have still been slammed at work.  I've put in some time on the game when I've been able to--and when my brain hasn't been fried from all the other stuff going on.

I am still working on getting basic graphics, interaction, and audio going.  In what time I've had since my last update, I've done the following:

1) Created a framework for "Features" that can be added to any object in the game.  For example, a star may be given a SolarFlares Feature and this would change the way it appears on the map and also allow it to create SolareFlareEvents, capable of doing damage to ships and (if severe enough) planets in its system.  Features can contain ViewModifiers, DataModifiers, and EventGenerators.

2) ViewModifiers and DataModifiers... well, do what the name says.  They can be applied to any object in the game.  ViewModifiers can change the way an object looks by altering its texture, colors, etc.  I still have to figure out what the limits of their capabilities are, but for now I'm using them to change textures.  They're usually coupled with Features that alter the behavior of an object, though they can be applied independently as well.

DataModifiers change some variable within an object's model data.  All object data is now kept in a HashMap<String, Double>, where the String is the variable name and Double is its value.  DataModifiers are Strings that are sent into the model and applied to a target variable.  They consist of a source, target variable, and modification.  For example, the technology of Nanoprobes could carry with it "Nanoprobes Production +2."  The String is parsed and the modifier +2 is added to Production, while the source of the modifier (Nanoprobes) is registered.  All modifiers are tracked in the model and can be added and removed through referencing this source.  This setup was necessary because players can lose or throw out technologies, reversing any gains previously made.

At this point, I see DataModifiers as probably more flexible than ViewModifiers and found in a wider variety of places (Features, technologies, special events, etc.)

3) EventGenerators generate in-game events.  They can be found in Features by may be found in other objects as well--I'll figure that out as I go along.  They can have a certain probability of generating an event every turn or can require some logical trigger condition to start.  Some persist forever, some for a limited number of turns, and some are single-shot and just create one event.

4) Vastly simplified my Events system.  I was creating an entirely new class for each event type and, since I'm making this a very loosely coupled application, I was generating a ton of very small classes that were all quite similar.  It makes more sense to just use a generic template class (ApplicationEvent), provide it a String for a name ("SolarFlareEvent"), and then stuff any needed object references into it (via an array of generic objects--Object[]).  The receiving classes look at the name and know exactly what to expect in the Object[] array, so they can cast to the appropriate types and do their thing.  This does mean that I still need to create a whole bunch of EventStrategies (which encode the responses to particular events), but its about 50% less coding burden in this area.

5) Simplified references to EventManager, AssetManager, and RootNode.  Don't remember if I've discussed these before, but EventManager handles all game events and communications between objects, AssetManager is part of JME3 and loads/maintains all assets (textures, materials, audio, models, etc.), and RootNode is also part of JME3 and is the base object to which all rendered visuals are attached--if you want it to appear, you attach it here.  I found myself having to pass references to these things to virtually everything and it was getting cluttered.  I'm a little worried about my solution, but it seems to be working so far.

And that solution is:  Create classes called EventPortal, AssetPortal, and RootNodePortal that contain static accessor methods for their corresponding classes.  I just initialize one object of each of these classes at startup, pass them a reference to the appropriate *Manager class (or RootNode), and can then access them anywhere.  I suppose its bad OO design since I'm not explicitly passing in references to objects that use these systems, but this removes a lot of worry for me while coding.  If I need a given object to send a particular event, I just write EventPortal.queueEvent(new AppEvent([misc. data])) and that's it.  No need to pass references to everything through all my various Builder classes.  I don't want to expand this technique further though, as I'd prefer it to only be used for referencing these really big, very common systems.

6) I've rewritten some of the external data loading for more flexibility and greater ease of modding down the road.  JME3 uses a Material class to set the visual properties of game objects and encourages either creating Materials on the fly or, if creating lots of them, loading pre-made Materials from .j3m files.  Well, so far I only have about a dozen materials, but I'm using them upwards of 10,000 times to create (for example) stars.  Creating them on the fly is therefore slow.  However, pre-made Materials would all have to go into self-contained .j3m files, of which there could be dozens or hundreds.  Modding that many files would suck.

Instead, I've placed all the relevant data for each Material into one table in a .txt file.  I load this data up and build each Material once at the start of the game, then save them in my AssetPortal class.  This avoids slowdown from creating thousands of new Material objects, but also lets modders (and myself, the developer) avoid slogging through tons of separate files to change things.  It's all in one table.

...

Wow, that actually ends up being more than I realized.  Still not enough for all the time that has gone by.

After all these changes under the hood, I am now back at a point where I can get a star up on the screen and have its level of detail change as I zoom in and out.  Next steps are, as they have been since February, being able to click and highlight it, play a sound when clicked, and get some sort of GUI display to appear/disappear when its selected/deselected.

Then I'll create a system for multi-star system visuals.  At a certain level of zoom, you will be able to see the number of stars in each system.  When zoomed further out, each system is just represented by a single star icon.

We're moving into the new house in June, then in July I'm traveling for work for over half the month.  I will do whatever I can in my free time!