Co-Op Layer
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using NUnit.Framework;
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ProjectM.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Pure-function tests for <see cref="PlayerSpawnMath.SpawnOffset"/> (no ECS world), mirroring
|
||||
/// StatMathTests. Pins the M4 co-op deterministic spawn spread: stable, distinct per-NetworkId ring
|
||||
/// positions so players never stack on connect.
|
||||
/// </summary>
|
||||
public class PlayerSpawnRingTests
|
||||
{
|
||||
const float R = 2.5f;
|
||||
const int Slots = 4;
|
||||
const float Eps = 1e-4f;
|
||||
|
||||
[Test]
|
||||
public void Deterministic_SameInputs_SameOffset()
|
||||
{
|
||||
var a = PlayerSpawnMath.SpawnOffset(2, R, Slots);
|
||||
var b = PlayerSpawnMath.SpawnOffset(2, R, Slots);
|
||||
Assert.AreEqual(a.x, b.x, Eps);
|
||||
Assert.AreEqual(a.y, b.y, Eps);
|
||||
Assert.AreEqual(a.z, b.z, Eps);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FirstFour_Land_On_Cardinal_Ring_Slots()
|
||||
{
|
||||
// NetworkIds start at 1; slots=4 -> 0, 90, 180, 270 degrees on a ring of radius R.
|
||||
AssertXz(PlayerSpawnMath.SpawnOffset(1, R, Slots), R, 0f);
|
||||
AssertXz(PlayerSpawnMath.SpawnOffset(2, R, Slots), 0f, R);
|
||||
AssertXz(PlayerSpawnMath.SpawnOffset(3, R, Slots), -R, 0f);
|
||||
AssertXz(PlayerSpawnMath.SpawnOffset(4, R, Slots), 0f, -R);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Distinct_NetworkIds_Give_Distinct_Positions()
|
||||
{
|
||||
var seen = new System.Collections.Generic.List<float3>();
|
||||
for (int id = 1; id <= 8; id++)
|
||||
{
|
||||
var p = PlayerSpawnMath.SpawnOffset(id, R, Slots);
|
||||
foreach (var q in seen)
|
||||
Assert.Greater(math.distance(p, q), 1e-3f, $"id {id} collides with an earlier slot");
|
||||
seen.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FifthPlayer_Spills_To_Outer_Ring()
|
||||
{
|
||||
// idx 4 with slots 4 -> ring 1, slot 0 -> radius doubled, angle 0.
|
||||
AssertXz(PlayerSpawnMath.SpawnOffset(5, R, Slots), 2f * R, 0f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonPositiveRadius_Returns_Zero()
|
||||
{
|
||||
Assert.AreEqual(0f, math.length(PlayerSpawnMath.SpawnOffset(3, 0f, Slots)), Eps);
|
||||
Assert.AreEqual(0f, math.length(PlayerSpawnMath.SpawnOffset(3, -1f, Slots)), Eps);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DegenerateSlots_DoNotThrow_AndStayDistinct()
|
||||
{
|
||||
// slots < 1 is clamped to 1 (every player on its own concentric ring).
|
||||
var a = PlayerSpawnMath.SpawnOffset(1, R, 0);
|
||||
var b = PlayerSpawnMath.SpawnOffset(2, R, 0);
|
||||
Assert.Greater(math.distance(a, b), 1e-3f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Offset_Is_Planar_NoVerticalComponent()
|
||||
{
|
||||
for (int id = 1; id <= 6; id++)
|
||||
Assert.AreEqual(0f, PlayerSpawnMath.SpawnOffset(id, R, Slots).y, Eps);
|
||||
}
|
||||
|
||||
static void AssertXz(float3 p, float x, float z)
|
||||
{
|
||||
Assert.AreEqual(x, p.x, Eps);
|
||||
Assert.AreEqual(z, p.z, Eps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6578b95ff4c4c40c780ec25b56e28eff
|
||||
Reference in New Issue
Block a user