132 lines
5.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|