Map Traversal Is Complete

After a long development period, map traversal is complete! And just in time for the Christmas holidays, too. What a relief! It’s been a long time in coming (in fact, I’ve been looking forward to this point since I started working on TGE in 2010!)

Video Demo

I’ve uploaded a video of a demo of me walking around on the game map. It’s pretty slick, there’s chunk traversal and everything! You can view the video here.

Tech Demo

The supporting tech demo is located here: http://99.236.181.174:5152/game/index.html

It mightn’t be running, depending on whether development of the game is under way  but I’ll try to leave the demo up as often as possible. If you’re really interested in seeing the functional demo, shoot me an email, and I will reply letting you know if/when the server is up and running. I’ll try to have a more permanent home for the tech demo as time progresses (I’m looking at a permanent VM home for the demo)

Note: there is a certain rendering behaviour which occurs when the browser client area exceeds 880 pixels in width (and an unresearched number of pixels in height, likely around 1260), which I believe to be related to a bug in the chunk rendering algorithm. It’ll get fixed eventually, but for now, the easiest fix is to simply resize your browser to the prescribed dimensions of less-than-880 by whatever.

What’s Next?

What indeed. I’ll be refocusing my efforts in the UI area, as the game engine has quickly reached a point where an interface is required in order to support upcoming features like login, character creation/selection, and basic chat.

Progress Update: Character Creation, Map Traversal

A quick progress update before Christmas vacation sets in.

Character Creation

Automated character creation is functioning. Upon successful authentication, a player character list is retrieved for the account, and sent to the client. If the list is empty, a John Smith demo character is created; otherwise, the client selects the first available character (i.e. John Smith) for play.

Journey Onward. It's the obvious choice.

Journey Onward. It’s the obvious choice.

This will be similar to default login/character selection in TGE; I liken it to Ultima’s usage of the “Journey Onward” option found in the mid-Ultima games. The player shouldn’t feel as though he’s interacting with a user interface, but rather, he’s returning to a virtual world. It’s only a small nuance, but the overall goal is to give the player a sense that this virtual world possesses depth.

My plan is for a specific behavior to occur after the player logs in for the first time, and enters the virtual world for the first time. The default option will be to opt-in to auto-login (the player can always opt-out in the user options). With the opt-in feature enabled, when the player hits the game website, he will automatically authenticate and select the last character he logged out with, and enter the world automatically.

A player whose account automatically logs in could invite trouble if an unwelcome party auto-logs in without knowing the player’s authentication credentials, and might cause havoc (character death, abusive behavior toward other community members, muling items, and others) at the expense of the owning player.

In all situations, the player should be able to opt-out of auto-login.

It’s not my intention to provide a platform for abuse-by-peers, or even unintentional chaos when a player’s younger sibling decides to see “what this game is all about”. It is my intention to provide safeguards against such situations. For example, using a session ID only valid on the player’s browser, allowing the user to select a “don’t auto-login when I return” option at log-out time, and possible other protective measures.

In short, if a player is in an unreliable gaming situation, the player should actively opt-out of the auto-login feature.

Map Traversal

I’m closing in on map traversal. The state of things is, the player is able to submit arrow-key input for movement, the client sends a request to the server, the server updates the player character’s position, and sends the success back to the client The client is also able to rotate map chunks.

Next up is rendering the map by a chunk offset, and loading new chunks as map traversal occurs.

Merry Christmas to all, and a Happy New Year! I’m looking forward to great things for TGE in 2013.

World Generation Is Complete

They weren’t kidding when they said it was going to be a bumpy ride.

This announcement marks an important stepping stone in TGE’s development.

One of the main difficulties with developing the map fractal conversion algorithm was that of tiles with disparate adjacent terrain types. I found that three passes were necessary in order to completely close gaps; once for rows, once for columns, and one final for the remaining diagonal “tween” tiles (for example, what goes between a grass tile and a grass-to-beach transition tile which has water on the north side?)

(Fortunately, coffee and pizza, the programmer’s two secret weapons, were able to fuel this weekend’s development)

I’ve also stripped the hard-coded tile-set out of the core conversion engine, and placed it in an XML document for simple modification and extension.

So what’s left?

  • for each instance of smaller bodies of land-locked water replace them with the most common surrounding terrain tile
  • “gap” the map
    • allocate a new grid 2x the width and height of the original
    • copy the old tile map to the new, inserting blank rows (and columns) every other row (or column)
    • fill the gaps according to surrounding tiles
  • for each instance of larger bodies of land-locked water, either
    • fill it with swamp, or
    • path it to the ocean
      • determine the shortest path to sea level
      • follow the path toward sea level
      • “carve” river into the terrain

Taking a quick look at the tasks above, we can see that there is nothing left to do for generating maps; the greyed out tasks indicate ones which might be deferred to a later development cycle, since they aren’t crucial to map generation; they’re more nice-to-haves. As time goes on (and I have the time to invest in learning about Perlin noise and Floodfill4) I will return to these lower-priority items.

Having said that, I will be returning to the main client/server development; loading map content over the wire, and traversing the world are my next focus.

Map Gapping, Redux

Development continues on the map gapping feature of the map generator. The most complex portion of this part of development is making deterministic decisions on tile-filling.

A quick update to the “Map Gapping effort” checklist:

  • for each instance of smaller bodies of land-locked water replace them with the most common surrounding terrain tile
  • “gap” the map
    • allocate a new grid 2x the width and height of the original
    • copy the old tile map to the new, inserting blank rows (and columns) every other row (or column)
    • fill the gaps according to surrounding tiles <– current effort
  • for each instance of larger bodies of land-locked water, either
    • fill it with swamp, or
    • path it to the ocean
      • determine the shortest path to sea level
      • follow the path toward sea level
      • “carve” river into the terrain

Other Considerations

The Forest biome, I believe, I will replace with more scrubland, and permit tree growth on these areas. The purpose of this, is to allow for a few game features:

  • Trees must be treated as Resource Objects (i.e. objects which yield Resources when a Player Character interacts with them with the intent to Harvest).
  • Trees must be able to grow from seedling, to sapling, to adult over the course of time.
  • Trees must exhibit a state, which includes their age, but will also include “stump”.

I’ll have to consider this for other flora, but that will come in time.

 

Closing in on Map Gaps

I’ve completed the map-expansion part of the fractal-to-tiled map converter, and so far everything is working great. Behold!

In the main part of the image you can see Tiled displaying the tile map which was converted from the fractal generator. The call-out shows a zoomed-in portion of the map; in it, you can see some joined tiles. As the tile-joining algorithm evolves, the currently visible gaps will disappear.

The most profound challenge I’ve encountered is that of processing time, though there are others as well.

Stuff I’ve noticed:

  • Avoid tests inside loops which iterate over the surface of the map. I knew that the empty tiles fell on certain rows and columns (in short, every other tile was a blank/0 tile from the expansion part of the converter).
  • The map ‘looks’ better and gap-closes better when higher resolution maps are generated. This is mainly because of the transition tiles available in my particular tile set. I suppose if I had a tile set laid out in ABCDE fashion, I’d have to develop a slightly better algorithm.
  • A map which is generated at 2048×1024 size, then expanded to 4096×2048, looks awesome. I’m getting excited about the sheer vastness of the playing landscape.

I can’t wait to play this f*n game. :-)

 

Converting Fractal Maps to Tile Maps

Today I made some remarkable progress.

The current effort is to provide the client with a map through which he can traverse. This means I need to be able to generate world maps in some way.

Fortunately, I’ve been able to fit a well-researched fractal world map generation system into the TGE world-genesis tool-chain. It’s pretty nifty; passing along various factors including land mass amounts and the number of iterations the fractal generator makes, it outputs a decent looking height map in an acceptable amount of time.

Map generation goes something like this:

  • generate a fractal-based terrain height map
  • read the byte-based height map into an integer array
  • close off any orphan terrain tiles based on surrounding tiles
  • for each instance of smaller bodies of land-locked water,
    • replace them with the most common surrounding terrain tile
  • replace each tile entry with a random common entry (e.g. if there are 5 variations of ‘tree’, randomly use one of these) <– current effort
  • “gap” the map
    • allocate a new grid 2x the width and height of the original
    • copy the old tile map to the new, inserting blank rows (and columns) every other row (or column)
    • fill the gaps according to surrounding tiles
  • for each instance of larger bodies of land-locked water, either
    • fill it with swamp, or
    • path it to the ocean
      • determine the shortest path to sea level
      • follow the path toward sea level
      • “carve” river into the terrain
  • save the map to the Tiled “.tmx” format (currently only .XML format works; I’d like to add base64/gzip in future)

As it stands, there is a complete start-to-finish workflow in place. I’m adding in map “niceifications” as I go.

 

Next Steps

I’ve completed work on the migration to AMD specification; the exception is the Window class, responsible for the core UI feature-set. I’ll get to this soon enough.

My current focus is to work through resolving a problem surrounding the .NET Queue class. I’m able to send WebSocket messages once more, but the Queue class is failing to call its own Enqueue method. At this point the cause is uncertain, thus more investigation is necessary.

I’m proud to announce the addition of a sought-after feature: ‘sprite’ animation! Sprites form from groups of animations, which form from sequentially-rendered series of tiles, which are subdivisions of images. The whole thing works quite well. You can see a demo of it here.

Fun fact: I added in a simple random deviation for sprite frames, giving the demo a decidedly Ultima IV feel.

Next up is windowing, then TGE will be back up to where it was pre-hiatus.

TGE + AMD = FTW

It’s been almost 10 months. What has TGE been up to?

With some recent developments in my own learning, I decided to refactor TGE’s layout and architecture. The original JS code-base wasn’t huge, but it was apparent early on that it was simple to get “lost” when performing updates. I was using global namespacing to access different “modules”.

After much consideration, I additionally decided to utilize the Dojo Toolkit (version 1.8.1) in TGE’s reconstruction. I’ve been using Dojo for a number of years, and a number of important features have come into play

During the refactor, I set out to achieve a few specific goals:

  • AMD. In order to achieve module interaction, I opted-out of using global namespaces, and instead restructured TGE to adhere strictly to AMD when designing each component.
  • Observer. Components would interact with one another primarily using events (dojo/topic subscribe/publish) managed by adopting the Observer Pattern. This enables modules with odd loading behaviour (for example, images, which provide an onload() mechanism) to signal their completion when doing something, allowing other reliant modules to react accordingly.
  • Mediator. Adopting the Mediator Pattern through resource “managers” in order to utilize a single-point-of-control scheme by which game objects interact with one another.
  • Factory. By using the Factory Pattern, it becomes clear which modules are responsible for object creation, what is involved, and under what circumstances are objects instantiated vs. cloned.
  • Scene Manager. An important part of any game engine is its scene manager, which takes care of
  • Layers. It wasn’t apparent at first, but storing scene objects in layers allows for interesting capabilities such as layer sorting, blending, toggling, shifting/offsetting, and so on.
  • UI. Reluctantly, I am considering shelving my idea to write a from-the-ground-up JavaScript UI library that renders inside an HTML5 canvas. If I go this route, I intend to use Dojo Toolkit’s Dijit library.
    • Pros
      • Dijit brings a plethora of UI widgets to my fingertips.
    • Cons
      • I still need to restyle Dijit, since I don’t want TGE to look like Claro/Tundra out-of-the-box.
      • Performance, since this UI would be rendered in the DOM and not in the (potentially hardware-accelerated) canvas.
      • I’ve already written the bulk of the code responsible for window management, sorting, and input handling, so this seems a waste.
      • I lose (without things getting hacky) sprite animation.

Given this list, weighted heavily in favor of not using Dijit, I’m not wholly convinced to abandon a custom GUI.

In any event, it hasn’t been long since beginning the rewrite, and I am nearly back up to where I was before. The next steps will be completing animation sequence management, and WebSocket communication (which is working, but the WebSockets component on the server needs to be upgraded, and the client needs to encrypt/decrypt packets properly, which was implemented before and is simply in need of porting and testing).

Bidirectional? Bi-winning!

I have been diligently working on client/server interaction. The newest developments include:

  • Retrieving lists of views (useful for populating list-controls in UIs)
  • Character creation (“John Smith” has awoken in the realm FTW)
  • Character selection (depends on views; yay reusability)

One dilemma I encountered, which quickly evaporated after (approximately) 37.6 microseconds of consideration, was that of applying traditional asynchronous methodologies in WebSocket-driven communication. For example, when creating a character, a player must be able to choose a Family, a Gender, and a Race. But how to load each of these in turn, in the client, then display the “create character” UI once loading is complete?

In an AJAX scenario, one would assign a series of onload events to simulate procedural function calls in order to obtain series of disparate data sets before displaying the UI dependent on them. But in WebSockets, no such asynchronous callback system exists; a WebSocket message is received, parsed, and handled as appropriate. There isn’t a clear way to link an incoming packet to a callback function that might be waiting for it.

Fortunately, who cares? Because WebSockets are bidirectional, instead of waiting on the client to initiate individual requests to build a UI, the server can simply blast out series of views, then tell the client to show a UI that is dependent on these views. Since messages are received in an orderly fashion, the views already contain data from which things like comboboxes and listboxes will be spawned.

 

To ORM, or not to ORM?

I recently got involved in a minor scuffle with a well-meaning nay-sayer. I find it irritating when folks with little vested interest get involved in a (potentially) lengthy discussion,  use straw-man logic and outdated internet articles, and make assumptions without a lengthy research and development phase to determine things like performance statistics.

So here’s why I am using ORM: Continue reading