fix: chat input isolation, mouse lock, multi spawn

- PlayerController: block WASD/jump callbacks when ChatUI is open
- PlayerController: clic droit = unlock souris, clic gauche = re-lock (n'est plus un toggle)
- PlayerController: ajoute ResetInputs() appelé à l'ouverture du chat
- ChatUI: appelle ResetInputs() quand le panel s'ouvre pour éviter les touches collées
- NetworkManager: seed les joueurs déjà présents dans la room à la connexion
  (les OnAdd Colyseus peuvent être manqués si l'état est décodé avant l'enregistrement des callbacks)
- NetworkManager: garde anti-doublon dans OnPlayerAdd
- NetworkManager: fallback sphere si remotePlayerPrefab est null

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 08:22:40 +02:00
parent aa27725c4e
commit e2fa2ba8a9
3 changed files with 42 additions and 81 deletions

View File

@@ -180,20 +180,18 @@ public class PlayerController : MonoBehaviour
// Update is called once per frame // Update is called once per frame
void Update() void Update()
{ {
// Toggle cursor lock/unlock avec clic droit (disabled when keybind menu is open) // Cursor lock: right-click unlocks, left-click re-locks (disabled when any UI panel is open)
if (!KeyBindingUI.IsVisible && Mouse.current != null && Mouse.current.rightButton.wasPressedThisFrame) if (!ChatUI.IsVisible && !KeyBindingUI.IsVisible && Mouse.current != null)
{ {
if (Cursor.lockState == CursorLockMode.Locked) if (Cursor.lockState == CursorLockMode.Locked && Mouse.current.rightButton.wasPressedThisFrame)
{ {
Cursor.lockState = CursorLockMode.None; Cursor.lockState = CursorLockMode.None;
Cursor.visible = true; Cursor.visible = true;
Debug.Log("Cursor UNLOCKED");
} }
else else if (Cursor.lockState != CursorLockMode.Locked && Mouse.current.leftButton.wasPressedThisFrame)
{ {
Cursor.lockState = CursorLockMode.Locked; Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false; Cursor.visible = false;
Debug.Log("Cursor LOCKED");
} }
} }
@@ -374,33 +372,19 @@ public class PlayerController : MonoBehaviour
public void OnJump(InputAction.CallbackContext context) public void OnJump(InputAction.CallbackContext context)
{ {
if (ChatUI.IsVisible) { isJumpPressed = false; jumpPressTime = 0f; return; }
if (context.started) if (context.started)
{ {
isJumpPressed = true; isJumpPressed = true;
jumpPressTime = 0f; jumpPressTime = 0f;
StatsTracker.Instance?.RegisterJump(); StatsTracker.Instance?.RegisterJump();
Debug.Log("Jump Started");
}
else if (context.performed)
{
// Action validée (utile pour saut immédiat aussi)
Debug.Log("Jump Performed");
} }
else if (context.canceled) else if (context.canceled)
{ {
// Touche relâchée
float jumpForceFactor = Mathf.Clamp01(jumpPressTime / maxJumpHoldTime); float jumpForceFactor = Mathf.Clamp01(jumpPressTime / maxJumpHoldTime);
if (IsGrounded()) if (IsGrounded())
{
PerformJump(jumpForceFactor * JumpForce); PerformJump(jumpForceFactor * JumpForce);
Debug.Log($"Jump Released after {jumpPressTime}s -> Force factor: {jumpForceFactor}");
}
else
{
Debug.Log("Jump Released but not grounded.");
}
// Reset jump state so gauge goes back to 0
isJumpPressed = false; isJumpPressed = false;
jumpPressTime = 0f; jumpPressTime = 0f;
} }
@@ -424,75 +408,30 @@ public class PlayerController : MonoBehaviour
public void OnForward(InputAction.CallbackContext context) public void OnForward(InputAction.CallbackContext context)
{ {
if (context.started) if (ChatUI.IsVisible) { isForwardHeld = false; return; }
{ if (context.started) isForwardHeld = true;
isForwardHeld = true; else if (context.canceled) isForwardHeld = false;
Debug.Log("Forward Action Started");
}
else if (context.performed)
{
// Forward action performed
Debug.Log("Forward Action Performed");
}
else if (context.canceled)
{
isForwardHeld = false;
Debug.Log("Forward Action Canceled");
}
} }
public void OnBackwards(InputAction.CallbackContext context) public void OnBackwards(InputAction.CallbackContext context)
{ {
if (context.started) if (ChatUI.IsVisible) { isBackwardsHeld = false; return; }
{ if (context.started) isBackwardsHeld = true;
isBackwardsHeld = true; else if (context.canceled) isBackwardsHeld = false;
Debug.Log("Backwards Action Started");
}
else if (context.performed)
{
Debug.Log("Backwards Action Performed");
}
else if (context.canceled)
{
isBackwardsHeld = false;
Debug.Log("Backwards Action Canceled");
}
} }
public void OnLeft(InputAction.CallbackContext context) public void OnLeft(InputAction.CallbackContext context)
{ {
if (context.started) if (ChatUI.IsVisible) { isLeftHeld = false; return; }
{ if (context.started) isLeftHeld = true;
isLeftHeld = true; else if (context.canceled) isLeftHeld = false;
Debug.Log("Left Action Started");
}
else if (context.performed)
{
Debug.Log("Left Action Performed");
}
else if (context.canceled)
{
isLeftHeld = false;
Debug.Log("Left Action Canceled");
}
} }
public void OnRight(InputAction.CallbackContext context) public void OnRight(InputAction.CallbackContext context)
{ {
if (context.started) if (ChatUI.IsVisible) { isRightHeld = false; return; }
{ if (context.started) isRightHeld = true;
isRightHeld = true; else if (context.canceled) isRightHeld = false;
Debug.Log("Right Action Started");
}
else if (context.performed)
{
Debug.Log("Right Action Performed");
}
else if (context.canceled)
{
isRightHeld = false;
Debug.Log("Right Action Canceled");
}
} }
// --- Bump collision with remote players --- // --- Bump collision with remote players ---
@@ -564,6 +503,16 @@ public class PlayerController : MonoBehaviour
_isSquashing = false; _isSquashing = false;
} }
public void ResetInputs()
{
isForwardHeld = false;
isBackwardsHeld = false;
isLeftHeld = false;
isRightHeld = false;
isJumpPressed = false;
jumpPressTime = 0f;
}
void OnDestroy() void OnDestroy()
{ {
// Clean up name label (it's not parented to the ball) // Clean up name label (it's not parented to the ball)

View File

@@ -163,6 +163,13 @@ public class NetworkManager : MonoBehaviour
_room.OnMessage<ChatUI.ChatMessage>("chat", msg => { ChatUI.Instance?.ReceiveChatMessage(msg); }); _room.OnMessage<ChatUI.ChatMessage>("chat", msg => { ChatUI.Instance?.ReceiveChatMessage(msg); });
_room.OnLeave += OnRoomLeave; _room.OnLeave += OnRoomLeave;
// Seed players already present in the room (state decoded before callbacks were registered)
if (_room.State.players != null)
{
foreach (var kvp in _room.State.players)
OnPlayerAdd(kvp.Key, kvp.Value);
}
OnConnected?.Invoke(); OnConnected?.Invoke();
} }
@@ -257,11 +264,14 @@ public class NetworkManager : MonoBehaviour
PlayerCount = _room.State.players?.Count ?? 0; PlayerCount = _room.State.players?.Count ?? 0;
if (sessionId == LocalSessionId) return; if (sessionId == LocalSessionId) return;
if (_remotePlayers.ContainsKey(sessionId)) return; // prevent duplicate spawn
if (remotePlayerPrefab != null)
{ {
Vector3 spawnPos = new Vector3(player.x, player.y, player.z); Vector3 spawnPos = new Vector3(player.x, player.y, player.z);
GameObject remoteBall = Instantiate(remotePlayerPrefab, spawnPos, Quaternion.identity); GameObject remoteBall = remotePlayerPrefab != null
? Instantiate(remotePlayerPrefab, spawnPos, Quaternion.identity)
: GameObject.CreatePrimitive(PrimitiveType.Sphere);
remoteBall.transform.position = spawnPos;
remoteBall.name = $"RemotePlayer_{player.name}_{sessionId[..6]}"; remoteBall.name = $"RemotePlayer_{player.name}_{sessionId[..6]}";
var controller = remoteBall.GetComponent<RemotePlayerController>() var controller = remoteBall.GetComponent<RemotePlayerController>()

View File

@@ -76,6 +76,8 @@ public class ChatUI : MonoBehaviour
_pollTimer = POLL_INTERVAL; // poll immediately _pollTimer = POLL_INTERVAL; // poll immediately
Cursor.lockState = CursorLockMode.None; Cursor.lockState = CursorLockMode.None;
Cursor.visible = true; Cursor.visible = true;
// Release held movement keys so the ball doesn't keep moving while typing
FindFirstObjectByType<PlayerController>()?.ResetInputs();
} }
else else
{ {