This can be seen as the initial state of the project after the released demo.
The changes include:
- New ship models
- Singleton manager structure to keep project scaleable in the future
- Managing players, their settings, character choices, statistics, match setups, controls etc. in a separate decoupled scene
- Main menu with transitions to the arena scene
- Beginnings of a custom audio solution
- Logging with Log4Net
It is really a complete overhaul of the projects structure and management.
176 lines
4.8 KiB
C#
176 lines
4.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using log4net;
|
|
using ShipHandling;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using static InputActionMaps;
|
|
|
|
namespace Managers
|
|
{
|
|
public class ControlsManager : MonoBehaviour
|
|
{
|
|
private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
/// <summary>
|
|
/// Globally accessible member to use manager with.
|
|
/// </summary>
|
|
public static ControlsManager G { get; private set; }
|
|
private Dictionary<int, UniqueControl> playersControlSchemes = new Dictionary<int, UniqueControl>();
|
|
public Dictionary<int, Player> unassignedPlayers = new Dictionary<int, Player>();
|
|
public EventHandler<Tuple<int, UniqueControl>> PlayerControlAssigned;
|
|
private ControlSchemeDetection controlSchemeDetector;
|
|
|
|
void Awake()
|
|
{
|
|
G = this;
|
|
Log.Info("Awake");
|
|
}
|
|
|
|
public void AssignControlsToPlayers(List<Player> players)
|
|
{
|
|
playersControlSchemes?.Clear();
|
|
foreach (Player p in players)
|
|
{
|
|
if (p.character.shipInput != null)
|
|
{
|
|
ShipInputHandler input = p.character.shipInput;
|
|
// TODO: Make this more unique with the GUID and save across more
|
|
// and different scenarios?
|
|
playersControlSchemes.Add(p.playerNumber,
|
|
new UniqueControl()
|
|
{
|
|
SchemeName = input.user.controlScheme.Value.name,
|
|
DeviceId = input.user.pairedDevices[0].deviceId
|
|
});
|
|
|
|
// TODO: Show some kind of hint which control scheme this player
|
|
// is using.
|
|
// TODO: Needs a possibility to change controls easily.
|
|
}
|
|
else
|
|
{
|
|
unassignedPlayers.Add(p.playerNumber, p);
|
|
}
|
|
}
|
|
StartControlSchemeDetection();
|
|
}
|
|
|
|
public void StartControlSchemeDetection()
|
|
{
|
|
controlSchemeDetector = new ControlSchemeDetection();
|
|
controlSchemeDetector.ControlSchemeDetected +=
|
|
(obj, uniqueControl) => DetectPlayerControls(uniqueControl);
|
|
controlSchemeDetector.EnableDetection();
|
|
}
|
|
|
|
private void DetectPlayerControls(UniqueControl uc)
|
|
{
|
|
if (unassignedPlayers.Count == 0)
|
|
{
|
|
controlSchemeDetector.DisableDetection();
|
|
Log.Debug("No player without controls left.");
|
|
return;
|
|
}
|
|
int playerId = unassignedPlayers.Keys.First();
|
|
|
|
if (playersControlSchemes.ContainsValue(uc))
|
|
{
|
|
Log.Warn("These controls can't be assigned to a second player.");
|
|
return;
|
|
}
|
|
|
|
unassignedPlayers[playerId].spawnedCharacter.TryGetComponent(out Ship s);
|
|
|
|
AssignShipControls(uc, s, unassignedPlayers[playerId].character);
|
|
Log.Info($"Player Number: {playerId} got assigned control scheme: {uc.SchemeName}.");
|
|
playersControlSchemes.Add(playerId, uc);
|
|
unassignedPlayers.Remove(playerId);
|
|
PlayerControlAssigned.Invoke(this, new Tuple<int, UniqueControl>(playerId, uc));
|
|
}
|
|
|
|
private void AssignShipControls(UniqueControl uc, Ship s, ShipProperties p)
|
|
{
|
|
p.shipInput = new ShipInputHandler(s.state,
|
|
InputSystem.GetDeviceById(uc.DeviceId), uc.SchemeName);
|
|
}
|
|
}
|
|
|
|
}
|
|
public struct UniqueControl
|
|
{
|
|
public string SchemeName;
|
|
public int DeviceId;
|
|
/// <summary>
|
|
/// Struct to simply define a control scheme with the device it belongs to.
|
|
/// </summary>
|
|
/// <param name="sn">Name of the control scheme (See Action Maps)</param>
|
|
/// <param name="di">Id of the device the control belongs to</param>
|
|
public UniqueControl(string schemeName, int deviceId)
|
|
{
|
|
SchemeName = schemeName;
|
|
DeviceId = deviceId;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Listens to all the events defined in the Player action map
|
|
/// (has multiple schemes across different devices)
|
|
/// and fires an event with information which device and control scheme
|
|
/// caused the event.
|
|
/// </summary>
|
|
public class ControlSchemeDetection : IPlayerActions
|
|
{
|
|
InputActionMaps actionMaps;
|
|
public event EventHandler<UniqueControl> ControlSchemeDetected;
|
|
|
|
public ControlSchemeDetection()
|
|
{
|
|
actionMaps = new InputActionMaps();
|
|
actionMaps.Player.SetCallbacks(this);
|
|
}
|
|
|
|
public void EnableDetection()
|
|
{
|
|
actionMaps.Player.Enable();
|
|
}
|
|
public void DisableDetection()
|
|
{
|
|
actionMaps.Player.Disable();
|
|
}
|
|
|
|
public void OnBoost(InputAction.CallbackContext context)
|
|
{
|
|
readControlScheme(context);
|
|
}
|
|
|
|
public void OnReset(InputAction.CallbackContext context)
|
|
{
|
|
readControlScheme(context);
|
|
}
|
|
|
|
public void OnSteer(InputAction.CallbackContext context)
|
|
{
|
|
readControlScheme(context);
|
|
}
|
|
|
|
public void OnThrust(InputAction.CallbackContext context)
|
|
{
|
|
readControlScheme(context);
|
|
}
|
|
|
|
public void readControlScheme(InputAction.CallbackContext context)
|
|
{
|
|
if (!context.canceled || context.performed)
|
|
{
|
|
return;
|
|
}
|
|
int bindingIndex = context.action.GetBindingIndexForControl(context.control);
|
|
InputBinding binding = context.action.bindings[bindingIndex];
|
|
string controlScheme = binding.groups.Split(';')[0];
|
|
ControlSchemeDetected.Invoke(this, new UniqueControl(controlScheme,
|
|
context.control.device.deviceId));
|
|
}
|
|
} |