I took a brief break from game programming yesterday and played with the biggest machine gun that I could carry in Battlefield 3, with javelins in Chivalry, and with the plasma cannon in Space Marine… all in one sitting.
But today I decided to get back to the work on Splatterfield. Since I most recently added the ability to remove blocks from the game world by clicking on them, I decided that today I should work on the ability to add blocks to the game world.
The process would require a few steps:
- The user hovers over a block and presses a key to create a new block.
- Calculate which face the user was pointing at.
- Attempt to add a new block one unit from the block that was selected.
The trickiest part of the whole process was figuring out which face the user was hovering over.
As I mentioned in my earlier post about collision detection, my initial method uses a sphere to determine collisions. However, Panda3D does have a handy function,
getSurfacePoint(), which returns the X, Y, and Z coordinates of the point of collision.
Currently the sphere is centered directly on the cube’s middle, and has a radius of
√2 * (BLOCK_SIZE / 2.0). This makes it so that the sphere just barely touches the edges of the block and bulges out from each side. I’m not sure if this is optimal (and I noticed it was buggy when I tried to increase the
BLOCK_SIZE, so I’m not sure what’s wrong there. However, it works with my default sizing of 1, so I proceeded to use that for testing the rest of the adding blocks functionality.
If anyone knows how I messed up the geometry here, let me know!
By looking at where the collision took place I can determine which face of the block the user was pointing at. It works because the sphere intersects the block’s edge, but the collision always takes place outside of the block. This means that I can then test the X, Y, and Z coordinates to see which of them is beyond the bounds of the block. When I find one, I know which face the user just clicked on.
Obviously, this method has some drawbacks. The sphere is only a loose approximation of the shape of the cube and the intersection technique that I used is useful, but leaves the corners of the block not clickable depending on the camera angle.
If it keeps being a problem or affects gameplay negatively, I may end up either: A.) Increasing the size of the sphere to encompass the entire block, or B.) use geometry nodes for collision detection instead. The former would probably be faster for Panda to render, but it would take a bit more math to know, since I would have to look at multiple coordinates where the collision took place and figure out which face was clicked. The latter option would most likely be more taxing for Panda, but would make the face detection simpler.
Once I know what face the user clicked on, it becomes a relatively simple matter to insert a new block. I have to make a few checks to see if the block already exists (in which case, do nothing), and that the coordinates are not out-of-bounds (something that I would like to eliminate altogether). Then it’s off to the rendering tree for the new block, and BLAMO!, it’s in the game and can be added to itself.
I went ahead and bound the block creation and destruction functions to buttons other than the mouse (“c” and “d”, respectively), in order to be able to build out structures without deleting pieces accidentally.
I have to say, I’m quite proud of the little program so far. I enjoyed being able to move the camera around and build structures by adding and removing blocks. However, it became readily apparent to me after just a few minutes of doing this that I currently have no way to save the data structure. That might be a good place to go next. Either that or adding in some kind of character that can move around the map. Both will be critical to Splatterfield. Probably whichever seems like the most fun later in the weekend.