Riding along: hold the current position inside the vehicle
Instead of snapping to a computed passenger seat, a player whose head is inside a vehicle's (shrunk) outline is held exactly there and moves with it; works for cabins, open doors and beds, with or without a driver. Getting out puts the player beside the vehicle on the nearer side. P next to the car still uses the passenger seat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+75
-33
@@ -4,11 +4,10 @@ using UnityEngine;
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// Beifahrer: Wer in die offene Beifahrertür an den Sitz tritt, setzt sich automatisch hin - egal ob schon jemand
|
||||
/// fährt oder das Auto noch steht (die Taste geht weiterhin, auch zum Aussteigen; Leertaste steigt ebenfalls aus).
|
||||
/// Der Sitz ist die Fahrerposition des Spiels (DriverHeadPivot), 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.
|
||||
/// Mitfahren: Wer mit dem Kopf im Fahrzeug ist (Kabine, offene Tür, Ladefläche ...), wird genau dort festgehalten und
|
||||
/// fährt mit - egal ob schon jemand fährt oder das Auto noch steht. Aussteigen mit Leertaste oder der Beifahrer-Taste.
|
||||
/// Steht man per Taste neben dem Auto, kommt man auf den Beifahrersitz (Fahrerposition des Spiels, gespiegelt).
|
||||
/// Während der Fahrt wird der Spieler jedes Frame an seine Stelle im Fahrzeug gesetzt und dreht mit; umschauen geht.
|
||||
/// </summary>
|
||||
public class Passenger
|
||||
{
|
||||
@@ -58,6 +57,12 @@ namespace MSCO
|
||||
return "Got out";
|
||||
}
|
||||
if (cam == null || objects.IsDriving) return null;
|
||||
SyncedBody inside = VehicleAround(objects, cam.transform.position);
|
||||
if (inside != null)
|
||||
{
|
||||
Enter(inside, inside.Rb.transform.InverseTransformPoint(cam.transform.position), player);
|
||||
return "Riding along (press again or Space to get out)";
|
||||
}
|
||||
|
||||
SyncedBody best = null;
|
||||
Vector3 bestSeat = Vector3.zero;
|
||||
@@ -81,16 +86,16 @@ namespace MSCO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Jedes Frame (zu Fuß): steht man mit dem Kopf am Beifahrersitz (in der offenen Tür), automatisch hinsetzen.
|
||||
/// Gibt einen Statustext zurück, wenn man eingestiegen ist.
|
||||
/// Jedes Frame (zu Fuß): ist man mit dem Kopf IM Fahrzeug (Kabine, Ladefläche ...), wird die aktuelle Position im
|
||||
/// Fahrzeug festgehalten - man fährt genau dort mit, wo man ist (kein Umsetzen auf einen berechneten Sitz).
|
||||
/// Gibt einen Statustext zurück, wenn man "eingestiegen" ist.
|
||||
/// </summary>
|
||||
public string AutoUpdate(Transform player, Camera cam, ObjectSync objects, IDictionary<int, PlayerInfo> players)
|
||||
{
|
||||
if (objects.IsDriving) lastDriving = Time.time;
|
||||
if (IsRiding || cam == null || player == null || objects.IsDriving) { dwellStart = -1f; return null; }
|
||||
// Steigt man auf der Fahrerseite ein, setzt das Spiel einen über die Sitze auf den Fahrersitz - dabei kommt der
|
||||
// Kopf kurz am Beifahrersitz vorbei. Solange das Spiel die Steuerung hat (CharacterController aus, Spieler an
|
||||
// ein Fahrzeug gehängt) oder kurz nach dem Fahren: nicht automatisch einsteigen.
|
||||
// Beim Ein-/Aussteigen am Fahrersitz übernimmt das Spiel die Steuerung (CharacterController aus, Spieler an ein
|
||||
// Fahrzeug gehängt) - dann und kurz nach dem Fahren nicht festhalten
|
||||
if (Time.time - lastDriving < AfterDrivingPause) { dwellStart = -1f; return null; }
|
||||
CharacterController cc = player.GetComponent<CharacterController>();
|
||||
if ((cc != null && !cc.enabled) || player.parent != null) { lastDriving = Time.time; dwellStart = -1f; return null; }
|
||||
@@ -98,31 +103,14 @@ namespace MSCO
|
||||
nextAutoCheck = Time.time + AutoCheckInterval;
|
||||
Vector3 head = cam.transform.position;
|
||||
|
||||
// Nach dem Aussteigen erst einmal weggehen, sonst säße man sofort wieder drin
|
||||
// Nach dem Aussteigen erst einmal aus dem Fahrzeug heraus, sonst säße man sofort wieder drin
|
||||
if (!autoArmed)
|
||||
{
|
||||
if ((head - lastExitSeat).sqrMagnitude > AutoRearmRange * AutoRearmRange) autoArmed = true;
|
||||
if (VehicleAround(objects, head) == null) autoArmed = true;
|
||||
else return null;
|
||||
}
|
||||
|
||||
SyncedBody found = null;
|
||||
Vector3 foundSeat = Vector3.zero;
|
||||
foreach (SyncedBody b in objects.AllVehicles())
|
||||
{
|
||||
if (b.Rb == null || (b.Rb.position - head).sqrMagnitude > 8f * 8f) continue;
|
||||
Vector3? seat = SeatFor(b, objects, players);
|
||||
if (seat == null) continue;
|
||||
if ((b.Rb.transform.TransformPoint(seat.Value) - head).sqrMagnitude > AutoEnterRange * AutoEnterRange) continue;
|
||||
Vector3 local = b.Rb.transform.InverseTransformPoint(head);
|
||||
if (Mathf.Abs(local.x) > Mathf.Abs(seat.Value.x) + AutoEnterSide) continue;
|
||||
// Nur von der Beifahrerseite her: Kopf auf der Seite des Beifahrersitzes und nicht weiter innen als der Sitz
|
||||
// (wer auf der Fahrerseite einsteigt, ist auf der anderen Seite bzw. in der Mitte)
|
||||
if (Mathf.Abs(seat.Value.x) >= CenterSeatThreshold
|
||||
&& (Mathf.Sign(local.x) != Mathf.Sign(seat.Value.x) || Mathf.Abs(local.x) < Mathf.Abs(seat.Value.x) - 0.1f)) continue;
|
||||
found = b;
|
||||
foundSeat = seat.Value;
|
||||
break;
|
||||
}
|
||||
SyncedBody found = VehicleAround(objects, head);
|
||||
if (found == null || found != dwellVehicle)
|
||||
{
|
||||
dwellVehicle = found;
|
||||
@@ -132,8 +120,57 @@ namespace MSCO
|
||||
if (Time.time - dwellStart < AutoEnterDwell) return null;
|
||||
dwellStart = -1f;
|
||||
dwellVehicle = null;
|
||||
Enter(found, foundSeat, player);
|
||||
return "Riding as passenger (Space or the passenger key to get out)";
|
||||
Enter(found, found.Rb.transform.InverseTransformPoint(head), player); // genau hier festhalten
|
||||
return "Riding along (Space or the passenger key to get out)";
|
||||
}
|
||||
|
||||
/// <summary>Fahrzeug, in dessen Umriss der Kopf gerade ist (null = in keinem).</summary>
|
||||
SyncedBody VehicleAround(ObjectSync objects, Vector3 head)
|
||||
{
|
||||
foreach (SyncedBody b in objects.AllVehicles())
|
||||
{
|
||||
if (b.Rb == null || (b.Rb.position - head).sqrMagnitude > 10f * 10f) continue;
|
||||
Bounds inner = InnerBounds(b);
|
||||
if (inner.Contains(b.Rb.transform.InverseTransformPoint(head))) return b;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
readonly Dictionary<Rigidbody, Bounds> innerBounds = new Dictionary<Rigidbody, Bounds>();
|
||||
|
||||
/// <summary>
|
||||
/// Innenraum des Fahrzeugs (lokal): Umriss aller festen Collider, seitlich und vorne/hinten etwas kleiner - neben
|
||||
/// der geschlossenen Tür steht man noch draußen, erst in der offenen Tür bzw. drin ist man "im Auto".
|
||||
/// </summary>
|
||||
Bounds InnerBounds(SyncedBody b)
|
||||
{
|
||||
Bounds result;
|
||||
if (innerBounds.TryGetValue(b.Rb, out result)) return result;
|
||||
Transform t = b.Rb.transform;
|
||||
bool any = false;
|
||||
foreach (Collider c in b.Rb.GetComponentsInChildren<Collider>())
|
||||
{
|
||||
if (c == null || c.isTrigger || !c.enabled) continue;
|
||||
Bounds wb = c.bounds;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Vector3 corner = wb.center + Vector3.Scale(wb.extents, new Vector3((i & 1) == 0 ? -1 : 1, (i & 2) == 0 ? -1 : 1, (i & 4) == 0 ? -1 : 1));
|
||||
Vector3 lp = t.InverseTransformPoint(corner);
|
||||
if (!any) { result = new Bounds(lp, Vector3.zero); any = true; }
|
||||
else result.Encapsulate(lp);
|
||||
}
|
||||
}
|
||||
if (!any) result = new Bounds(Vector3.zero, Vector3.zero);
|
||||
else
|
||||
{
|
||||
Vector3 size = result.size;
|
||||
// Weltachsen-Umrisse schräger Teile sind zu groß: seitlich 0.25 m, vorne/hinten 0.3 m kleiner,
|
||||
// oben 0.6 m Luft (Kopf über dem Dach der Ladefläche / im offenen Fahrzeug)
|
||||
result.size = new Vector3(Mathf.Max(0.1f, size.x - 0.5f), size.y + 0.6f, Mathf.Max(0.1f, size.z - 0.6f));
|
||||
result.center += new Vector3(0f, 0.3f, 0f);
|
||||
}
|
||||
innerBounds[b.Rb] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Enter(SyncedBody b, Vector3 seat, Transform player)
|
||||
@@ -222,8 +259,12 @@ namespace MSCO
|
||||
lastExitSeat = vehicle.Rb.transform.TransformPoint(seatHeadLocal);
|
||||
autoArmed = false;
|
||||
// Auf der Seite des Sitzes neben das Fahrzeug stellen
|
||||
// Zur näheren Seite neben das Fahrzeug (außerhalb seines Umrisses), auf Kopfhöhe von vorher
|
||||
float side = seatHeadLocal.x >= 0f ? 1f : -1f;
|
||||
Vector3 outside = vehicle.Rb.transform.TransformPoint(seatHeadLocal + new Vector3(side * ExitSideOffset, 0f, 0f));
|
||||
Bounds inner = InnerBounds(vehicle);
|
||||
float x = inner.size.sqrMagnitude > 0f ? inner.center.x + side * (inner.extents.x + 0.85f) : seatHeadLocal.x + side * ExitSideOffset;
|
||||
var local = new Vector3(x, seatHeadLocal.y, seatHeadLocal.z);
|
||||
Vector3 outside = vehicle.Rb.transform.TransformPoint(local);
|
||||
Vector3 cameraOffset = cam != null ? cam.transform.position - player.position : Vector3.up * 1.6f;
|
||||
player.position = outside - cameraOffset + Vector3.up * 0.1f;
|
||||
}
|
||||
@@ -238,6 +279,7 @@ namespace MSCO
|
||||
dwellVehicle = null;
|
||||
dwellStart = -1f;
|
||||
driverHeads.Clear();
|
||||
innerBounds.Clear();
|
||||
SetMovementEnabled(null, true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user