Development Update 6/2
I enjoyed a birthday over the weeked; I'm now 31 *groan* ;)
Design Related Update
I'm happy to say that I'm pretty much set with the land-mass layout of the Revel Immortal world map.
I've created a base graphic and imported it into the engine in the WorldMap view class; expressing 'rooms' on this map and performing fast travels between them will be one of the first new pieces of functionality.
Technical Related Update
Lots of work is being done on the technical side of revel; as it needs to be prepared to support the new high level decisions; as a recap and addition here are some of those plans.
- node based world map
- larger 'room' maps, with layered graphics to reveal building internals at multiple levels.
- removal of html5 DOM based UI; it has/had some benefits but ultimently it is counter productive to the development of a refined game-like UI; so far the plan is to use an immediate mode gui instead.
- removal of the front-side website as a 'main menu' instead we'll move to a traditional in-game menu; which means the ability to do an engine state re-init, instead of relying on a page refresh to wipe the JS universe.
- removal of virtual gamepads for tablet/mobile; moving to a predominantly point-click interface; still considering WASD motion where availiable, and actual gamepad/joystick support.
- supporting lots of variable 'experiences' by using view encapsulation and a 'view stack' to perform flow-control
Views and the View Stack
One game engine concept i've seen a lot but never really had a use for was the gamestate or 'state' stack.
It is commonly used to get rid of large if-else or switch statements, when traveling through various rendering/operation states of the engine. (company cinematic, game intro, main menu, main game, world map, credits, etc.)
When thinking about how I was going to shove the new varried mechanics into my otherwise very clear engine; it seemed like this mechanisim would work well.
Take into account before that, when the engine was started (via a url switch to /game.html) from the main menu/front site (/index.html); the system was primed with a game file to load and from there it was only a serries of room to room load sequences as the player moved about.
All UI existed in the DOM and floated over the running game in Canvas.
This is not the way things are going to be in the future; for starters at the very least there was a new type of 'Room'; notably the world-map.
The travel dialogue (the closest analogue in current version Revel Immortal) never worked very well; it was really a fullscreen experience, trapped in a windowed frame.
Anyhow this deviation from elegance made me assume at the very least there would have to be a common IView between Room and WorldMap classes; as trying to implement the worldmap as a true room would probably be bad for both systems.
After this revelation, I realized I would some how need to present a main menu; and all of the inventory and related UI screens that were in the DOM previously.
And that pretty much broke any hope I had of keeping things mostly 'business as usual'.
So, after thinking about it, driving most systems down to a common IView interface, for processing, rendering, mouse input, etc. seemed easy enough; but I realized that it wasn't going to do to always change from one view to another; requiring reloads of various non-stated components.
So this is where the need for a view-stack came in.
Views could simply be pushed and pop'd on said stack, and the top of the stack was rendered and processed.
Immediately I was unhappy with the idea of various views, reaching out to the game, and specifying it pop them (at weird times no less); and push other new views.
So the thread-signaling model came to mind:
Now, when a view at the top of the stack is updated, its return value signifies hard coded engine functionality.
If view.update(t) returns...
'this' - nothing changes, stack remains the same (keep me)
'null' - stack is pop'd (remove me)
'some other view pointer' - new pointer is pushed (load new view)
This seemed very elegant, and kept various systems from reaching out and playing with the stack.
...though the more astute may notice there isn't a state for 'pop me and push new view' (replace top)
doing so might require the use of a more complex return type (action and pointer).
With this system I am hoping that I can deal with various kinds of gameplay 'experiences' which can be changed easily.
Game Main Menu
- new game
- pop then push
- load game
- push load menu
- select game
- return selected game, pop (main menu looks for return signal, then pops and pushes starting room)
etc. etc. etc.
Elegance of an Immediate Mode GUI
I've been hearing about immediate mode GUI's since probably '08-'09; and I didn't give it much thought for a while.
I belive I've ranted before on how writing a GUI system will be the worst thing ever, and I still stand by that.
The case of using the DOM for Revel was a good example of ease of starting/prototyping; but ultimently not a great tool for the job; if you're going for a very 'windowed' app type experience, I think it is a decent tool; but mostly the revel GUI wasn't easy to build those really custom interfaces (npc dialogue, inventory/stats window).
The idea of implementing even a limited retained-mode (traditional) UI component; filled me with dread.
Sure, it was only gonna be image-button functionality, with text too; but I knew all too well the pain even that came with.
Even scarier was the plans of the init functions, used to create the complex models, and then the various callbacks; and referencing all of these objects to modify its state.
Faced with this, I decided it was time to look more seriously into immediate mode; it claimed to solve most of these issues; but a quick run through my head made me figure that some very easy traditional gui stuff; would be brutally hard.
Despite claims otherwise, i'm still pretty sure that if you want edit boxes, listviews, trees, etc; in a GUI; you probably are better off using retained mode; otherwise you will probably be stuck implementing the non-trivial state for these things; which for some controls (listviews and treeviews) are better left implemented underneath.
But I only needed buttons, and maybe some text; so after reading up on the principle again I gave it a shot.
I was able to code a basic IMGUI 'library' in about 2-3 hours; and indeed, it gives you buttons and button feedback for practically free.
You need to do three things to use it; and probably less if you have access to polled-mode input (which in HTML5 I don't.).
First you need a GUI object:
var gui=new GUI();
In theory you can go C-Style procedural, but in this case I don't see benefits in either direction.
After that, you need to service the UI event(s)
for simplicity i have one single ui event call that covers, mouseup,move,down (touch equivilents too)
gui.mouse(x,y,type);//where type is 0-2 for down,up,move
The third and final piece is to define your GUI.
In your render function, wherever it may be, you simply render and handle your button:
//here is the code that is called if you get a button click
That's it; and note, this does handle standard button click semantics (with drag-off cancel etc.)
The fact that you can construct the gui in one big render function like this, is a boon for prototyping and drawing various pieces of information into your visual state.
All of a sudden adding bits of UI to things is easy and not a hassle.
I'll report more as my use of it expands.