Beta Release
This commit is contained in:
+131
@@ -0,0 +1,131 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user