Godot Tank

I decided I’d like to make a tank game in godot, just for fun. So I downloaded a tank model off the internet, and after lots of messing around in Blender, I managed to export it in a format that godot could automatically parse into a tree. Cool! In this post I’m gonna cover two little tricks I used while working on the tank.

Rotating the Tank

In my game, I want the tank’s movement to be somewhat difficult. So, it will turn in a way similar to actual early tanks. It won’t be able to move its treads in opposite directions. Instead, to turn around more or less in place, it will need to brake on one side, and advance on the other. This is how most tanks during WWII turned. This presents a problem for the game, though. If we simply rotate the tank to the left, the tank will be turning around it’s origin, in other words, spinning in place. It should instead rotate around the left tread which is braking. Here’s some lovingly crafted images to demonstrate.

image showing incorrect turn of object

A normal turn in godot engine. The tank rotates around its origin, contrary to realistic motion. The orange ‘X’ shows where the tank ought to rotate around. To fix this, I saved the position of ‘X’ before turning (The orange ‘X’) and subtracted it from the position of ‘X’ after turning (The red ‘X’). I then applied that translation to the tank. This is a pretty simple solution and it works well. The end result looks like this.

image showing correct turn of object around lefthand side

Here we can see the tank is rotated around the lefthand side. The difference in one image is slight, but the effect in motion is much more convincing. The X doesn’t move, but the middle of the tank, the ‘O’, does. This is what should happen. Here’s the code in Godot Engine for this turn.

func rotate_around_side(delta):
	#set rotation origin if braking on only one side
	if Input.is_action_pressed("brake_left") and not Input.is_action_pressed("brake_right"):
		rot_base = $LeftSide
		rot_direction = -1
	elif Input.is_action_pressed("brake_right") and not Input.is_action_pressed("brake_left"):
		rot_base = $RightSide
		rot_direction = 1
	
	#get current position of point we want to rotate around
	var tmp_rot_global = rot_base.global_transform.origin
	#rotate normally around the origin of the tank
	rotate(Vector3.UP, rot_speed * rot_direction * delta)
	#correct the transformation by moving the tank by however much the point 
	#we didn't want to translate was translated.
	transform.origin += tmp_rot_global - rot_base.global_transform.origin

So this is pretty simple code. Godot doesn’t come with a built-in way to rotate around points apart from the origin, so I found this was the simplest way to do so.


Spinning the Treads

Another cool trick I tried for this project was a trick for spinning the treads of the tank. Rather than animating them normally, I used the tank’s position to offset the UV map of the tank tread texture, as well as rotate the wheels. I created a new parent node for each side to organize things nicely, which looks like this.

Image showing node tree and tank tread and wheels in godot engine

The code for this trick is below.

onready var track_mat = $Track.get_surface_material(0)
var last_frame_global = Vector3.ZERO
var travel = Vector3.ZERO

func _process(delta):
	#compare current location to previous
	travel = translation - to_local(last_frame_global)
	#simply add travel to texture offset. Track speed adjustable via editor in parent
	track_mat.uv1_offset.y -= delta * travel.z * get_parent().track_speed
	
	#same process to rotate each wheel
	for _i in $WheelGroup.get_children():
		var diameter = _i.get_aabb().size.x #each wheel may be a different size
		#rotate by travel, but scale by inverse of size, i.e. bigger wheel rotates slower
		_i.rotate_x(travel.z * delta * (1 / diameter) * get_parent().wheel_speed)
	
	#save "previous" location
	last_frame_global = to_global(translation)

Unfortunately, this had some kinks. The tank looked right from some angles…

…But not from others.

What needed changing was the UV map on the original model. It wasn’t made with this scrolling in mind, so some sections had to be flipped around. This took approximately forever in blender, but the result was good. It would have been possible to line things up even more nicely, but all the remaining jank is covered by the wheels.

After adjusting both the speed the UV offset changes, and the speed the wheels move, a pretty convincing effect is created.

Thanks for reading. Godot is pretty fun to use and easy, compared at least to Unreal Engine and Unity. I recommend messing around with it. It’s also easy to work with just Godot Engine and nothing else, since the editor is decent and the program has a portable .exe version.

Thomas

Software developer, musician, and tinkerer.


Some tidbits of things that work in Godot Engine.

2022-08-17