Files
MSCO/Passenger.cs
T
2026-09-26 19:37:28 +02:00

132 lines
5.5 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace MSCO
{
/// <summary>
/// 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.
/// </summary>
public class Passenger
{
const float EnterRange = 4f; // so nah muss man am Fahrzeug stehen
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<Behaviour> disabled = new List<Behaviour>();
CharacterController controller;
public bool IsRiding { get { return vehicle != null; } }
/// <summary>Taste gedrückt: einsteigen oder aussteigen. Gibt einen Statustext zurück.</summary>
public string Toggle(Transform player, Camera cam, ObjectSync objects, IDictionary<int, PlayerInfo> players)
{
if (IsRiding)
{
Exit(player, cam);
return "Got out";
}
if (cam == null) return null;
SyncedBody best = null;
RemotePlayer driver = null;
float bestDist = EnterRange * EnterRange;
foreach (SyncedBody b in objects.RemoteDrivenVehicles())
{
PlayerInfo owner;
if (!players.TryGetValue(b.OwnerId, out owner) || owner.Avatar == null) continue;
float d = (b.Rb.worldCenterOfMass - player.position).sqrMagnitude;
if (d < bestDist) { bestDist = d; best = b; driver = owner.Avatar; }
}
if (best == null) return "No vehicle driven by another player nearby";
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)";
}
/// <summary>Nach der Physik (LateUpdate): Spieler auf den Sitz setzen und mitdrehen.</summary>
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);
}
/// <summary>Szenenwechsel/Verbindungsende: ohne Teleport alles zurücksetzen.</summary>
public void Reset()
{
vehicle = null;
SetMovementEnabled(null, true);
}
void SetMovementEnabled(Transform player, bool enabled)
{
if (!enabled)
{
disabled.Clear();
foreach (MonoBehaviour mb in player.GetComponents<MonoBehaviour>())
{
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<CharacterController>();
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;
}
}
}
}