feat(Car): wire NWH Vehicle Physics 2 — scripts only, scene/prefabs still TODO
Code-only first pass. The local Player.prefab (ball) is still in the scene until the user creates the PlayerCar / RemoteCar prefab variants in the Editor. New scripts: - VehicleLocalSetup: attaches name label + colored capsule marker to the local vehicle, registers its Rigidbody with NetworkManager for broadcast. - RemoteVehicleSync: snapshot interpolation for remote vehicles. Disables the NWH VehicleController + every WheelController + every AudioSource on init. Makes the rigidbody kinematic, MovePosition-driven from network. Disables all non-trigger colliders during the 1.5s spawn grace window to avoid ejecting overlapping locals at connect. Adapted scripts: - NetworkManager: RegisterLocalVehicle(Transform, Rigidbody) replaces the FindFirstObjectByType<PlayerController>() lookup. Remote spawn now wires RemoteVehicleSync instead of RemotePlayerController. - LobbyUI: OnConnected drives VehicleLocalSetup.SetupLocal; OnDisconnected toggles NWH.VehicleController instead of PlayerController. - GameManager.SetPlayerActive: toggles VehicleController, not PlayerController. - DebugNetworkUI: live position read from VehicleController.vehicleRigidbody. - ChatUI: drops PlayerController.ResetInputs() (NWH polls Input System each frame; no manual reset needed when chat opens). - StatsTracker: drops dead _pc field; Rigidbody still gets resolved via GetComponent on the host GameObject (will be the vehicle on Car). Frontend (deployed earlier on master): build_ball replaces pretty_build assets.
This commit is contained in:
@@ -30,7 +30,7 @@ public class NetworkManager : MonoBehaviour
|
||||
public string LastError { get; private set; } = "";
|
||||
|
||||
// Expose remote players for debug UI
|
||||
public Dictionary<string, RemotePlayerController> RemotePlayers => _remotePlayers;
|
||||
public Dictionary<string, RemoteVehicleSync> RemotePlayers => _remotePlayers;
|
||||
|
||||
// Local player info (set during join)
|
||||
public string LocalPlayerName { get; private set; } = "";
|
||||
@@ -73,7 +73,7 @@ public class NetworkManager : MonoBehaviour
|
||||
private Client _client;
|
||||
private Room<GameState> _room;
|
||||
private StateCallbackStrategy<GameState> _callbacks;
|
||||
private readonly Dictionary<string, RemotePlayerController> _remotePlayers = new();
|
||||
private readonly Dictionary<string, RemoteVehicleSync> _remotePlayers = new();
|
||||
private float _broadcastTimer;
|
||||
private const float BROADCAST_INTERVAL = 0.01667f; // ~60/sec
|
||||
private bool _isJoining;
|
||||
@@ -270,14 +270,17 @@ public class NetworkManager : MonoBehaviour
|
||||
|
||||
{
|
||||
Vector3 spawnPos = new Vector3(player.x, player.y, player.z);
|
||||
GameObject remoteBall = remotePlayerPrefab != null
|
||||
? Instantiate(remotePlayerPrefab, spawnPos, Quaternion.identity)
|
||||
: GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
remoteBall.transform.position = spawnPos;
|
||||
remoteBall.name = $"RemotePlayer_{player.name}_{sessionId[..6]}";
|
||||
if (remotePlayerPrefab == null)
|
||||
{
|
||||
Debug.LogError("[Network] remotePlayerPrefab not assigned — cannot spawn remote vehicle.");
|
||||
return;
|
||||
}
|
||||
GameObject remote = Instantiate(remotePlayerPrefab, spawnPos, Quaternion.identity);
|
||||
remote.transform.position = spawnPos;
|
||||
remote.name = $"RemoteVehicle_{player.name}_{sessionId[..6]}";
|
||||
|
||||
var controller = remoteBall.GetComponent<RemotePlayerController>()
|
||||
?? remoteBall.AddComponent<RemotePlayerController>();
|
||||
var controller = remote.GetComponent<RemoteVehicleSync>()
|
||||
?? remote.AddComponent<RemoteVehicleSync>();
|
||||
|
||||
controller.Initialize(sessionId, player.name,
|
||||
new Color(player.colorR, player.colorG, player.colorB));
|
||||
@@ -324,20 +327,21 @@ public class NetworkManager : MonoBehaviour
|
||||
|
||||
// ─── Position Broadcasting ────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="VehicleLocalSetup"/> after the local vehicle is ready.
|
||||
/// Tells us which Rigidbody to broadcast each tick.
|
||||
/// </summary>
|
||||
public void RegisterLocalVehicle(Transform t, Rigidbody rb)
|
||||
{
|
||||
_localPlayer = t;
|
||||
_localPlayerRb = rb;
|
||||
Debug.Log($"[Network] Local vehicle registered: {t?.name}");
|
||||
}
|
||||
|
||||
private void BroadcastPosition()
|
||||
{
|
||||
if (_room == null || !IsConnected) return;
|
||||
|
||||
if (_localPlayer == null)
|
||||
{
|
||||
var pc = FindFirstObjectByType<PlayerController>();
|
||||
if (pc != null)
|
||||
{
|
||||
_localPlayer = pc.transform;
|
||||
_localPlayerRb = pc.GetComponent<Rigidbody>();
|
||||
}
|
||||
else return;
|
||||
}
|
||||
if (_localPlayer == null || _localPlayerRb == null) return;
|
||||
|
||||
Vector3 pos = _localPlayer.position;
|
||||
Vector3 vel = _localPlayerRb != null ? _localPlayerRb.linearVelocity : Vector3.zero;
|
||||
|
||||
Reference in New Issue
Block a user