新增动态水物理插件
This commit is contained in:
110
Packages/com.nwh.common/Runtime/Vehicle/FollowVehicleState.cs
Normal file
110
Packages/com.nwh.common/Runtime/Vehicle/FollowVehicleState.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using NWH.NUI;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically enables/disables a GameObject based on parent vehicle's active state.
|
||||
/// Useful for optimizing performance by disabling effects, audio, or visuals when a vehicle is inactive.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Attach this component to child objects that should only be active when the vehicle is being
|
||||
/// simulated. When the vehicle is put to sleep (disabled), attached objects are also disabled,
|
||||
/// saving processing time for effects that wouldn't be visible anyway.
|
||||
/// </remarks>
|
||||
[DefaultExecutionOrder(21)]
|
||||
public partial class FollowVehicleState : MonoBehaviour
|
||||
{
|
||||
private Vehicle _vc;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_vc = GetComponentInParent<Vehicle>();
|
||||
if (_vc == null)
|
||||
{
|
||||
Debug.LogError("VehicleController not found.");
|
||||
}
|
||||
|
||||
_vc.onEnable.AddListener(OnVehicleWake);
|
||||
_vc.onDisable.AddListener(OnVehicleSleep);
|
||||
|
||||
if (_vc.enabled)
|
||||
{
|
||||
OnVehicleWake();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnVehicleSleep();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
// Clean up event listeners to prevent memory leaks
|
||||
if (_vc != null)
|
||||
{
|
||||
_vc.onEnable.RemoveListener(OnVehicleWake);
|
||||
_vc.onDisable.RemoveListener(OnVehicleSleep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnVehicleWake()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
|
||||
private void OnVehicleSleep()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
[CustomEditor(typeof(FollowVehicleState))]
|
||||
[CanEditMultipleObjects]
|
||||
public partial class FollowVehicleStateEditor : NUIEditor
|
||||
{
|
||||
public override bool OnInspectorNUI()
|
||||
{
|
||||
if (!base.OnInspectorNUI())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
drawer.Info("Enables/disables the GameObject based on Vehicle state (awake/asleep).");
|
||||
|
||||
drawer.EndEditor(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public override bool UseDefaultMargins()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08f34355d7a235f499204d23250af006
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Packages/com.nwh.common/Runtime/Vehicle/ShowInSettings.cs
Normal file
81
Packages/com.nwh.common/Runtime/Vehicle/ShowInSettings.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using System;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute that marks a field to be displayed in runtime settings UI.
|
||||
/// Allows players to adjust vehicle parameters during gameplay.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public partial class ShowInSettings : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum value for the setting slider.
|
||||
/// </summary>
|
||||
public float max = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum value for the setting slider.
|
||||
/// </summary>
|
||||
public float min;
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the setting in the UI.
|
||||
/// </summary>
|
||||
public string name;
|
||||
|
||||
/// <summary>
|
||||
/// Increment step for the slider. Smaller values allow finer adjustment.
|
||||
/// </summary>
|
||||
public float step = 0.1f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a settings attribute with a custom display name.
|
||||
/// </summary>
|
||||
public ShowInSettings(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a settings attribute with specified min, max, and step values.
|
||||
/// </summary>
|
||||
public ShowInSettings(float min, float max, float step = 0.1f)
|
||||
{
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a settings attribute with custom name and value constraints.
|
||||
/// </summary>
|
||||
public ShowInSettings(string name, float min, float max, float step = 0.1f)
|
||||
{
|
||||
this.name = name;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
|
||||
public ShowInSettings()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a0a7c580cead1345a77b1082d6b525d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
Packages/com.nwh.common/Runtime/Vehicle/ShowInTelemetry.cs
Normal file
61
Packages/com.nwh.common/Runtime/Vehicle/ShowInTelemetry.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using System;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute that marks a field or property to be displayed in the runtime telemetry UI.
|
||||
/// Used for monitoring vehicle parameters during gameplay and debugging.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public partial class ShowInTelemetry : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum value for the field (used for progress bar visualization).
|
||||
/// </summary>
|
||||
public float Min { get; set; } = float.NaN;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum value for the field (used for progress bar visualization).
|
||||
/// </summary>
|
||||
public float Max { get; set; } = float.NaN;
|
||||
|
||||
/// <summary>
|
||||
/// Format string for displaying the value (e.g., "0.00", "0.0").
|
||||
/// </summary>
|
||||
public string Format { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Unit of measurement (e.g., "km/h", "RPM", "N", "°").
|
||||
/// </summary>
|
||||
public string Unit { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Display priority. 0 = highest (always visible), 3 = lowest (detailed info).
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ShowInTelemetry attribute with optional parameters.
|
||||
/// </summary>
|
||||
public ShowInTelemetry(float min = float.NaN, float max = float.NaN, string format = null, string unit = null, int priority = 1)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
Format = format;
|
||||
Unit = unit;
|
||||
Priority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82a0970af98f7f04ab501aaec0abdcb1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
309
Packages/com.nwh.common/Runtime/Vehicle/Vehicle.cs
Normal file
309
Packages/com.nwh.common/Runtime/Vehicle/Vehicle.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all NWH vehicles including VehiclePhysics2.VehicleController and DWP2.AdvancedShipController.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public abstract class Vehicle : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Any input below this value will register as no input.
|
||||
/// </summary>
|
||||
public const float INPUT_DEADZONE = 0.02f;
|
||||
|
||||
/// <summary>
|
||||
/// Any speed below this value will register as no speed.
|
||||
/// </summary>
|
||||
public const float SPEED_DEADZONE = 0.2f;
|
||||
|
||||
/// <summary>
|
||||
/// Anything below this can be considered 0.
|
||||
/// </summary>
|
||||
public const float SMALL_NUMBER = 1e-5f;
|
||||
|
||||
/// <summary>
|
||||
/// Like SMALL_NUMBER but a bit bigger.
|
||||
/// </summary>
|
||||
public const float KINDA_SMALL_NUMBER = 0.01f;
|
||||
|
||||
public static List<Vehicle> ActiveVehicles = new();
|
||||
|
||||
/// <summary>
|
||||
/// Called when active vehicle is changed.
|
||||
/// First parameter is the previously active vehicle and the second parameter is the currently active vehicle
|
||||
/// (at the time of the callback). Params can be null.
|
||||
/// </summary>
|
||||
public static UnityEvent<Vehicle, Vehicle> onActiveVehicleChanged = new();
|
||||
|
||||
/// <summary>
|
||||
/// True if the vehicle can be driven by the player. False if the
|
||||
/// vehicle is passive (such as a trailer). A vehicle that has isPlayerControllable
|
||||
/// can be the ActiveVehicle.
|
||||
/// </summary>
|
||||
public bool isPlayerControllable = true;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of vehicle rigidbody.
|
||||
/// </summary>
|
||||
[Tooltip(" Cached value of vehicle rigidbody.")]
|
||||
[NonSerialized]
|
||||
public Rigidbody vehicleRigidbody;
|
||||
|
||||
/// <summary>
|
||||
/// Cached value of vehicle transform.
|
||||
/// </summary>
|
||||
[Tooltip(" Cached value of vehicle transform.")]
|
||||
[NonSerialized]
|
||||
public Transform vehicleTransform;
|
||||
|
||||
// Points to the last enabled vehicle.
|
||||
public static Vehicle ActiveVehicle
|
||||
{
|
||||
get
|
||||
{
|
||||
int activeVehicleCount = ActiveVehicles.Count;
|
||||
if (activeVehicleCount == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ActiveVehicles[activeVehicleCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void Awake()
|
||||
{
|
||||
vehicleTransform = transform;
|
||||
vehicleRigidbody = GetComponent<Rigidbody>();
|
||||
vehicleRigidbody.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
}
|
||||
|
||||
|
||||
public virtual void FixedUpdate()
|
||||
{
|
||||
// Pre-calculate values
|
||||
_prevLocalVelocity = LocalVelocity;
|
||||
Velocity = vehicleRigidbody.linearVelocity;
|
||||
LocalVelocity = transform.InverseTransformDirection(Velocity);
|
||||
LocalAcceleration = (LocalVelocity - _prevLocalVelocity) / Time.fixedDeltaTime;
|
||||
LocalForwardVelocity = LocalVelocity.z;
|
||||
LocalForwardAcceleration = LocalAcceleration.z;
|
||||
VelocityMagnitude = Velocity.magnitude;
|
||||
AngularVelocity = vehicleRigidbody.angularVelocity;
|
||||
AngularVelocityMagnitude = AngularVelocity.magnitude;
|
||||
}
|
||||
|
||||
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
onEnable.Invoke();
|
||||
|
||||
if (isPlayerControllable)
|
||||
{
|
||||
if (!ActiveVehicles.Contains(this))
|
||||
{
|
||||
Vehicle previouslyActiveVehicle = ActiveVehicle;
|
||||
ActiveVehicles.Add(this);
|
||||
Vehicle currentlyActiveVehicle = ActiveVehicle;
|
||||
onActiveVehicleChanged.Invoke(previouslyActiveVehicle, currentlyActiveVehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void OnDisable()
|
||||
{
|
||||
onDisable.Invoke();
|
||||
|
||||
if (isPlayerControllable)
|
||||
{
|
||||
Vehicle previouslyActiveVehicle = ActiveVehicle;
|
||||
ActiveVehicles.RemoveAll(vehicle => vehicle == this);
|
||||
Vehicle currentlyActiveVehicle = ActiveVehicle;
|
||||
onActiveVehicleChanged.Invoke(previouslyActiveVehicle, currentlyActiveVehicle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region CAMERA
|
||||
|
||||
/// <summary>
|
||||
/// True when camera is inside vehicle (cockpit, cabin, etc.).
|
||||
/// Set by the 'CameraInsideVehicle' component.
|
||||
/// Used for audio effects.
|
||||
/// </summary>
|
||||
public bool CameraInsideVehicle
|
||||
{
|
||||
get { return _cameraInsideVehicle; }
|
||||
set
|
||||
{
|
||||
if (_cameraInsideVehicle && !value)
|
||||
{
|
||||
onCameraExitVehicle.Invoke();
|
||||
}
|
||||
else if (!CameraInsideVehicle && value)
|
||||
{
|
||||
onCameraEnterVehicle.Invoke();
|
||||
}
|
||||
|
||||
_cameraInsideVehicle = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _cameraInsideVehicle;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the camera enters the vehicle.
|
||||
/// </summary>
|
||||
public UnityEvent onCameraEnterVehicle = new();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the camera exits the vehicle.
|
||||
/// </summary>
|
||||
public UnityEvent onCameraExitVehicle = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region EVENTS
|
||||
|
||||
/// <summary>
|
||||
/// Called when vehicle is put to sleep.
|
||||
/// </summary>
|
||||
[Tooltip(" Called when vehicle is put to sleep.")]
|
||||
[NonSerialized]
|
||||
public UnityEvent onDisable = new();
|
||||
|
||||
/// <summary>
|
||||
/// Called when vehicle is woken up.
|
||||
/// </summary>
|
||||
[Tooltip(" Called when vehicle is woken up.")]
|
||||
[NonSerialized]
|
||||
public UnityEvent onEnable = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region MULTIPLAYER
|
||||
|
||||
/// <summary>
|
||||
/// Determines if vehicle is running locally is synchronized over active multiplayer framework.
|
||||
/// </summary>
|
||||
[Tooltip(" Determines if vehicle is running locally is synchronized over active multiplayer framework.")]
|
||||
private bool _multiplayerIsRemote;
|
||||
|
||||
/// <summary>
|
||||
/// True if the vehicle is a client (remote) and not simulated.
|
||||
/// If true the input is expected to be synced through the network.
|
||||
/// </summary>
|
||||
public bool MultiplayerIsRemote
|
||||
{
|
||||
get { return _multiplayerIsRemote; }
|
||||
set
|
||||
{
|
||||
if (_multiplayerIsRemote && !value)
|
||||
{
|
||||
onMultiplayerStatusChanged.Invoke(false);
|
||||
}
|
||||
else if (!_multiplayerIsRemote && value)
|
||||
{
|
||||
onMultiplayerStatusChanged.Invoke(true);
|
||||
}
|
||||
|
||||
_multiplayerIsRemote = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when MultiplayerIsRemote value gets changed.
|
||||
/// Is true if remote.
|
||||
/// </summary>
|
||||
public UnityEvent<bool> onMultiplayerStatusChanged = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region PHYSICAL_PROPERTIES
|
||||
|
||||
/// <summary>
|
||||
/// Cached acceleration in local coordinates (z-forward)
|
||||
/// </summary>
|
||||
public Vector3 LocalAcceleration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached acceleration in forward direction in local coordinates (z-forward).
|
||||
/// </summary>
|
||||
public float LocalForwardAcceleration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached velocity in forward direction in local coordinates (z-forward).
|
||||
/// </summary>
|
||||
public float LocalForwardVelocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached velocity in m/s in local coordinates.
|
||||
/// </summary>
|
||||
[ShowInTelemetry]
|
||||
public Vector3 LocalVelocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached speed of the vehicle in the forward direction. ALWAYS POSITIVE.
|
||||
/// For positive/negative version use SpeedSigned.
|
||||
/// </summary>
|
||||
[ShowInTelemetry(format: "0.0", unit: "m/s")]
|
||||
public float Speed
|
||||
{
|
||||
get { return LocalForwardVelocity < 0 ? -LocalForwardVelocity : LocalForwardVelocity; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cached speed of the vehicle in the forward direction. Can be positive (forward) or negative (reverse).
|
||||
/// Equal to LocalForwardVelocity.
|
||||
/// </summary>
|
||||
[ShowInTelemetry(format: "0.0", unit: "m/s")]
|
||||
public float SpeedSigned
|
||||
{
|
||||
get { return LocalForwardVelocity; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cached velocity of the vehicle in world coordinates.
|
||||
/// </summary>
|
||||
public Vector3 Velocity { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached velocity magnitude of the vehicle in world coordinates.
|
||||
/// </summary>
|
||||
public float VelocityMagnitude { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached angular velocity of the vehicle.
|
||||
/// </summary>
|
||||
public Vector3 AngularVelocity { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached angular velocity maginitude of the vehicle.
|
||||
/// </summary>
|
||||
public float AngularVelocityMagnitude { get; protected set; }
|
||||
|
||||
private Vector3 _prevLocalVelocity;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Packages/com.nwh.common/Runtime/Vehicle/Vehicle.cs.meta
Normal file
11
Packages/com.nwh.common/Runtime/Vehicle/Vehicle.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a2bed2e81607714099d879a07950fe7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
540
Packages/com.nwh.common/Runtime/Vehicle/VehicleChanger.cs
Normal file
540
Packages/com.nwh.common/Runtime/Vehicle/VehicleChanger.cs
Normal file
@@ -0,0 +1,540 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NWH.Common.Input;
|
||||
using NWH.Common.Vehicles;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.SceneManagement;
|
||||
#if UNITY_EDITOR
|
||||
using NWH.NUI;
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.SceneManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages switching between multiple vehicles in a scene with support for both instant
|
||||
/// and character-based (enter/exit) modes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// VehicleChanger supports two modes:
|
||||
/// - Instant switching: Press a button to cycle through vehicles immediately
|
||||
/// - Character-based: Player must walk to a vehicle and enter/exit at designated points
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// In character-based mode, the player can only enter vehicles when near an EnterExitPoint
|
||||
/// and the vehicle is moving slowly enough. This creates more realistic vehicle switching
|
||||
/// similar to GTA-style games.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Inactive vehicles can optionally be put to sleep to improve performance when managing
|
||||
/// many vehicles in a scene.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[DefaultExecutionOrder(500)]
|
||||
public class VehicleChanger : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the player's spatial relationship to vehicles.
|
||||
/// </summary>
|
||||
public enum CharacterLocation
|
||||
{
|
||||
/// <summary>
|
||||
/// Player is too far from any vehicle to interact.
|
||||
/// </summary>
|
||||
OutOfRange,
|
||||
|
||||
/// <summary>
|
||||
/// Player is close enough to enter a vehicle.
|
||||
/// </summary>
|
||||
Near,
|
||||
|
||||
/// <summary>
|
||||
/// Player is currently inside a vehicle.
|
||||
/// </summary>
|
||||
Inside,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current vehicle in vehicles list.
|
||||
/// </summary>
|
||||
[Tooltip(" Index of the current vehicle in vehicles list.")]
|
||||
public int activeVehicleIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Is vehicle changing character based? When true changing vehicles will require getting close to them
|
||||
/// to be able to enter, opposed to pressing a button to switch between vehicles.
|
||||
/// </summary>
|
||||
[Tooltip(
|
||||
"Is vehicle changing character based? When true changing vehicles will require getting close to them\r\nto be able to enter, opposed to pressing a button to switch between vehicles.")]
|
||||
public bool characterBased;
|
||||
|
||||
/// <summary>
|
||||
/// Game object representing a character. Can also be another vehicle.
|
||||
/// </summary>
|
||||
[Tooltip(" Game object representing a character. Can also be another vehicle.")]
|
||||
public GameObject characterObject;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum distance at which the character will be able to enter the vehicle.
|
||||
/// </summary>
|
||||
[Range(0.2f, 3f)]
|
||||
[Tooltip(" Maximum distance at which the character will be able to enter the vehicle.")]
|
||||
public float enterDistance = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// Tag of the object representing the point from which the enter distance will be measured. Useful if you want to
|
||||
/// enable you character to enter only when near the door.
|
||||
/// </summary>
|
||||
[Tooltip(
|
||||
"Tag of the object representing the point from which the enter distance will be measured. Useful if you want to enable you character to enter only when near the door.")]
|
||||
public string enterExitTag = "EnterExitPoint";
|
||||
|
||||
/// <summary>
|
||||
/// When the location is Near, the player can enter the vehicle.
|
||||
/// </summary>
|
||||
[Tooltip("When the location is Near, the player can enter the vehicle.")]
|
||||
public CharacterLocation location = CharacterLocation.OutOfRange;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum speed at which the character will be able to enter / exit the vehicle.
|
||||
/// </summary>
|
||||
[Tooltip(" Maximum speed at which the character will be able to enter / exit the vehicle.")]
|
||||
public float maxEnterExitVehicleSpeed = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// Event invoked when all vehicles are deactivated (e.g., when exiting in character-based mode).
|
||||
/// </summary>
|
||||
public UnityEvent onDeactivateAll = new();
|
||||
|
||||
/// <summary>
|
||||
/// Event invoked whenever the active vehicle changes.
|
||||
/// </summary>
|
||||
public UnityEvent onVehicleChanged = new();
|
||||
|
||||
/// <summary>
|
||||
/// Should the vehicles that the player is currently not using be put to sleep to improve performance?
|
||||
/// </summary>
|
||||
[Tooltip(
|
||||
" Should the vehicles that the player is currently not using be put to sleep to improve performance?")]
|
||||
public bool putOtherVehiclesToSleep = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should the player start inside the vehicle?
|
||||
/// </summary>
|
||||
[Tooltip("Should the player start inside the vehicle?")]
|
||||
public bool startInVehicle;
|
||||
|
||||
/// <summary>
|
||||
/// List of all of the vehicles that can be selected and driven in the scene.
|
||||
/// </summary>
|
||||
[Tooltip("List of all of the vehicles that can be selected and driven in the scene.")]
|
||||
public List<Vehicle> vehicles = new();
|
||||
|
||||
private GameObject[] _enterExitPoints;
|
||||
private bool _enterExitPointsDirty = true;
|
||||
private GameObject _nearestEnterExitPoint;
|
||||
|
||||
/// <summary>
|
||||
/// The vehicle the player is nearest to, or in case the player is inside the vehicle, the vehicle the player is inside
|
||||
/// of.
|
||||
/// </summary>
|
||||
private Vehicle _nearestVehicle;
|
||||
|
||||
private Vector3 _relativeEnterPosition;
|
||||
|
||||
public static VehicleChanger Instance { get; private set; }
|
||||
|
||||
private static Vehicle ActiveVehicle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Instance.activeVehicleIndex < 0 || Instance.activeVehicleIndex >= Instance.vehicles.Count
|
||||
? null
|
||||
: Instance.vehicles[Instance.activeVehicleIndex];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
// Remove null vehicles from the vehicles list
|
||||
for (int i = vehicles.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (vehicles[i] == null)
|
||||
{
|
||||
Debug.LogWarning("There is a null reference in the vehicles list. Removing. Make sure that" +
|
||||
" vehicles list does not contain any null references.");
|
||||
vehicles.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_enterExitPointsDirty = true;
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
}
|
||||
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
}
|
||||
|
||||
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
_enterExitPointsDirty = true;
|
||||
}
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (characterBased && !startInVehicle)
|
||||
{
|
||||
DeactivateAllIncludingActive();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateAllExceptActive();
|
||||
}
|
||||
|
||||
if (startInVehicle && ActiveVehicle != null)
|
||||
{
|
||||
EnterVehicle(ActiveVehicle);
|
||||
_relativeEnterPosition = new Vector3(-2.5f, 1f, 0.5f); // There was no enter/exit point, make a guess
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!characterBased)
|
||||
{
|
||||
bool changeVehicleInput = InputProvider.CombinedInput<SceneInputProviderBase>(i => i.ChangeVehicle());
|
||||
|
||||
if (changeVehicleInput)
|
||||
{
|
||||
NextVehicle();
|
||||
}
|
||||
}
|
||||
else if (characterObject != null)
|
||||
{
|
||||
if (location != CharacterLocation.Inside)
|
||||
{
|
||||
location = CharacterLocation.OutOfRange;
|
||||
|
||||
if (!characterObject.activeSelf)
|
||||
{
|
||||
characterObject.SetActive(true);
|
||||
}
|
||||
|
||||
// Cache enter/exit points until scene changes
|
||||
if (_enterExitPointsDirty)
|
||||
{
|
||||
_enterExitPoints = GameObject.FindGameObjectsWithTag(enterExitTag);
|
||||
_enterExitPointsDirty = false;
|
||||
}
|
||||
|
||||
_nearestEnterExitPoint = null;
|
||||
float nearestSqrDist = Mathf.Infinity;
|
||||
|
||||
foreach (GameObject eep in _enterExitPoints)
|
||||
{
|
||||
float sqrDist =
|
||||
Vector3.SqrMagnitude(characterObject.transform.position - eep.transform.position);
|
||||
if (sqrDist < nearestSqrDist)
|
||||
{
|
||||
nearestSqrDist = sqrDist;
|
||||
_nearestEnterExitPoint = eep;
|
||||
}
|
||||
}
|
||||
|
||||
if (_nearestEnterExitPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Vector3.Magnitude(Vector3.ProjectOnPlane(
|
||||
_nearestEnterExitPoint.transform.position -
|
||||
characterObject.transform.position,
|
||||
Vector3.up)) < enterDistance)
|
||||
{
|
||||
location = CharacterLocation.Near;
|
||||
_nearestVehicle = _nearestEnterExitPoint.GetComponentInParent<Vehicle>();
|
||||
}
|
||||
}
|
||||
|
||||
bool changeVehiclePressed = InputProvider.CombinedInput<SceneInputProviderBase>(i => i.ChangeVehicle());
|
||||
if (InputProvider.Instances.Count > 0 && changeVehiclePressed)
|
||||
{
|
||||
// Enter vehicle
|
||||
if (location == CharacterLocation.Near && _nearestVehicle.Speed < maxEnterExitVehicleSpeed)
|
||||
{
|
||||
EnterVehicle(_nearestVehicle);
|
||||
}
|
||||
|
||||
// Exit vehicle
|
||||
else if (location == CharacterLocation.Inside && _nearestVehicle.Speed < maxEnterExitVehicleSpeed)
|
||||
{
|
||||
ExitVehicle(_nearestVehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Puts the player inside the specified vehicle and activates it.
|
||||
/// In character-based mode, stores the entry position for later exit.
|
||||
/// </summary>
|
||||
/// <param name="v">Vehicle to enter.</param>
|
||||
public void EnterVehicle(Vehicle v)
|
||||
{
|
||||
_nearestVehicle = v;
|
||||
if (characterBased)
|
||||
{
|
||||
characterObject.SetActive(false);
|
||||
_relativeEnterPosition = v.transform.InverseTransformPoint(characterObject.transform.position);
|
||||
location = CharacterLocation.Inside;
|
||||
}
|
||||
|
||||
Instance.ChangeVehicle(v);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes the player from the vehicle and spawns the character object nearby.
|
||||
/// Character is positioned at the stored entry location.
|
||||
/// </summary>
|
||||
/// <param name="v">Vehicle to exit.</param>
|
||||
public void ExitVehicle(Vehicle v)
|
||||
{
|
||||
// Call deactivate all to deactivate on the same frame, preventing 2 audio listeners warning.
|
||||
Instance.DeactivateAllIncludingActive();
|
||||
location = CharacterLocation.OutOfRange;
|
||||
if (characterBased)
|
||||
{
|
||||
characterObject.transform.position = v.transform.TransformPoint(_relativeEnterPosition);
|
||||
characterObject.transform.forward = v.transform.right;
|
||||
characterObject.transform.up = Vector3.up;
|
||||
characterObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a vehicle to the managed vehicles list if not already present.
|
||||
/// Newly registered vehicles are automatically disabled unless they are the active vehicle.
|
||||
/// </summary>
|
||||
/// <param name="v">Vehicle to register.</param>
|
||||
public void RegisterVehicle(Vehicle v)
|
||||
{
|
||||
if (!vehicles.Contains(v))
|
||||
{
|
||||
vehicles.Add(v);
|
||||
if (activeVehicleIndex != vehicles.Count - 1)
|
||||
{
|
||||
v.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes a vehicle from the managed vehicles list.
|
||||
/// If the vehicle was active, automatically switches to the next vehicle.
|
||||
/// </summary>
|
||||
/// <param name="v">Vehicle to deregister.</param>
|
||||
public void DeregisterVehicle(Vehicle v)
|
||||
{
|
||||
if (ActiveVehicle == v)
|
||||
{
|
||||
NextVehicle();
|
||||
}
|
||||
|
||||
vehicles.Remove(v);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Changes vehicle to requested vehicle.
|
||||
/// </summary>
|
||||
/// <param name="index"> Index of a vehicle in Vehicles list. </param>
|
||||
public void ChangeVehicle(int index)
|
||||
{
|
||||
if (vehicles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activeVehicleIndex = index;
|
||||
if (activeVehicleIndex >= vehicles.Count)
|
||||
{
|
||||
activeVehicleIndex = 0;
|
||||
}
|
||||
|
||||
DeactivateAllExceptActive();
|
||||
|
||||
onVehicleChanged.Invoke();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Switches to the specified vehicle if it exists in the vehicles list.
|
||||
/// </summary>
|
||||
/// <param name="ac">Vehicle reference to switch to.</param>
|
||||
public void ChangeVehicle(Vehicle ac)
|
||||
{
|
||||
int vehicleIndex = vehicles.IndexOf(ac);
|
||||
|
||||
if (vehicleIndex >= 0)
|
||||
{
|
||||
ChangeVehicle(vehicleIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Switches to the next vehicle in the list, wrapping to the first vehicle when reaching the end.
|
||||
/// </summary>
|
||||
public void NextVehicle()
|
||||
{
|
||||
if (vehicles.Count == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeVehicle(activeVehicleIndex + 1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Switches to the previous vehicle in the list, wrapping to the last vehicle when at the beginning.
|
||||
/// </summary>
|
||||
public void PreviousVehicle()
|
||||
{
|
||||
if (vehicles.Count == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int previousIndex = activeVehicleIndex == 0 ? vehicles.Count - 1 : activeVehicleIndex - 1;
|
||||
|
||||
ChangeVehicle(previousIndex);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enables the current active vehicle and optionally disables all others based on putOtherVehiclesToSleep setting.
|
||||
/// </summary>
|
||||
public void DeactivateAllExceptActive()
|
||||
{
|
||||
for (int i = 0; i < vehicles.Count; i++)
|
||||
{
|
||||
if (i == activeVehicleIndex)
|
||||
{
|
||||
vehicles[i].enabled = true;
|
||||
}
|
||||
else if (putOtherVehiclesToSleep)
|
||||
{
|
||||
vehicles[i].enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Disables all managed vehicles including the currently active one.
|
||||
/// Used when exiting vehicles in character-based mode.
|
||||
/// </summary>
|
||||
public void DeactivateAllIncludingActive()
|
||||
{
|
||||
for (int i = 0; i < vehicles.Count; i++)
|
||||
{
|
||||
vehicles[i].enabled = false;
|
||||
}
|
||||
|
||||
onDeactivateAll.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
namespace NWH.Common.SceneManagement
|
||||
{
|
||||
[CustomEditor(typeof(VehicleChanger))]
|
||||
[CanEditMultipleObjects]
|
||||
public class VehicleChangerEditor : NUIEditor
|
||||
{
|
||||
public override bool OnInspectorNUI()
|
||||
{
|
||||
if (!base.OnInspectorNUI())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VehicleChanger sc = drawer.GetObject<VehicleChanger>();
|
||||
|
||||
drawer.BeginSubsection("Vehicles");
|
||||
drawer.ReorderableList("vehicles");
|
||||
|
||||
//drawer.Field("deactivateAll");
|
||||
drawer.Field("putOtherVehiclesToSleep");
|
||||
drawer.Field("activeVehicleIndex");
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
drawer.Label("Active Vehicle: " +
|
||||
(Vehicle.ActiveVehicle == null ? "None" : Vehicle.ActiveVehicle.name));
|
||||
}
|
||||
|
||||
drawer.EndSubsection();
|
||||
|
||||
drawer.BeginSubsection("Character-based Switching");
|
||||
if (drawer.Field("characterBased").boolValue)
|
||||
{
|
||||
drawer.Field("characterObject");
|
||||
drawer.Field("enterDistance", true, "m");
|
||||
drawer.Field("startInVehicle");
|
||||
drawer.Field("enterExitTag");
|
||||
drawer.Field("maxEnterExitVehicleSpeed", true, "m/s");
|
||||
drawer.Field("location", false);
|
||||
}
|
||||
|
||||
drawer.EndSubsection();
|
||||
|
||||
drawer.EndEditor(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public override bool UseDefaultMargins()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc64a64f2888b1942b9b64877d834931
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,150 @@
|
||||
// ╔════════════════════════════════════════════════════════════════╗
|
||||
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
|
||||
// ║ Licensed under Unity Asset Store Terms of Service: ║
|
||||
// ║ https://unity.com/legal/as-terms ║
|
||||
// ║ Use permitted only in compliance with the License. ║
|
||||
// ║ Distributed "AS IS", without warranty of any kind. ║
|
||||
// ╚════════════════════════════════════════════════════════════════╝
|
||||
|
||||
#region
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using NWH.NUI;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages vehicle reflection probe settings, switching between baked and realtime modes
|
||||
/// based on vehicle activity to optimize performance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Realtime reflection probes are expensive. This component switches to cheaper baked probes
|
||||
/// when the vehicle is inactive, maintaining visual quality while improving performance.
|
||||
/// The probe is automatically re-baked when the vehicle becomes inactive to capture the
|
||||
/// current environment state.
|
||||
/// </remarks>
|
||||
[RequireComponent(typeof(ReflectionProbe))]
|
||||
[DefaultExecutionOrder(19)]
|
||||
public partial class VehicleReflectionProbe : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of reflection probe to use.
|
||||
/// </summary>
|
||||
public enum ProbeType
|
||||
{
|
||||
/// <summary>
|
||||
/// Pre-rendered cubemap, low cost but static.
|
||||
/// </summary>
|
||||
Baked,
|
||||
|
||||
/// <summary>
|
||||
/// Updates every frame, high cost but accurate.
|
||||
/// </summary>
|
||||
Realtime,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Probe type to use when vehicle is inactive/sleeping. Default is Baked for performance.
|
||||
/// </summary>
|
||||
public ProbeType asleepProbeType = ProbeType.Baked;
|
||||
|
||||
/// <summary>
|
||||
/// Probe type to use when vehicle is active. Default is Realtime for accurate reflections.
|
||||
/// </summary>
|
||||
public ProbeType awakeProbeType = ProbeType.Realtime;
|
||||
|
||||
/// <summary>
|
||||
/// Automatically bake the probe when vehicle becomes inactive to capture environment state.
|
||||
/// </summary>
|
||||
public bool bakeOnSleep = true;
|
||||
|
||||
/// <summary>
|
||||
/// Bake the probe once on start for initial environment capture.
|
||||
/// </summary>
|
||||
public bool bakeOnStart = true;
|
||||
|
||||
private ReflectionProbe _reflectionProbe;
|
||||
private Vehicle _vc;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_vc = GetComponentInParent<Vehicle>();
|
||||
if (_vc == null)
|
||||
{
|
||||
Debug.LogError("VehicleController not found.");
|
||||
}
|
||||
|
||||
_reflectionProbe = GetComponent<ReflectionProbe>();
|
||||
_vc.onEnable.AddListener(OnVehicleEnable);
|
||||
_vc.onDisable.AddListener(OnVehicleDisable);
|
||||
|
||||
_reflectionProbe.refreshMode = ReflectionProbeRefreshMode.EveryFrame;
|
||||
|
||||
if (bakeOnStart)
|
||||
{
|
||||
_reflectionProbe.RenderProbe();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnVehicleEnable()
|
||||
{
|
||||
_reflectionProbe.mode = awakeProbeType == ProbeType.Baked
|
||||
? ReflectionProbeMode.Baked
|
||||
: ReflectionProbeMode.Realtime;
|
||||
}
|
||||
|
||||
|
||||
private void OnVehicleDisable()
|
||||
{
|
||||
_reflectionProbe.mode = asleepProbeType == ProbeType.Baked
|
||||
? ReflectionProbeMode.Baked
|
||||
: ReflectionProbeMode.Realtime;
|
||||
|
||||
if (bakeOnSleep && _reflectionProbe.isActiveAndEnabled)
|
||||
{
|
||||
_reflectionProbe.RenderProbe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
namespace NWH.Common.Vehicles
|
||||
{
|
||||
[CustomEditor(typeof(VehicleReflectionProbe))]
|
||||
[CanEditMultipleObjects]
|
||||
public partial class VehicleReflectionProbeEditor : NUIEditor
|
||||
{
|
||||
public override bool OnInspectorNUI()
|
||||
{
|
||||
if (!base.OnInspectorNUI())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
drawer.Field("awakeProbeType");
|
||||
drawer.Field("asleepProbeType");
|
||||
drawer.Field("bakeOnStart");
|
||||
drawer.Field("bakeOnSleep");
|
||||
|
||||
drawer.EndEditor(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public override bool UseDefaultMargins()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 677f12722777bfc478d18a520b979bc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user