Monday 29 August 2011

Colourful Behaviour.

Currently I am working on the second phase of the MapData generator, which is to scan the map for scene objects and then adjust the walkable/unwalkable data accordingly. The basics are working fine from a simple AABB check per collision type. Although I am only using the x and z returns at the moment, a more "honest" check would also require y0 and y1 with reference to terrain elevation to be taken into account, but for now this will do as I have another system in mind to further "refine" the AABB space check. 

I also integrated a version of my Blitzmax A* system, and have a test "AI Bot" that can path the generated data in the editor and traverse the loaded map. Debugging is currently paramount, especially with regard to the data generated and co-ordinate conversion between the different ways arrays and tables within Blitzmax and lua store data and the co-ordinate system of an .sbx file. On smaller maps I simply drew a small coloured cube at the grid position, and made use of LE's view range to "cull out" an area surrounding the cameras position. A physical pick test which did not rely on any generated data would then tell me if the system was aligned correctly. At the moment I am confident that the formulas I have derived are working fine. 

The issue with this type of debugging is it is only practical on small maps, whilst alignment will (should) remain the same regardless of map size, drawing check cubes for every grid tile is a non starter once the map goes over a certain size, as it eats up the available memory to a point when the application will simply crash whilst generating or indeed with very large maps simply crash on start. The map in the videos is "128 x 128" or more precisely 129 x 129 with an MpT of 2 this equates to 66,049 "tiles" which would require 66,049 check cubes to be created. Whereas a "1024 x 1024" with an MpT of 2 equates to 4,198,401 "tiles" which would require 4,198,401 check cubes to be created and a "4096 x 4096" with an MpT of 2 equates to 67,125,249 "tiles" which would require 67,125,249 check cubes to be created. So my solution was to write a function for both the camera and the AI Bot that would create, on the fly, a set sized area of check cubes around the respective focal points.





So, whilst "playing" around with different ways to save and retrieve the data generated for a map, I tried the Portable Network Graphics (.png) image format, mainly to see a pictorial representation of the walkable and unwalkable areas of a map, but also as another way of storing the data, where the red and green channels act as the 1's and 0's stored in the .dat .txt and .lua files. It then dawned on me that an extra "cost" per walkable tile could be embedded in the green channels value, such as the slope of the tile, the flatter the tile, the easier the route. Writing a small routine to determine the slope of a walkable tile (along the same lines used to determine walkable/unwalkable) the value written to the green channel was adjusted a set amount for a particular slope range. The result can be seen below.





I then wrote a small function to read the png's pixel data on the fly and display its ARGB values.


This set me thinking, why just store slope data and walkable and unwalkable logic. Of course, you can change the value of the map data stored as values in .dat .txt and .lua files, for instance, instead of 1 meaning unwalkable, the value 0 could be used with walkable tiles having a value ( 1,2,3,4....) which reflects extra cost. But using the .png format this can be done using only two channels of the single (co-ordinate) pixels returned ARGB value.

But channels A and B are left unused, both of which can contain a value 0-255 (00-ff). So why not use them to reference area specific AI behaviour. One scenario might be, a town crier NPC, areas where that NPC is required to "do his stuff" could be defined by a certain value stored in either the A or B channels of the single (co-ordinate) pixels returned ARGB value, this value would only be recognised by that particular NPC class, so other NPC types would simply ignore it. The AI behaviour routines would be encapsulated into the lua control scripts for that class, simply waiting to be triggered. Of course it maybe required that an "area" should have several AI behavioural aspects associated with it, currently I can think of a way to attach three behavioural aspects to a single grid tile using the colour information from a single pixel, but I have a few other ideas on a way to increase that. Those ideas will have to wait as I am trying not to do what I always do and get side-tracked, but they are on the to do list.


This approach would also fit in well with my ideas about Ambient NPC Populations, where the vast majority of control resides in the hands of the "map".

This is all still very much a WIP, but shows potential.

3 comments:

I'd treat the whole RGBA value as a bitstream, so you have 32 bits to distribute between whatever you wanted. Could do the whole penalty structure just as 8 bits (0 being unwalkable, 1-255 being different penalty values for slopes or terrain types. Then you still have 24 bits you can use as a bitmask. Maybe bit 9 (bit one of G channel) being set could indicate this is a cover position. Or extend it to use 2 bits and store what directions that grid node provides cover from.

Hey Nio, long time no chat, I hope you and yours are well, and everything is great in “Nioland”.

What you suggest seems to coincide with one of the ideas I am trying not to let myself get sidetracked with. I visualised the hex as a bank of 32(bits) switches. As FFFFFFFF is:

11111111111111111111111111111111

I had not thought about using it to assign cover regions but mainly for triggering AI behaviours of a more “ambient” nature, but that's definitely something to keep in mind. One aspect I have to keep in mind is always the speed of operation, so when I finally get around to pursuing this, it will be nice to have some feedback on this front, after all if this method can be efficient enough, maybe the option for using more than one map image might be viable, thus increasing the options.

Hope all's well with you as well. Been missing you guys, but been hanging out in Unity land these days. Keep wanting to dust off LE, but until the asset importing and workflow is a little smoother I can't make myself. Hoping LE3 bridges the gap enough to bring me back.

Using at least part of it as a bit field shouldn't hurt performance too much as it would all be shift operations and masks to extract the desired data.

How's your A* solver looking? Have you looked at http://www.codeguru.com/csharp/csharp/cs_misc/designtechniques/article.php/c12527__2/A-Star-A-Implementation-in-C-Path-Finding-PathFinder.htm ? It's C#, but some of the optimizations he's using might be applicable to yours.

You doing the solving in the engine thread or as a separate thread? You can add a bunch more features if you don't have to worry about the solver hurting framerate. I really don't notice if the path takes a little longer to solve as long as the game doesn't pause while it does it.

Post a Comment

Share

Twitter Delicious Facebook Digg Stumbleupon Favorites