mapeditor-day4-headerWhen I was at Electronic Arts there was a legend about a function in FIFA called DoBestKick. It was the ur-function for determining what kick an AI player would do. The story tells that no one really understood the inner workings of the function and that the mandate was “no one touch DoBestKick.”

I have a similar function, WhichWall. It determines, based on the orientation of the walls in a square and the orientation of the walls in the neighboring squares which wall to draw: inner corners, left corner, middle, solo, etc. There are 52 possible combinations with dense conditions such as, if this wall is north facing and there is an east wall and the western square has no east wall and the north-western square has an east wall then this wall is an outside corner skewed to the left. If at all possible, I did not want to revisit that function. We don’t always get what we want.

There were two new features being added to the map editor; 1) adding map objects that are not walls or floors, and 2) saving and loading the maps as XML files. These two forced me to touch WhichWall.

Simple UI added to the right-hand side. (Click to enlarge.)

Simple UI added to the right-hand side.
(Click to enlarge.)

During the re-factor of the map code, I concluded that storing the wall conditions as properties of the map square wasn’t very efficient. Moving them to an array of booleans let me access the walls with the same logic I use for pathfinding movement. This let me greatly simplify all of the wall handling. This meant reworking WhichWall.

Adding arbitrary objects to the map meant adding a new class to the map squares to hold those objects, both for rendering and for storing in the XML files. It made sense that the walls would also be part of this list of objects. Reason two for revisiting WhichWall.

The in-game map with columns. (Click to enlarge.)

The in-game map with columns.
(Click to enlarge.)

At last, success. Though I only have one type of extra object at the moment ( a column), I can now add non-wall objects in the map editor. I’ve also done the calculations for which wall in the editor and save that information in XML file, eliminating the need to determine which walls should be added when the file is loaded.

Time to layout the Big Map in the new map editor, 12 minutes. Not as fast as I’d like, but much better than editing by hand. I have some specific ideas to speed up map editing, but those will have to “go on the list” for now. I have enough of the basic features in place that I have to dive into networking.

mapeditor-day2-headerAs much as I liked the idea of drawing walls by following the mouse—allowing the user to turn corners while adding walls—it was too much like drawing a straight line with a mouse in MS Paint. I’ve opted instead to restrict the wall addition to a single axis. That is, as the user starts adding north a facing wall and moves the mouse either east or west, new north facing walls are added.

A couple of other new additions, when adding walls both sides of the wall are added, e.g. when adding east facing walls, the corresponding west facing wall is added. (See also, Splitting Walls.)

You can add floors now, too. Currently, floors are added when clicking on the center of the square, rather than on edges. I’m considering spltting walls and floors into two separate modes. We’ll see how that plays out when I add new terrain pieces and types.

There’s a new UI element, as well. You can now see what type of piece you’re adding before starting construction. With the right mouse button, you can also remove existing pieces.

Continuing to use the Big Map as my test, the time to build has been significantly reduced. With the new method of adding pieces, it’s much easier and faster to add them with the map zoomed out. The video below has been sped up, so you don’t have to watch it in realtime. The total time to draw what you’ll see is just under a minute.

 

Unity Map Editor – Day 2 from C. Lewis Pinder on Vimeo.

mapeditor-headerYou may have asked yourself, “can a map editor be written in a day?” It’s a question I asked myself. The answer is, in this case, not entirely; but let’s see how far we’ve come.

I spent some time yesterday teasing apart my mapping code to disentangle it from the “playing surface” and to get a head start on the XML serialization for loading and saving maps.

In the editing module, you can load a reference 2D map and draw directly on the surface.

 

hotspot-sketchI did quite a bit of sketching to determine the “hot spots” on the grid that indicate what walls are being added: north, south, and so on. Walls are added by clicking on a “hot spot” and dragging to add wall sections. If you change direction, the wall is continued in a logical fashion, wrapping around the corner.

A significant amount of work is still outstanding, but the ground work is laid for a fully functional editor. The Big Map that I spent an afternoon entering, can now be created in a few minutes.

 

Unity Map Editor from C. Lewis Pinder on Vimeo.

testdrive-headerYou can only work in a vacuum for so long, before hands-on feedback is necessary. And this is that time. Now’s your chance to take some miniatures out for a spin and let me know what’s working an what isn’t.

Miniature controls
Left-click on mini – selects mini
Left-click and hold/move left or right – rotates mini
Left-click and hold/move up – lifts mini

Camera controls
Right-mouse button or Left ALT key – orbits camera
Middle-mouse button – moves camera
Scroll-wheel – zoom camera

Dice
Left click on any die to roll two of that die. (Note: the d4s do not return the correct result.)

Map
The visible portion of the map is determined by the line-of-sight and by distance. The mini can “see” up to 120′.
Any part of the map that has been “seen” will be shown as a 2D map when no longer visible.

Click here to launch.

I’m looking forward to any and all comments. [Edit: A quick note based on some feedback that I’ve had so far: 1) the final product will be a standalone program, it’s running in the web player so I can get comments; 2) the ALT orbit is a workaround for the Unity player pop-up that appears when clicking the right-mouse button. If you right-click and choose full-screen, if pop-up goes away.]

big-map-headerTo test out new features and performance, I needed a bigger map. I used the random dungeon generator at Donjon to create a modest 46 square x 58 square dungeon.

Click to enlarge.

Click to enlarge.

I learned a few things from this test (other than I need to replace the cyan ink in my printer). The first is that drawing the terrain on top of a 2D map looks like good solution. The map is broken up into a grid that matches terrain, so any part of the map can be hidden. I’m still leaning towards revealing only portions of the map that the player has seen as the default behavior.

Click to enlarge.

Click to enlarge.

And second, I can’t write the level editor soon enough. The levels are currently stored in a text file, which has worked up to this point. Inputting larger maps, however, is a tedious exercise in data entry.

 

I dropped in my first “painted” miniature today. Unlike the dwarf and the ogre miniatures, this one isn’t a copy of a Ral Partha miniature. It’s an original sculpt.

 

It’s really hammered home the need to open up the hood and author new shaders. I’ll be nice and say that the default Unity shaders are “unsatisfactory.” I’ve taken a look at the shader syntax and it’s a variation on cg-fx, so the authoring shouldn’t be much of a stretch. I am, however, a little rusty with shaders and Unity has stirred just enough of their own flavor into the sauce that it will take me a little while to sort it out.

 

You can see the archer in chain-mail and his pals, the dwarf with broken torch and the angry ogre with club. Right away you may have noticed that this is the first time you’ve seen a party of miniatures, rather than a solo piece.

 

Those of you paying extra close attention might also notice that we’re seeing an underlying map being shown in areas that are outside of the player’s line-of-sight.

Okay, back to it. I have an idea about polyhedral dice rolling.

The one feature that I knew I wanted for dice was rolling the dice directly on the map and watching them clatter about and bounce of the walls, floors, and miniatures. I wanted to avoid using the Unity physics primarily because it’s non-deterministic and, like most physics engines, a bit squirrely and unpredictable.

I spent a fair amount of time investigating other possibilities and I was getting close to a workable solution, but it was ultimately going to consume too much time and effort to develop a custom die-rolling system. I chose, instead, to go ahead and implement dice rolling with using the built-in physics. The Unity documentation specifically calls out scale as an issue with their physics engine. The presumption is that 1 unit = 1 meter and the physics are calculated using that scale. It’s not modifiable.

Fortunately, when I began the project, I knew that the scale of the map may one day be a factor and that day was today. I included a global scale factor that let’s me arbitrarily modify the overall scale of the world. I’ve been working at a scale of 40 (an entirely made-up test number). To get the physics simulation of the dice to look at all correct, I had to set the world scale down to 0.5. To get a true representation of 25mm figures, I’d need to set the scale to 0.025. Unfortunately, the physics simulations fall apart at that size.

The second issue with the smaller scale is that the font rendering in Unity does not like tiny fonts. Fonts that once rendered well, now are all blurry. For dynamic fonts, Unity uses OS specific font renderers and the Windows renderer does not like font sizes that small. I may have to create custom textures for the movement costs. Other than the text, I have a few issues still to resolve.

1) I’m determining the value of the roll by checking the orientation of the die when it comes to rest. Sometimes the simulation results in a “cocked die” that isn’t lying flat on the surface. Currently that is resulting in a value of 0, but it’s addressable. For dice that are really cattywampus, the die can just be re-rolled. For those that are pretty close to flat, I’ll have to adjust the calculations to allow for a greater range of orientations.

2) Sometimes the dice fall off of the table. Constructing an invisible box to contain the dice, or just an invisble plane, should be enough. It’s just on the to-do list.

3) At the moment, I’m only rolling six-sided dice. Determining the facing side of a d20 is significantly more involved. I have some work with pen-paper to figure out the best way to handle polyhedral dice. Worst case is a look-up table. For the standard six dice, this shouldn’t be too bad. It’s only eight if I included the d30 and d100.

Most importantly, rolling the dice is pretty fun. It has much of the same satisfaction of rolling real dice on a table. Take a look as I roll some dice. Lots of dice.

Probably the most head-scratching, frustrating feature I’ve tackled so far has been calculating line-of-sight. It’s something that can’t work 90% of the time, or fail on some edge cases. It has to work 100%. And that’s the part that kept me busy with the graph paper checking the math.

My first approach was to “walk the squares” out from the miniature and test collision with any walls encountered. This “marching squares” algorithm was working well and as expected, but it failed on corner cases. As the LOS rays traversed across the map, there were cases wherein the ray would miss potentially visible squares by passing precisely through the corner and ignoring the squares on either side. I spent a while trying different solutions, but none of them were satisfactory.

I moved on to casting rays from the miniature through the end points of each wall section to the edges to check for collision. The rays were then sorted by angle and the collision points connected to form visibility triangles. When considered all together, these triangles formed the potential visibility. Again it was failing on the edges. This time, rather than a miss, I was getting early rejection. The ray was intersecting the end of the wall segment and stopping. It was working well enough, unless the miniature was standing in a doorway or narrow opening between walls.

I tried a few a few tweaks: shortening the walls slightly at the end of the segments, tweaking the angle of the rays. None of these solutions were 100%. Finally, I settled on splitting the rays—guaranteeing that one ray would collide with a wall and the other, if it was open on one end, would slip past. This has doubled my ray count, but it should be a negligible difference once optimizations are in place. A linear increase is far more desirable than an exponential or logarithmic one.

In order to prevent the player from “peeking around corners,” the line-of-sight is only reset when the player drops the miniature and movement is restricted to those squares that are visible. There is still a slight issue. When a visibility triangle intersects a square, that entire square is visible. So the player can sometimes see slightly around corners.  I have a couple of avenues to address this issue. Real-time shadows and render-to-texture are cleverly disabled in the free version of Unity, so with an upgrade to the Pro version this may no longer be a problem. Additionally, I have the triangles calculated. Those calculation are accurate and could be used to create a stencil, either for rejecting pixels at render, or for creating a projection mask for the spot light that hovers over the miniature.

I am contemplating revealing a 2D map for any squares that the player has already seen, but are not currently visible. This help prevent the player from getting lost. I only hope that it doesn’t spoil the dungeon feel that is achieved by only rendering part of the map. I’m also calculating visibility for 360 degrees around the player and not considering miniature facing. It will be trivial to do so and will likely be an option.

There are number of optimizations remaining. Primarily the walls for collision testing need to be sorted by proximity to the player. As it stands now, the routine runs at framerate for smaller maps, but slows to a crawl on large maps. For now, it is functional and, as I like to say, “I’ll burn that bridge when I come to it.”

Unity-LOS-debug from C. Lewis Pinder on Vimeo.

Unity-LOS from C. Lewis Pinder on Vimeo.