Preventing Player Vehicles From Passing Through Walls In Unity
Colliding with Walls
Making vehicles collide properly with walls in a Unity scene starts with configuring the collision layers and rigidbody physics. By correctly defining which game objects can collide with each other, we can lay the groundwork for realistic vehicle-wall interactions.
Defining Collision Layers
Unity uses layers to dictate which objects should collide in a scene. We need to properly configure the layer collision matrix to enable collisions between vehicles and walls. Here are the key steps:
- Create a “Vehicle” layer under Edit > Project Settings > Tags and Layers
- Create a “Wall” layer
- Under the Layer Collision Matrix, check the box to enable “Vehicle” vs “Wall” collisions
Now walls and vehicles can collide with each other by default. Any GameObjects assigned to those layers will intersect properly during physics simulation.
Assigning Collision Layers
After defining collision layers, we need to add vehicles and walls to them:
- Select each vehicle GameObject
- In the Inspector, assign the “Vehicle” layer
- Repeat for each wall GameObject, assigning the “Wall” layer
The scene layers are now configured correctly. Vehicles belong to the Vehicle layer, walls belong to the Wall layer, and collisions between those layers are enabled.
Configuring Rigidbody Physics
The final step is ensuring vehicles and walls use rigidbody physics:
- Add a Rigidbody component to each vehicle
- Check “Is Kinematic” on each wall Rigidbody
This allows the vehicles to move dynamically while walls remain static colliders. The physics simulation will now detect and resolve collisions between them.
Blocking Vehicle Movement
With collision layers and physics defined, vehicles will collide with walls. However, by default they will still pass through. We need custom logic to block vehicles from passing through colliders.
Using OnCollisionEnter Function
The key is using the OnCollisionEnter function to detect when a vehicle first contacts a wall collider:
void OnCollisionEnter(Collision collision)
{
// Detect collision
}
This gets called automatically by physics when a collision occurs. We can access information about the collision to check if it was with a wall.
Checking Collision Normal
To test if the collision was head-on with a wall, we need to check the collision normal:
void OnCollisionEnter(Collision collision)
{
if (Vector3.Dot(collision.contacts[0].normal, transform.forward) < -0.5)
{
// Head-on wall collision
}
}
If the angle between the vehicle's forward and the collision normal is less than 90 degrees, it was primarily a front-end impact. This indicates a wall blockage rather than just scraping alongside it.
Negating Vehicle Velocity
Once we detect a head-on wall collision inside OnCollisionEnter, we can block the vehicle from passing through by negating its velocity:
void OnCollisionEnter(Collision collision)
{
if (HeadOnWallCollision(collision))
{
GetComponent().velocity = Vector3.zero;
GetComponent().angularVelocity = Vector3.zero;
}
}
This instantly cancels out the vehicle's movement, blocking it in place against the wall. The physics simulation will then separate them on the next frame.
Example Vehicle Controller
For a real working example, here is a basic vehicle controller script that handles wall collisions:
Creating Vehicle Script
First we make a VehicleController script and attach it to the vehicle:
public class VehicleController : MonoBehaviour {
public float speed = 10f;
public float turnSpeed = 45f;
private Rigidbody rb;
void Start()
{
rb = GetComponent();
}
void FixedUpdate()
{
// Move vehicle
}
void OnCollisionEnter(Collision collision)
{
// Handle collisions
}
}
This will drive the vehicle forward based on input and resolve wall collisions.
Getting Input and Move Direction
Inside FixedUpdate we handle input and calculate a move direction:
void FixedUpdate()
{
// Forward input
float vInput = Input.GetAxis("Vertical") * speed;
// Turn input
float hInput = Input.GetAxis("Horizontal");
// Calculate move direction
Vector3 dir = transform.forward * vInput;
dir += transform.right * hInput * turnSpeed;
// Apply to rigidbody
rb.MovePosition(rb.position + dir * Time.fixedDeltaTime);
}
This uses the Vertical axis for acceleration and Horizontal axis for steering. The end result is applied to the rigidbody movement.
Applying Movement Rules
For more control over movement mechanics, we can modify the direction before applying forces:
void FixedUpdate()
{
// Gather inputs
// Calculate desired direction
Vector3 desiredDir = transform.forward * vInput;
desiredDir += transform.right * hInput * turnSpeed;
// Limit direction based on angle
desiredDir = Vector3.ClampMagnitude(desiredDir, speed);
// Apply friction slant direction
Vector3 slantDir = Vector3.Lerp(desiredDir, rb.velocity, slick);
// Final direction
Vector3 dir = slantDir;
dir.y = rb.velocity.y;
// Apply to rigidbody
rb.velocity = dir;
}
This clamps max speed, slants movement on turns, and keeps upright orientation. The exact rules can be customized as needed.
Handling Collisions
Finally we use OnCollisionEnter to check for wall impacts:
void OnCollisionEnter(Collision collision)
{
// Head-on wall collision test
if (Vector3.Dot(collision.contacts[0].normal, transform.forward) < -0.5)
{
// Halt velocity to block sliding through
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
}
}
If a front-end collision is detected, we zero out velocity to block the vehicle from passing through the wall.
Improving Collision Response
To make collisions look and feel more realistic, we can improve the physical reaction using physics materials.
Using Physics Materials
Adding a physics material overrides the default collision response with custom values. Here are the main benefits:
- Configure exact friction and bounciness reactions
- Tune the audio clips triggered by impacts
- Eliminate surface sticking and tight physics gaps
This helps make vehicles behave realistically when hitting walls and other objects.
Configuring Bounciness and Friction
Inside a physics material, the two main tuning values are:
- Bounciness - Controls how much energy is retained after impact
- Friction - Determines how slippery the surface contact is
High bounciness with low friction makes surfaces very "bouncy". Low bounciness with high friction creates very "sticky" collisions.
Preventing Sticking
One issue is vehicles sticking to wall collisions too much. Symptoms include:
- Getting caught on minor surface cracks
- Being anchored to steep slopes
- Feeling glued down around tight turns
This is often from too much friction influence after an impact. Some tips to reduce sticking:
- Lower the Friction Combine setting closer to "Minimum"
- Raise default collision Bounciness higher
- Increase Rigidbody drag settings
Tuning values appropriately reduces sticky forces so vehicles can glance off surfaces more readily after collisions.
Summary
Preventing vehicles from passing through walls takes careful configuration between layers, physics, and scripts in Unity:
Key Points for Solid Collisions
- Define collision layers for vehicles vs walls
- Use physics rigidbodies and triggers appropriately
- Detect collisions entering OnCollisionEnter
- Halt velocity on front-end wall impacts
- Tune physics materials for best reactions
Additional Tips for Tuning
Here are some other tips for realistic vehicle-wall collisions:
- Use smaller, tapered trigger colliders on vehicles to avoid surface snagging
- Add physics distortion effects using shader animations
- Use audio clips triggered by collision enter/exit events
- Animate vehicle parts reacting to impacts
With the fundamentals handled in code, there is a lot of room for building on realism via special effects and sound design.