How to prevent tunnelling through objects (both have colliders)

I’m having difficulties preventing a ‘Tank’ object from driving through walls that it should not be able to drive through. I’ve spent a couple days searching forums/blogs whilst trying to figure out how to do this, but only one approach, (1) below, which I consider unsatisfactory, works for me.

In my scene, I have a ‘Tank’ object and several unconnected walls (set to static). The tank, and each of the wall objects have a Box Collider component attached, and all their Is Trigger attributes are set to OFF. Only the tank has a Rigidbody component, and I’ve tried all the different collision detection options and have also tried setting the tank’s Is Kinematic ON and OFF. The floor is a mesh plane with a mesh collider attached.

Below are three attempts I tried:

  1. Moving the tank using Rigidbody.MovePosition():
    This method is the only one that works for me, and even then, only works as long as I keep the moveSpeed of the tank less than 10.4 (approx). From all the reading I’ve done on this subject, using MovePosition() in this use-case is considered a bad option because it bypasses the physics engine. Ironically, bypassing the physics engine is the only way I’ve been able to get it working holistically. The downside, from my perspective, is that I have to reduce the speed of the tank to a painfully slow rate in order for this method to work.

  2. Another approach I tried was to save the last position of the tank at each Update(). Thus, when a collision with a wall occurred, the script moves the tank back to its last saved position. This approach worked in situations where the tank stopped moving forward after it had partially entered the wall. But, like (1) above, if the tank persists to move forward into/through the wall and if the moveSpeed is over 10.3 (approx), the tank eventually creeps through the wall. With a slower speed, the tank is prevented from passing through the wall.

For some reason, the OnCollisionEnter() function is only invoked once, on the initial impact (i.e. collisions are only detected at the boundaries of colliding objects). Strangely, backing the tank off by changing its position, per (2) above, does not change this behaviour. In order to get another collision event, the tank needs to move well clear of the wall first and then make another attempt to pass through it.

  1. The last method I tried uses the tank’s rigidbody velocity attribute to generate movement;

    float move = Input.GetAxis(“Vertical”);
    Vector3 fwd = _transform.forward * moveSpeed * move;
    _rigidbody.velocity = fwd;

Whilst collisions now work correctly, there are several strange behaviours that occur;
a) The view starts shacking (sometimes rather violently) once I start moving forward, causing my tank to launch into the air.
b) The tank does not always move at the desired speed. Instead, its velocity is noticeably reduced at times (as though its trying to move up-hill, despite the fact that I’m setting velocity not force), and at other times it moves are its normal speed.
c) The tank, probably because of the shaking, ends up floating above the floor and behaves as though it’s on ice, though I have “Use Gravity” set on the tank’s rigidbody.
d) Probably because the tank is no longer “on the floor”, it is able to move away from the floor area without falling off the edge.

*** OP solved problem: setted both velocity and angular velocity to zero first and then set the rotation and velocity through user input ***

Original answer:
I’m not too well versed in movement as I pretty much always use physics velocity for collisions but here’s my two cents.
Just making sure but try checking your tank collider and if the bottom of it goes through the floor which I assume it doesn’t. Also see if it collides with anything else nearby such as the turret collider if it has any. You could try limiting the new y velocity of the Vector3 before you set the rigidbody velocity if you are just moving on a flat terrain.

 Vector3 fwd = _transform.forward * moveSpeed * move;
fwd.y = 0;
 _rigidbody.velocity = fwd;

Also physics calculations should be done in FixedUpdate so try putting it there. You can leave the move = getaxis(vertical) in the Update.

If that doesn’t work you could try experimenting with the OnCollisionStay function for the second approach that you did with saving the previous tank position. Hope this helps.