The last couple of days I have been pounding away at Splatterfield after work, and I’m happy to say that I’ve made some progress. First in terms of making the battlefield more visually interesting by converting it into a RAINBOW BATTLEFIELD, and second by adding basic collision detection. It’s complicated and frustrating but very important to get right.
RAINBOW BATTLEFIELD… a bit of fun
I decided that my previous battlefield was functional but also a bit dull. In order to spice things up a bit I added a tiny bit of code to produce a RAINBOW BATTLEFIELD.
It’s actually incredibly simple. Each block loads the same model of a cube. This model is “painted” using a simple texture to give it the line borders and to make it look like a graph. However, there is also a color filter that can be applied to the block as well, mixing both the colors on the original texture and the new color.
This color can be specified in the standard format of RGBA(red, green, blue, alpha). So, if I know what position a block is in (X, Y, Z), and I know how far each axis stretches (the limit of X), then I simply do
r = x / x_limit.
Well, it’s a teensy bit trickier as everything kept showing up as black… until I realized that Python was doing some integer math. Nothing a little
float(x) couldn’t solve.
r = float(x) / float(self.x_limit)
g = float(y) / float(self.y_limit)
b = float(z) / float(self.z_limit)
And oh, the majesty that resulted from it.
These kinds of things I always find so cool, because a simple mathematical expression produced a beautiful result. And if I peeled away the layers of blocks the colors would continue to transition smoothly. Nice.
I needed to add some simple collision detection too. Even if it isn’t as awesome as the RAINBOW BATTLEFIELD.
Splatterfield will need a fair amount of collision detection since it’s a game about blocks and shooting things. I will need some basic collision detection for clicking on soldiers, issuing orders, placing blocks, and for ballistic projectiles. I know that Panda3D has some graphical user interface modules as well, though I’m not sure if there are special cases for collision detection needed there as well (e.g., clicking on a menu item doesn’t click on the ground below it).
I decided to start with the selection of blocks in the world. To implement this, I was following a sample of a chessboard provided with Panda. However, my case is a bit more complicated and it required quite a lot of customization.
The way it works is this:
- There is a multidimensional array that represents the blocks of the battlefield. It’s essentially one big grid.
- When a block should be visible, a node containing the block’s information (such as model, color, and position) is added to the render tree to be drawn to the screen.
- To this node is attached a special collision node.
- The collision node is populated with shapes that define when things collide into it. While it may seem redundant to have two nodes for each block, these two nodes allow for the separation of the display and game logic. It’s taxing to check complex shapes for collisions every frame. In the case of the block grid, I’m displaying a cube but using a sphere for collision detection(for now, though it may be faster to use another method).
- Another separate collision node and populated with a with a ray. This node is attached to the camera.
- A task is created that sends the ray “into” the window from a position relative the camera. This task runs every frame.
- If the ray from the camera would connect with another collision node, I grab the block it collided with and set the color to white.
- If a new block gets selected, calculate the color that the old block should be and set it to that.
It took a long while to get everything hooked up, but I’m happy with the results so far. It only slows down when the framerate of the whole application slows down. Otherwise it is highly responsive and works pretty well.
I think the next step for me is to adjust the collision detection to make it modify the render tree and the internal representation of the battlefield. So, I click a block and it explodes. Or I click a block and another block gets created on the face that I clicked on. That would be pretty awesome, though I may have to adjust my internal representation a bit to account for new blocks being added to the edges. Right now, the entire thing is filled up when the map is instantiated.
I mean, if I can get the blocks to be added and removed in a consistent and predictable manner, the rest of the game pretty much writes itself after that. /sarcasm