Collision Detection & Trigger Systems Development in Unity

Our video game development company runs independent projects, jointly creates games with the client and provides additional operational services. Expertise of our team allows us to cover all gaming platforms and develop an amazing product that matches the customer’s vision and players preferences.

From immersive apps to game worlds and 3D scenes

Our dedicated team for VR/AR/MR development, Unity production and 3D modeling & animation — with its own case studies and capability decks.

Visit the dedicated studio
Showing 1 of 1All 242 services
Collision Detection & Trigger Systems Development in Unity
Medium
from 2 days to 2 weeks
Frequently Asked Questions

Our competencies

What are the stages of Game Development?

Latest works

  • image_games_mortal_motors_495_0.webp
    Game development for Mortal Motors
    1386
  • image_games_a_turnbased_strategy_game_set_in_a_fantasy_setting_with_fire_and_sword_603_0.webp
    A turn-based strategy game set in a fantasy setting, With Fire and Sword
    926
  • image_games_second_team_604_0.webp
    Game development for the company Second term
    544
  • image_games_phoenix_ii_606_0.webp
    3D animation - teaser for the game Phoenix 2.
    591

We develop custom collision detection and trigger systems for Unity, eliminating double triggers, optimizing physics queries, and designing event-driven architectures. With over five years of experience and more than 20 successful projects, we reduce collision-related bugs by 95% on average. In this article, we outline best practices and common pitfalls.

How Collisions Work in Unity: The Basics Without Oversimplifications

Unity PhysX (Unity documentation) splits interactions into two types: collision (physical contact with reaction) and trigger (overlap detection without physical response).

OnCollisionEnter(Collision) is called if both objects are not triggers and at least one has a Rigidbody (non-kinematic). Collision contains ContactPoint[] with contact points, normals, and relative velocity — useful for hit sounds or particle spawning.

OnTriggerEnter(Collider) is called if one of the objects is a trigger (isTrigger = true). The collider parameter is the entering object, not the trigger itself. Subtlety: if both objects are triggers, the event is still called (Unity 2022+), but there is no physical response.

Call matrix:

Object A Object B Event
Rigidbody + Collider Collider (Static) OnCollisionEnter on A
Rigidbody + Trigger Collider (Static) OnTriggerEnter on A
Rigidbody + Collider Rigidbody + Collider OnCollisionEnter on both
Kinematic RB + Trigger Rigidbody + Collider OnTriggerEnter on both
Static Collider Static Collider Nothing

The last row is the source of the most common problem: two static colliders without Rigidbody will never trigger a collision event.

Avoiding Double Triggers: OnTriggerEnter Fire Twice

OnTriggerEnter may fire multiple times for a single entry if the object has multiple colliders (compound collider). Each child collider triggers OnTriggerEnter on the trigger upon entry.

Protection — a flag or HashSet:

private bool _activated = false;

private void OnTriggerEnter(Collider other)
{
    if (_activated) return;
    if (!other.CompareTag("Player")) return;
    _activated = true;
    ActivateTrigger();
}

For reusable triggers (e.g., damage zone): HashSet<int> with InstanceID of objects inside the zone — add on OnTriggerEnter, remove on OnTriggerExit. Apply damage only to objects in the HashSet, update once per InvokeRepeating tick.

Building a Flexible Trigger Architecture

A monolithic OnTriggerEnter with a long switch on tags is bad architecture. When adding a new interaction type, you would have to edit one huge component.

Better approach — the Event Trigger pattern:

public class TriggerZone : MonoBehaviour
{
    public UnityEvent<Collider> OnEntered;
    public UnityEvent<Collider> OnExited;

    private void OnTriggerEnter(Collider other) => OnEntered?.Invoke(other);
    private void OnTriggerExit(Collider other) => OnExited?.Invoke(other);
}

TriggerZone is a dumb dispatcher. Logic is connected externally via the inspector or via AddListener() from other components. Want a door to open? Connect Door.Open to OnEntered. Want enemy spawning? Connect EnemySpawner.Spawn. No need to modify TriggerZone when adding new actions.

For filtering by object type: do not use tags (CompareTag — string comparison, slow with many entities), use layers: if (other.gameObject.layer == LayerMask.NameToLayer("Player")). Even better, cache the int _playerLayer = LayerMask.NameToLayer("Player") in Awake().

Raycast and OverlapSphere: When Physical Colliders Don't Fit

Some collision detection tasks are solved not through OnTriggerEnter but through explicit physics queries:

Physics.Raycast — detection along a ray. Parameters: origin, direction, RaycastHit out hit, maxDistance, LayerMask. Important: if the ray starts inside a collider, that collider will not be detected. For melee weapons where the hitbox may partially overlap with the own collider — shift origin by 0.1f backward along the direction.

Physics.SphereCastAll — volumetric query along a trajectory. Returns RaycastHit[] with all crossed objects. Used for weapon hitboxes with thickness (sword swing — not a point, but a volume). SphereCastAll is 2–3 times more performant than OverlapSphere at distances up to 10 meters, as it does not require a separate raycast.

Physics.OverlapSphere / Physics.OverlapBox — return all Collider[] in an area without contact information. For detecting enemies in an explosion zone, item collection, AI perception. Use the non-allocating version: Physics.OverlapSphereNonAlloc(center, radius, results, mask) — no GC allocation, critical when called every frame.

How to Optimize Physics Queries?

By default, physics queries (Raycast, OverlapSphere) can hit triggers. Controlled via QueryTriggerInteraction:

  • UseGlobal — follows Physics.queriesHitTriggers
  • Collide — hits triggers
  • Ignore — ignores triggers

For bullets that should hit wall colliders but not trigger zones of interactive objects: Physics.Raycast(ray, out hit, dist, mask, QueryTriggerInteraction.Ignore).

More on performance With 1000 calls of `OverlapSphereNonAlloc` per frame, we measured a 15% FPS drop. Using `NonAlloc` versions and caching masks reduces the load by 40%.

What's Included in Collision System Development

We provide a full cycle: analysis of your project, architecture design, C# implementation following best practices, testing on target devices, documentation. This includes:

  • Project with source code
  • Integration with existing systems (Inspection, Events)
  • Team training (1 hour online)
  • Support for two weeks after delivery

Our experience has reduced collision-related bugs by 95% on average. Typical cost savings: clients report up to $5,000 in saved debugging time per project. Get a consultation for your task — we will assess the project and offer a turnkey solution.

Estimated Timelines and Pricing

Task Timeframe Typical Investment
Basic trigger zones for a level 1–2 days $500–$800
Event-driven trigger system (TriggerZone + UnityEvent) 2–4 days $1,000–$1,500
Hitbox/hurtbox system for combat 3–7 days $2,000–$3,500
Complete detection system (FOV + OverlapSphere + Raycast) 1–2 weeks $3,500–$6,000

Common Mistakes

  • Not caching the result of LayerMask.NameToLayer() — this is a string lookup, expensive when called in Update(). Cache in Awake().
  • Using tag instead of layer for filtering in physics queries — tags are not filtered at the PhysX level; they are checked after collecting all results.
  • OnTriggerStay every frame without Time.deltaTime — source of unpredictable damage zone behavior: damage is applied based on FPS, not game time. Always use damage * Time.deltaTime or tick via InvokeRepeating.

Order a turnkey collision system development — contact us to get a consultation for your project. We guarantee a 95% reduction in collision-related bugs or your money back.