Cannot get tank control system to work

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By mextie-dev

Hi,

I am trying to create a tank-style movement system in 3D space, similar to the original Resident Evil games. The character can only move forwards and backwards in the direction they are facing, and angles themselves left and right using A and D. However, after a lot of trying, and using every solution I can find on the Godot forums and the Reddit, I absolutely cannot get this system to work. I have had so many issues trying to get it to work, including:

Character losing collision when moving
Character sliding around without even touching any buttons
Game running at locked 60fps while turning the character, but dropping to less than 1 frame per second while moving forwards or backwards
Character simply moving on the universal Z axis, regardless of rotation

I cannot figure this out. If anyone has any advice or knows how to do this, please let me know. Thank you for the help.

:bust_in_silhouette: Reply From: Yuminous

Um, I’m not sure exactly what you’ve tried so far or where you’ve gotten to now, but is it something like this that you’re trying to achieve?

Tank Movement
I made up this little project to demo some tank movement like you were describing. There’s quite a number of extra things in here I couldn’t help but adding in but the tank movement is very straightforward, so here’s how it works:

This tank is a RigidBody, but Rigid physics can be somewhat unreliable so you could also use a KinematicBody. Regardless of which system you choose, the movement aspect boils down to this:

Left / Right = rotate the body on the Y-axis (several different methods you could use):
tank.rotate_y(slew_acceleration), or:

tank.rotation.y = min(tank.rotation.y + slew_acceleration, maximum_rotation_speed), or in this case:

tank.angular_velocity.y = min(tank.angular_velocity.y + slew_acceleration, maximum_rotation_speed)

Drive / Reverse = accelerate the body in the global Z-direction (while on the ground):

Rotating the tank will not change the local Z-direction, so it’s essential to get the global Z-direction, like so: tank.get_global_transform().basis.z.normalized(), therefore:

tank.translate_z(tank.get_global_transform().basis.z.normalized() / translation_limiter), or:

tank.translation.z = min(tank.translation.z - tank.get_global_transform().basis.z.normalized() / acceleration, max_speed), or:

tank.move_and_slide(tank.get_global_transform().basis.z.normalized() * acceleration, Vector3.UP), or:

tank.add_central_force(tank.get_global_transform().basis.z.normalized() * acceleration)

So, thus! Here’s the full code for the tank movement in this demo (excluding the turret, camera and more) and also note these properties are exclusive to RigidBodies:

if Input.is_action_pressed("tank_drive"):
    tank.add_central_force(tank.get_global_transform().basis.z.normalized() * acceleration)
elif Input.is_action_pressed("tank_reverse"):
    tank.add_central_force(tank.get_global_transform().basis.z.normalized() * -acceleration)
if Input.is_action_pressed("tank_slew_left"):
    tank.angular_velocity.y = min(tank.angular_velocity.y + slew_speed, max_rotate)
elif Input.is_action_pressed("tank_slew_right"):
    tank.angular_velocity.y = max(tank.angular_velocity.y - slew_speed, -max_rotate)
	

An important part that was excluded here is that you have to check if your tank is actually on the ground before applying movements, or else players can easily make the tank fly (unless you want that?).

But that’s all you need to get tank-like movement!

The other part to this equation is having a good CollisionShape so that your tank can navigate terrain properly. Here’s what this one looks like:

CollisionMesh
Tapered or rounded edges are very important so that the body can move over small obstacles. Squares will completely stop at an edge of any size.

You can see that my CollisionShape wasn’t actually very good (and that Rigid physics aren’t the best) because the tank was jumping over the seams in the Static map.

KinematicBodies might do a bit better as forementioned (move_ and_slide).

I hope that it helps! Good luck!

Thank you so much for this answer! By far the most detailed response I’ve ever received. However, if it’s not too much trouble, would you be able to somehow provide the project file for the demo you showed? I’m having a bit of trouble getting my CollisionShapes to cooperate, and I think I’m missing something big (I’m very new to game dev so I’m not great at inferring stuff, lol). If you can’t provide it, that’s no problem at all.

Thank you!

mextie-dev | 2021-07-21 23:19

Of course I can! I just uploaded it on Github:
https://github.com/Yuminous/Godot-Shorts/tree/main/3.3%20→%20Rigid%20Tank%20Movement

–Although, it’s by no means a great example by any measure.

That was the first time I tried doing tank gameplay and rigid movements. There’s lots of stuff you’ll probably want to add, like fixes for tank acceleration while airborne (this one can actually fly), turret angle limits and more… And I haven’t commented on anything (sorry).

Anyway… I hope that you find it somewhat useful!

Yuminous | 2021-07-22 04:10