NWH Common
Search Results for

    VehicleChanger

    VehicleChanger is a scene-level manager that handles switching between vehicles. It supports both instant switching (press button to cycle) and character-based enter/exit (GTA-style walking to vehicles).


    Overview

    The vehicle enter/exit system uses a minimalist architecture:

    • VehicleChanger - Scene-level singleton managing vehicle switching
    • Vehicle - Base class tracking active vehicles globally
    • EnterExitPoints - Tag-based GameObjects marking entry locations

    No dedicated Seat or Portal classes are needed. Entry points are simple tagged GameObjects.


    Operation Modes

    Instant Mode

    Switch directly between vehicles without a character:

    characterBased = false
    
    • Press button to cycle through vehicles immediately
    • No character object needed
    • Useful for vehicle showcases, testing, arcade games

    Character-Based Mode

    GTA-style walking to vehicles and entering:

    characterBased = true
    
    • Player walks to vehicle entry points
    • Enter/exit at designated EnterExitPoints
    • Character object enables/disables on entry/exit

    Quick Setup

    Instant Mode Setup

    1. Add VehicleChanger component to a scene GameObject
    2. Populate the vehicles list with your vehicles
    3. Set characterBased = false
    4. Configure input for NextVehicle/PreviousVehicle

    Character-Based Setup

    1. Add VehicleChanger component to a scene GameObject
    2. Populate the vehicles list with your vehicles
    3. Set characterBased = true
    4. Assign your player object to characterObject
    5. For each vehicle:
      • Create an empty GameObject child at each door position
      • Tag it with "EnterExitPoint" (or your custom tag)

    Properties

    Core Settings

    Property Type Default Description
    vehicles List<Vehicle> - All managed vehicles in the scene
    activeVehicleIndex int 0 Currently active vehicle index
    characterBased bool false Enable character enter/exit mode
    characterObject GameObject null Player character object

    Entry Settings

    Property Type Default Description
    enterDistance float 2.0 Maximum distance to enter (meters)
    enterExitTag string "EnterExitPoint" Tag for entry point GameObjects
    maxEnterExitVehicleSpeed float 2.0 Max vehicle speed for entry/exit (m/s)

    Behavior Settings

    Property Type Default Description
    putOtherVehiclesToSleep bool true Disable inactive vehicles
    startInVehicle bool false Begin scene inside active vehicle

    EnterExitPoint Setup

    Entry points are simple tagged GameObjects, not dedicated components.

    Creating Entry Points

    1. Create an empty GameObject at each door/entry position
    2. Parent it to the vehicle's transform hierarchy
    3. Tag it with enterExitTag (default: "EnterExitPoint")
    Vehicle (VehicleController)
    ├── Body
    ├── Wheels
    └── EnterExitPoints
        ├── DriverDoor (tag: EnterExitPoint)
        ├── PassengerDoor (tag: EnterExitPoint)
        └── RearDoor (tag: EnterExitPoint)
    

    Distance Calculation

    • Uses horizontal plane distance (ignores Y axis)
    • Calculates from character position to each EnterExitPoint
    • Nearest point determines which vehicle can be entered

    Character Location States

    The system tracks character position relative to vehicles:

    public enum CharacterLocation
    {
        OutOfRange,  // Too far from any vehicle
        Near,        // Close enough to enter (< enterDistance)
        Inside       // Currently in vehicle
    }
    

    Access current state:

    CharacterLocation location = VehicleChanger.Instance.characterLocation;
    

    API Reference

    Singleton Access

    VehicleChanger changer = VehicleChanger.Instance;
    

    Vehicle Switching

    // Switch to specific vehicle by index
    changer.ChangeVehicle(2);
    
    // Switch to specific vehicle by reference
    changer.ChangeVehicle(myVehicle);
    
    // Cycle through vehicles
    changer.NextVehicle();
    changer.PreviousVehicle();
    

    Enter/Exit

    // Enter a vehicle (character mode)
    changer.EnterVehicle(vehicle);
    
    // Exit current vehicle (character mode)
    changer.ExitVehicle(currentVehicle);
    

    Vehicle Registration

    // Register a spawned vehicle
    changer.RegisterVehicle(spawnedVehicle);
    
    // Deregister a destroyed vehicle
    changer.DeregisterVehicle(destroyedVehicle);
    

    Activation Control

    // Deactivate all except active vehicle
    changer.DeactivateAllExceptActive();
    
    // Deactivate all including active (exit in character mode)
    changer.DeactivateAllIncludingActive();
    

    Events

    VehicleChanger Events

    // Vehicle changed (includes enter/exit)
    VehicleChanger.Instance.onVehicleChanged.AddListener(() => {
        Debug.Log("Vehicle changed!");
    });
    
    // All vehicles deactivated (exit in character mode)
    VehicleChanger.Instance.onDeactivateAll.AddListener(() => {
        Debug.Log("Exited all vehicles");
    });
    

    Global Vehicle Tracking

    // Track active vehicle changes globally
    Vehicle.onActiveVehicleChanged.AddListener((previous, current) => {
        Debug.Log($"Changed from {previous?.name} to {current?.name}");
    });
    
    // Access static vehicle lists
    List<Vehicle> allActive = Vehicle.ActiveVehicles;
    Vehicle currentActive = Vehicle.ActiveVehicle;
    

    Enter/Exit Flow

    Character-Based Entry

    1. Character approaches EnterExitPoint
    2. Distance < enterDistance
       └── characterLocation = Near
    3. Check: Vehicle.Speed < maxEnterExitVehicleSpeed
    4. Input triggers ChangeVehicle
    5. Store relative enter position
    6. characterObject.SetActive(false)
    7. characterLocation = Inside
    8. Vehicle.enabled = true
       └── Adds to Vehicle.ActiveVehicles
    

    Character-Based Exit

    1. characterLocation == Inside
    2. Check: Vehicle.Speed < maxEnterExitVehicleSpeed
    3. Input triggers exit
    4. DeactivateAllIncludingActive()
    5. Character positioned at stored relative location
    6. Character.forward = Vehicle.right (face outward)
    7. characterObject.SetActive(true)
    8. characterLocation = OutOfRange
    

    Instant Mode Switching

    1. Input triggers NextVehicle()
    2. activeVehicleIndex++
    3. DeactivateAllExceptActive()
    4. onVehicleChanged fires
    

    Character Positioning

    On Enter

    The relative position is stored for later use:

    _relativeEnterPosition = vehicle.transform.InverseTransformPoint(character.position);
    character.SetActive(false);
    

    On Exit

    Character is placed back at the relative position, facing outward:

    character.position = vehicle.transform.TransformPoint(_relativeEnterPosition);
    character.forward = vehicle.transform.right;  // Face outward from vehicle
    character.SetActive(true);
    

    Integration with Input

    Scene Input Provider

    // Input is read from SceneInputProviderBase
    InputProvider.CombinedInput<SceneInputProviderBase>(i => i.ChangeVehicle())
    

    Default Keys

    Action Input Manager Input System
    Next Vehicle V ChangeVehicle action
    Enter/Exit V (near vehicle) ChangeVehicle action

    Custom Input

    // Trigger vehicle change programmatically
    if (Input.GetKeyDown(KeyCode.E))
    {
        VehicleChanger.Instance.NextVehicle();
    }
    

    Performance Optimization

    putOtherVehiclesToSleep

    When enabled (default), inactive vehicles are disabled:

    putOtherVehiclesToSleep = true;
    

    Benefits:

    • Reduces physics calculations
    • Reduces Update/FixedUpdate overhead
    • Saves CPU for active vehicle

    Vehicles are re-enabled when switched to.

    Scene Loading

    EnterExitPoints are cached and refreshed on scene load:

    SceneManager.sceneLoaded += OnSceneLoaded;
    

    Points are found using:

    GameObject.FindGameObjectsWithTag(enterExitTag)
    

    Usage Examples

    Basic Scene Setup

    // Scene structure:
    // - VehicleChanger (singleton)
    // - Player (character, if using character mode)
    // - Vehicle1 (VehicleController)
    //   - EnterExitPoint (tagged)
    // - Vehicle2 (VehicleController)
    //   - EnterExitPoint (tagged)
    

    Runtime Vehicle Spawning

    public void SpawnVehicle(GameObject prefab, Vector3 position)
    {
        GameObject instance = Instantiate(prefab, position, Quaternion.identity);
        Vehicle vehicle = instance.GetComponent<Vehicle>();
    
        // Register with VehicleChanger
        VehicleChanger.Instance.RegisterVehicle(vehicle);
    
        // Optionally switch to it
        VehicleChanger.Instance.ChangeVehicle(vehicle);
    }
    
    public void DestroyVehicle(Vehicle vehicle)
    {
        // Deregister first
        VehicleChanger.Instance.DeregisterVehicle(vehicle);
    
        Destroy(vehicle.gameObject);
    }
    

    Custom Enter Logic

    public class CustomVehicleEntry : MonoBehaviour
    {
        public void TryEnterNearestVehicle()
        {
            VehicleChanger changer = VehicleChanger.Instance;
    
            if (!changer.characterBased) return;
            if (changer.characterLocation != CharacterLocation.Near) return;
    
            // Find nearest vehicle
            Vehicle nearest = FindNearestVehicle();
            if (nearest != null && nearest.Speed < changer.maxEnterExitVehicleSpeed)
            {
                changer.EnterVehicle(nearest);
            }
        }
    }
    

    Listening for Vehicle Changes

    public class GameManager : MonoBehaviour
    {
        void Start()
        {
            // Listen to VehicleChanger events
            VehicleChanger.Instance.onVehicleChanged.AddListener(OnVehicleChanged);
    
            // Or listen to global Vehicle events
            Vehicle.onActiveVehicleChanged.AddListener(OnActiveVehicleChanged);
        }
    
        void OnVehicleChanged()
        {
            // Update UI, camera, etc.
            UpdateHUD();
        }
    
        void OnActiveVehicleChanged(Vehicle previous, Vehicle current)
        {
            // Handle vehicle change with references
            if (previous != null)
                DisableVehicleUI(previous);
            if (current != null)
                EnableVehicleUI(current);
        }
    }
    

    Limitations

    • Single occupant only - No passenger seat system
    • No seat assignment - All entry points are equivalent
    • Character teleports - No animation support built-in
    • Single instance - Singleton pattern, one per scene

    For more complex requirements (passengers, animations, seat selection), you may need to extend or replace this system.


    Vehicle Base Class

    The Vehicle class (base for VehicleController) provides static tracking:

    Static Properties

    // All currently enabled vehicles
    public static List<Vehicle> ActiveVehicles;
    
    // The most recently enabled vehicle
    public static Vehicle ActiveVehicle;
    
    // Event when active vehicle changes
    public static UnityEvent<Vehicle, Vehicle> onActiveVehicleChanged;
    

    Instance Properties

    Property Description
    isPlayerControllable Can be ActiveVehicle (false for trailers)
    Speed Forward speed (always positive)
    SpeedSigned Forward speed (can be negative in reverse)

    Related Documentation

    • Input - Input system configuration
    • Cameras - Camera system
    • VehicleController (NWH Vehicle Physics 2) - Main vehicle component
    • Edit this page
    In this article
    Back to top Copyright © NWH - Vehicle Physics, Aerodynamics, Dynamic Water Physics