using System.Collections.Generic; using UnityEngine; namespace MSCO { /// /// Beifahrer: Neben einem Fahrzeug, das ein anderer Spieler fährt, per Taste einsteigen. /// Der Sitz ist die Fahrerposition, auf die andere Seite gespiegelt (bei Fahrzeugen mit /// Sitz in der Mitte, z.B. Traktor oder Moped: dahinter). Während der Fahrt wird der /// Spieler jedes Frame auf den Sitz gesetzt und dreht mit dem Fahrzeug mit; umschauen geht weiter. /// public class Passenger { const float EnterRange = 5f; // so nah muss man am Fahrzeug stehen (Abstand zur Fahrzeugmitte) const float CenterSeatThreshold = 0.2f; const float BehindCenterSeat = 0.7f; const float ExitSideOffset = 1.4f; // beim Aussteigen so weit neben den Sitz // Bewegungs-Skripte des Spielers (Unity Standard Assets), während der Fahrt aus static readonly string[] MovementScripts = { "CharacterMotor", "FPSInputController" }; SyncedBody vehicle; Vector3 seatHeadLocal; float lastYaw; readonly List disabled = new List(); CharacterController controller; public bool IsRiding { get { return vehicle != null; } } /// Taste gedrückt: einsteigen oder aussteigen. Gibt einen Statustext zurück. public string Toggle(Transform player, Camera cam, ObjectSync objects, IDictionary players) { if (IsRiding) { Exit(player, cam); return "Got out"; } if (cam == null) return null; SyncedBody best = null; RemotePlayer driver = null; float bestDist = EnterRange * EnterRange; List driven = objects.RemoteDrivenVehicles(); float nearest = float.MaxValue; foreach (SyncedBody b in driven) { float d = (b.Rb.worldCenterOfMass - player.position).sqrMagnitude; nearest = Mathf.Min(nearest, d); PlayerInfo owner; if (!players.TryGetValue(b.OwnerId, out owner) || owner.Avatar == null) continue; if (d < bestDist) { bestDist = d; best = b; driver = owner.Avatar; } } if (best == null) { // Genau sagen, woran es liegt if (driven.Count == 0) return "Passenger: nobody is driving a vehicle right now (the driver must sit in the driver's seat)"; return "Passenger: get closer to the car (" + Mathf.Sqrt(nearest).ToString("0") + " m away, max " + EnterRange.ToString("0") + " m)"; } Transform vt = best.Rb.transform; Vector3 driverHead = vt.InverseTransformPoint(driver.HeadPosition); seatHeadLocal = Mathf.Abs(driverHead.x) < CenterSeatThreshold ? driverHead - new Vector3(0f, 0f, BehindCenterSeat) // Sitz in der Mitte: dahinter : new Vector3(-driverHead.x, driverHead.y, driverHead.z); // gegenüber vom Fahrer vehicle = best; lastYaw = vt.eulerAngles.y; SetMovementEnabled(player, false); return "Riding as passenger (press again to get out)"; } /// Nach der Physik (LateUpdate): Spieler auf den Sitz setzen und mitdrehen. public void LateUpdate(Transform player, Camera cam, ObjectSync objects) { if (!IsRiding) return; // Fahrer ausgestiegen oder Fahrzeug weg: automatisch aussteigen if (vehicle.Rb == null || cam == null || !objects.IsRemoteOwnedBody(vehicle)) { Exit(player, cam); return; } Transform vt = vehicle.Rb.transform; float yaw = vt.eulerAngles.y; player.Rotate(0f, Mathf.DeltaAngle(lastYaw, yaw), 0f, Space.World); lastYaw = yaw; Vector3 cameraOffset = cam.transform.position - player.position; player.position = vt.TransformPoint(seatHeadLocal) - cameraOffset; } public void Exit(Transform player, Camera cam) { if (!IsRiding) return; if (player != null && vehicle.Rb != null) { // Auf der Seite des Sitzes neben das Fahrzeug stellen float side = seatHeadLocal.x >= 0f ? 1f : -1f; Vector3 outside = vehicle.Rb.transform.TransformPoint(seatHeadLocal + new Vector3(side * ExitSideOffset, 0f, 0f)); Vector3 cameraOffset = cam != null ? cam.transform.position - player.position : Vector3.up * 1.6f; player.position = outside - cameraOffset + Vector3.up * 0.1f; } vehicle = null; SetMovementEnabled(player, true); } /// Szenenwechsel/Verbindungsende: ohne Teleport alles zurücksetzen. public void Reset() { vehicle = null; SetMovementEnabled(null, true); } void SetMovementEnabled(Transform player, bool enabled) { if (!enabled) { disabled.Clear(); foreach (MonoBehaviour mb in player.GetComponents()) { if (mb == null || !mb.enabled) continue; if (System.Array.IndexOf(MovementScripts, mb.GetType().Name) < 0) continue; mb.enabled = false; disabled.Add(mb); } controller = player.GetComponent(); if (controller != null && controller.enabled) controller.enabled = false; else controller = null; } else { foreach (Behaviour b in disabled) if (b != null) b.enabled = true; disabled.Clear(); if (controller != null) controller.enabled = true; controller = null; } } } }