Whilst tinkering with (yet another) game idea I’ve been having fun using BitmapData value maps. My game world consists of a space that is 100 metres square and I have a range of different BitmapDatas that describe different properties of the world. I use BitmapData.getPixel() to get information about the point in the world that corresponds to the NPC’s (Non Player Character) current position. Although slower than other types of value maps you can get some interesting effects when using the built in methods of the AS3 BitmapData class (perlin noise and filters for example).
Simple Value Maps
Sometimes world information is not modfified throughout the game session and when this is the case I use a static value map. In my game I have a cover map that determines how much protection an NPC receives for standing in a particular location. This currently looks like this.
Black areas represent parts of the world that have no cover. The brighter a pixel becomes the more cover is provided. So friendly units standing in the trenches and central fort area will avoid a percentage of attacks.
These static maps could be used for a myriad of applications e.g. height (to give higher NPCs a combat advantage), surface types (to modify an NPC’s speed based on different conditions) or environmental hazards (NPCs could take damage whilst walking through barbed wire or caltrops).
Flow Field Value Maps
I wanted the enemy NPCs to approach the central fort as if they were dodging and weaving to throw off the the aim of the defenders. I’m using a value map to alter the heading of incoming NPCs. I effect an NPCs rotation based on a value map that converts the brightness of the pixel into a value between 0 and 360 degrees. This can be achieved using a base shape like this.
Adding some noise to this base image produces a more natural wandering movement in the approaching enemies.
This method was inspired by a conversation I had a few years ago with Shane McCartney who was using similar techniques in his games. I also loved the perlin noise flow field demo done by Justin Windle over on SoulWire as an illustration of what can be achieved with this technique.
Dynamic Value Maps
During their time in the game world NPCs can be exposed to threats such as grenades, rockets and area of effect attacks. I’m using a dynamic value map to help NPCs avoid these threats. When a threat is introduced into the game world I draw a small circle into the threat value map. Every few frames I use BitmapData.applyFilter() to blur the source BitmapData to feather the circle and gradually fade it out when the threat is removed. Any NPC that is standing in an area that corresponds to a high threat level will turn away from the threat and run off until the threat level decreases. I use one value map for all the factions in the game but just query different channels depending what alliance they belong to. E.g. the ‘red’ faction only respond to threats in the blue and green channels, the ‘blue’ faction respond to threats in the red and green channels etc.
A grenade showing up in the threat map:
Now I bet you are thinking “Tom you fool! Using BitmapData where a Vector or 2 dimensional array would suffice is lunacy!”. Well, fair point, especially for the simpler implementations (like the cover map). But using this technique I could easily update the cover map on the fly. For example if a large explosion occurred in the game world I could print another gradient circle into the cover map to represent the cover created by the resultant crater. As soon as the value map becomes a bit more complex or dynamic this is actually a reasonably fast way of going about things. It’s also nice being able to chuck the BitmapData on stage via a Bitmap object for debugging purposes. I can also overlay the value map on a minimap to accurately see where NPCs are. I’m sure I’ll not being use this technique so often in the finished game when some serious optimisation has taken place but until then this is a fast and convenient way of getting the values I need and, perhaps more importantly, visualising them.