Add game mode manager with player-control and paint modes

Introduce an extensible game mode system toggled with Tab:
- Player Control: WASD movement with always-on mouse camera orbit
- Paint: player frozen, left-click paints, right-click holds to orbit

Add GameMode base class, GameModeManager, and the two concrete modes.
Refactor controlled scripts to expose clean state flags instead of
handling input themselves: ThirdPersonOrbitInput.LookMode,
PlayerCharacterController.ControlEnabled, MeshPainter.PaintingEnabled.

Also fix camera zoom: remove the obsolete /120 wheel normalization so
one scroll notch maps to one zoomSpeed step under the new Input System.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-22 15:13:46 +02:00
1 parent 6e8ab4bc6d
commit dcb1fc42a6
12 files changed
+358 -55

No files matched your search

+117
View File
@@ -0,0 +1,117 @@
using System.Collections.Generic;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
/// <summary>
/// Central state manager that switches the game between high-level modes.
/// Currently two modes exist:
/// 0. Player Control - WASD movement, camera orbits freely with the mouse.
/// 1. Paint - player stands still, left mouse paints the mesh, the
/// camera orbits only while the right mouse button is held.
///
/// Pressing the switch key (Tab) cycles to the next registered mode, so adding
/// more modes later automatically extends the cycle.
///
/// The manager owns references to the systems a mode may toggle (player
/// controller, orbit camera input, mesh painter) and exposes them to the modes.
/// Modes are plain C# classes derived from <see cref="GameMode"/>; register
/// additional ones in <see cref="BuildModes"/>.
///
/// Attach this to a single, persistent GameObject in the scene.
/// </summary>
[DisallowMultipleComponent]
public class GameModeManager : MonoBehaviour
{
[Header("Controlled Systems")]
[Tooltip("Player movement controller. Empty = found automatically in the scene.")]
public PlayerCharacterController player;
[Tooltip("Third-person orbit camera input. Empty = found automatically in the scene.")]
public ThirdPersonOrbitInput cameraInput;
[Tooltip("Mesh painter. Empty = found automatically in the scene.")]
public MeshPainter painter;
[Header("Switching")]
[Tooltip("Key that cycles to the next mode.")]
#if ENABLE_INPUT_SYSTEM
public Key switchKey = Key.Tab;
#else
public KeyCode switchKey = KeyCode.Tab;
#endif
[Tooltip("Index of the mode that is active at startup (0 = Player Control).")]
public int startModeIndex = 0;
// --- accessors used by the modes ---
public PlayerCharacterController Player => player;
public ThirdPersonOrbitInput CameraInput => cameraInput;
public MeshPainter Painter => painter;
private readonly List<GameMode> _modes = new List<GameMode>();
private int _activeIndex = -1;
/// <summary>The currently active mode (null before startup).</summary>
public GameMode ActiveMode =>
(_activeIndex >= 0 && _activeIndex < _modes.Count) ? _modes[_activeIndex] : null;
private void Awake()
{
// Auto-resolve references so the manager works with minimal wiring.
if (player == null) player = FindFirstObjectByType<PlayerCharacterController>();
if (cameraInput == null) cameraInput = FindFirstObjectByType<ThirdPersonOrbitInput>();
if (painter == null) painter = FindFirstObjectByType<MeshPainter>();
BuildModes();
}
private void Start()
{
if (_modes.Count > 0)
SwitchTo(Mathf.Clamp(startModeIndex, 0, _modes.Count - 1));
}
/// <summary>Registers all available modes. Add new modes here.</summary>
private void BuildModes()
{
_modes.Clear();
_modes.Add(new PlayerControlMode());
_modes.Add(new PaintMode());
foreach (var m in _modes)
m.Bind(this);
}
private void Update()
{
if (_modes.Count == 0) return;
if (WasSwitchPressed())
SwitchTo((_activeIndex + 1) % _modes.Count);
ActiveMode?.Tick();
}
/// <summary>Activates the mode at <paramref name="index"/> (Exit old, Enter new).</summary>
public void SwitchTo(int index)
{
if (index < 0 || index >= _modes.Count || index == _activeIndex) return;
ActiveMode?.Exit();
_activeIndex = index;
ActiveMode.Enter();
Debug.Log($"[GameModeManager] Mode -> {ActiveMode.DisplayName}", this);
}
private bool WasSwitchPressed()
{
#if ENABLE_INPUT_SYSTEM
return Keyboard.current != null && Keyboard.current[switchKey].wasPressedThisFrame;
#else
return Input.GetKeyDown(switchKey);
#endif
}
}