+140
@@ -0,0 +1,140 @@
|
||||
using System.Diagnostics;
|
||||
using BSO.Net;
|
||||
|
||||
namespace BSO
|
||||
{
|
||||
/// <summary>
|
||||
/// Der eigene Spieler: Kamera, Spielfigur (KeyControlledCharacter) und eigener Bus (CarVehicle). Im Bus verschwindet
|
||||
/// die Figur aus der Szene - nur dann wird der eigene Bus festgelegt (das CarVehicle naechst der Kamera, im Cockpit
|
||||
/// ~5 m) und bleibt es, bis er verschwindet oder man in einem anderen Bus sitzt. Sonst springt die Zuordnung zu
|
||||
/// vorbeifahrendem Verkehr. Die Engine rechnet in cm.
|
||||
/// </summary>
|
||||
public static class LocalPlayer
|
||||
{
|
||||
const float RelockDistance = 3000; // cm: so weit weg von der Kamera, obwohl man faehrt -> anderer Bus
|
||||
|
||||
/// <summary>Ein verfolgtes Objekt: Platz in der Entity-Tabelle + Zeiger (zusammen = lebt noch).</summary>
|
||||
public class Tracked
|
||||
{
|
||||
public int Slot = -1;
|
||||
public nint Ptr;
|
||||
public Vec3 Pos, Rot;
|
||||
public bool Valid => Ptr != 0;
|
||||
|
||||
public void Set(EntityInfo? e)
|
||||
{
|
||||
Ptr = e?.Ptr ?? 0;
|
||||
Slot = e?.Slot ?? -1;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (Ptr != 0 && !Entities.StillThere(Slot, Ptr)) Ptr = 0;
|
||||
if (Ptr == 0) return;
|
||||
Pos = Vision.GetPosition(Ptr);
|
||||
Rot = Vision.GetOrientation(Ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly Tracked Bus = new(), Character = new();
|
||||
public static bool InScene { get; private set; }
|
||||
public static Vec3 Camera { get; private set; }
|
||||
/// <summary>cm pro Sekunde (aus der Bewegung des Busses bzw. der Figur).</summary>
|
||||
public static float Speed { get; private set; }
|
||||
|
||||
public static PlayerMode Mode => !InScene ? PlayerMode.Menu : Character.Valid ? PlayerMode.OnFoot : Bus.Valid ? PlayerMode.InBus : PlayerMode.Menu;
|
||||
|
||||
/// <summary>Was an die anderen geht: Position/Drehung des Busses im Bus, sonst der Figur.</summary>
|
||||
public static PlayerState State
|
||||
{
|
||||
get
|
||||
{
|
||||
PlayerMode mode = Mode;
|
||||
Tracked t = mode == PlayerMode.InBus ? Bus : Character;
|
||||
if (mode == PlayerMode.Menu) return new PlayerState { Mode = mode };
|
||||
return new PlayerState
|
||||
{
|
||||
Mode = mode,
|
||||
X = t.Pos.X, Y = t.Pos.Y, Z = t.Pos.Z,
|
||||
Yaw = t.Rot.X, Pitch = t.Rot.Y, Roll = t.Rot.Z,
|
||||
Speed = Speed
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static bool sceneLogged;
|
||||
static readonly Stopwatch speedClock = new(), findClock = new();
|
||||
static Vec3 lastPos;
|
||||
static PlayerMode lastMode;
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
nint cam = Vision.MainCamera;
|
||||
InScene = cam != 0 && Rtti.ClassName(cam) != null; // sonst Menue / Laden
|
||||
if (!InScene) return;
|
||||
Camera = Vision.GetPosition(cam);
|
||||
if (!sceneLogged)
|
||||
{
|
||||
sceneLogged = true;
|
||||
Bootstrap.Log("Szene da, Kamera bei " + Camera);
|
||||
}
|
||||
|
||||
Bus.Refresh();
|
||||
Character.Refresh();
|
||||
// Alle Entities durchsuchen kostet - 4x pro Sekunde reicht
|
||||
if (!findClock.IsRunning || findClock.ElapsedMilliseconds >= 250)
|
||||
{
|
||||
findClock.Restart();
|
||||
Find();
|
||||
}
|
||||
UpdateSpeed();
|
||||
}
|
||||
|
||||
static void Find()
|
||||
{
|
||||
EntityInfo? nearestCar = null, character = null;
|
||||
float bestDist = float.MaxValue;
|
||||
foreach (EntityInfo e in Entities.Scan())
|
||||
{
|
||||
if (e.Class == "KeyControlledCharacter") character = e;
|
||||
if (e.Class != "CarVehicle") continue;
|
||||
float d = (e.Pos - Camera).Length;
|
||||
if (d < bestDist) { bestDist = d; nearestCar = e; }
|
||||
}
|
||||
|
||||
if ((character?.Ptr ?? 0) != Character.Ptr)
|
||||
{
|
||||
Bootstrap.Log(character != null ? $"Spieler = KeyControlledCharacter in Platz {character.Value.Slot}" : "Spielfigur weg - Spieler sitzt im Bus");
|
||||
Character.Set(character);
|
||||
Character.Refresh();
|
||||
}
|
||||
|
||||
// Bus nur festlegen, wenn man drinsitzt (keine Spielfigur), und nur wechseln, wenn der alte fehlt oder weit weg ist
|
||||
bool driving = character == null;
|
||||
bool keep = Bus.Valid && (!driving || (Bus.Pos - Camera).Length < RelockDistance);
|
||||
if (keep || !driving || nearestCar == null || nearestCar.Value.Ptr == Bus.Ptr) return;
|
||||
Bootstrap.Log($"Eigener Bus = CarVehicle in Platz {nearestCar.Value.Slot}, {bestDist / 100:0.0} m von der Kamera");
|
||||
Bus.Set(nearestCar);
|
||||
Bus.Refresh();
|
||||
}
|
||||
|
||||
static void UpdateSpeed()
|
||||
{
|
||||
PlayerMode mode = Mode;
|
||||
Vec3 pos = mode == PlayerMode.InBus ? Bus.Pos : Character.Pos;
|
||||
if (mode != lastMode || !speedClock.IsRunning)
|
||||
{
|
||||
lastMode = mode;
|
||||
lastPos = pos;
|
||||
speedClock.Restart();
|
||||
Speed = 0;
|
||||
return;
|
||||
}
|
||||
double seconds = speedClock.Elapsed.TotalSeconds;
|
||||
if (seconds < 0.25) return;
|
||||
Speed = (float)((pos - lastPos).Length / seconds);
|
||||
lastPos = pos;
|
||||
speedClock.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user