Untitled Tank Game - Part 2
Development on my untitled tank game continues in this post. This time, the first NPC vehicle AIs are created, and now vehicle and terrain models are created in Blender and imported into Godot.
Note:
This builds upon the work from the previous post.
Basic Enemy AI
Using the newly added ballistic solutions code (from the previous post), it's possible to have NPC tanks aim at, and then shoot at, target positions (such as the player.)
A basic AI was added where the NPC vehicles were given "eyes" (RayCast3Ds) that look towards the player. If those "eyes" can see the player directly (not obstructed by physical colliders) then the NPC will enter a combat state. They'll compute a ballistic solution, rotate and aim their turret, and when the angular difference between the solution and the barrel is small enough: shoot.
This resulted in the first player vehicle death in any of my 3D games.
Location-Dependent Damage (Hit-boxes)
A basic form of hit-box was added in the form of front/side/back detection to simulate armor on the vehicles. This was built by comparing the XZ angle between the center of the vehicle and the impact point. Shots to the back deal 50-100% damage, to the side deal 25-50% damage, and to the front deal 5-25% damage.
Radio Communication
A rudimentary form of "radio communication" was also added. When an NPC vehicle is hit, or sees an enemy, they broadcast a message to nearby units of the same team, telling them to raise their alert state (which at this point means increasing the radius they scan for the player.)
The radio is implemented with locality, the vehicles can only communicate with nearby vehicles. This is accomplished using Area3D nodes. Every vehicle has a custom RadioTxRange
spherical Area3D node, and a RadioRxRange
Area3D node, and these exist in a unique "radio" collision layer. When a vehicle wants to send a radio message it emits a signal to the parent vehicles of any overlapping RadioRxRange
areas (if they're on the same team.)
Note:
This was posted to the Godot subreddit The enemy tanks scan for targets and fire if they have a clean shot. Also hits now do a different amount of damage depending where they strike. This is getting fun, but RIP my tank crews.
Mapping Trials
Prior to this point, the maps have all been constructed of primitive shapes built in the Godot editor. And in the previous project, terrain was generated and manipulated via an addon to the editor. My goal here is to experiment with designing a terrain in Blender, importing that into Godot, generating a collision map for the ground, and using it in a level.
Ultimately, I successfully created a 2km x 2km tile of rolling hill terrain and imported it. The points of the terrain on perimeter tapered off to a vertical value 0.0, allowing for 8 additional flat tiles to be seamlessly adjoined to the terrain, creating a 6km x 6km total play area.
Some small buildings, enemy vehicles, and a rough "city" were added around the perimeter of the terrain to experiment with scale, travel time, and long-distance shooting.
This mapping experiment helped provide a window into the future look and the feel of the game. I was able to experience slowly seeing enemy vehicles reveal as you peek over hills, and firing long-distance shots at barely-visible targets.
And getting shot from behind by an enemy I didn't see.
New Tank Model and AI Driving
The next feature I worked on involved teaching the NPC vehicles how to drive. This feature involves creating NavigationRegion3Ds to enable the vehicles to plan routes, The creation of navigation meshes is (for me at this point) easier with basic geometry, so temporarily the game returned to a primitive-mesh based level design, allowing for easier testing.
Once the navigation regions were able to generate automatically, the actual driving implementation was similar to my 2D AI driving work from previous projects.
The vehicle considers its next waypoint and provides inputs (steering, throttle, and brake) to move it towards that direction. There are also some complex behaviors added to handle collision avoidance and gracefully slowing before sharp turns/stops.
The ability to use ShapeCast3D to scan for collisions, instead of an array of RayCast3Ds (as had to be done in Godot 3) makes this much easier.
At this point, with the 3D import workflow tested by the terrain, I created new 3D models for the tanks. This not only required the 3D modeling work, but also importing the components and materials correctly and updating the vehicle scenes to use the new meshes.
To make this test map more visually interesting, and to give a sense of how gameplay might feel, I added a dense inner town area with buildings and props. It includes buildings (apartments, houses, factories, water towers, walls, and pylons) as well as bushes and trees, hills, roads, and fog.
Additionally, some HUD elements were added to indicate "HIT" or "TARGET DESTROYED".
Note:
This was posted to the Godot subreddit My untitled tank game crawls forward with improved AI, navigation, and audio.
Larger Map of Rolling Hills
With AI working and able to drive, and with new 3D models for the vehicles, it was time to revisit the terrain modeling in Blender to create an even larger map.
I created large rolling hill 'tiles" in Blender that were 4km x 4km in area. These were arranged into a 3x3 grid of tiles, making a map with a total area of 12km x 12km - far enough that the player can't easily see the full thing from any one point.
This large new map (titled "Nine Hills" after the 9 tiles) allows for the testing of long-range hill-to-hill shots, and modeling some small villages and farms to use as cover. It also allows for the testing of AI driving across long distances, merging navigation regions together, experiments with adjusting the level of detail in map and vehicle meshes, and trying to adjust the fog into something that feels more realistic.
It was in this test map where I discovered that long-range shots were, for me, one of the most satisfying elements of this game so far.
Shooting accurately in third-person is also easy because of the ballistic solution calculations and automatic turret controls working together to hit the target point.
Note:
This was posted to the Godot subreddit This sort of long-range shooting is my favorite aspect so far. I think it's something I'd like to develop and polish into a core gameplay feature.
Continue Reading
Work on this project continues in the next post: