Tilt Five™ Unity API  1.3.0
 
Loading...
Searching...
No Matches
Player.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using UnityEngine;
5
6#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
7using UnityEngine.InputSystem;
8#endif
9
10namespace TiltFive
11{
15 public class Player : Singleton<Player>
16 {
17 #region Private Fields
18
19 private Dictionary<PlayerIndex, PlayerCore> players = new Dictionary<PlayerIndex, PlayerCore>();
20 internal static bool scanningForPlayers = false;
21
22 #endregion
23
24
25 #region Public Functions
26
32 public static bool IsConnected(PlayerIndex playerIndex)
33 {
34 return playerIndex != PlayerIndex.None && Instance.players.TryGetValue(playerIndex, out var playerCore);
35 }
36
37
44 public static bool TryGetFriendlyName(PlayerIndex playerIndex, out string friendlyName)
45 {
46 if (playerIndex == PlayerIndex.None || !Instance.players.TryGetValue(playerIndex, out var playerCore))
47 {
48 friendlyName = "";
49 return false;
50 }
51
52 friendlyName = playerCore.FriendlyName;
53 return true;
54 }
55
56 #endregion
57
58
59 #region Internal Functions
60
65 internal static void Update(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
66 {
67 if (scanningForPlayers)
68 {
69 return;
70 }
71
72 if (playerSettings != null && Instance.players.TryGetValue(playerSettings.PlayerIndex, out var playerCore))
73 {
74 var playerIndex = playerSettings.PlayerIndex;
75
76 // Check to make sure the glasses for this player are still connected.
77 if (!Glasses.IsConnected(playerCore.GlassesHandle))
78 {
79 // This player's glasses are gone, so it's time to destroy this PlayerCore.
80 Log.Info($"Player {playerIndex} was removed due to their glasses (handle: {playerCore.GlassesHandle}) being disconnected.");
81 Instance.players.Remove(playerIndex);
82 return;
83 }
84
85 playerCore.Update(playerSettings, spectatorSettings);
86 }
87 }
88
93 internal static void Reset(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
94 {
95 var playerIndex = playerSettings.PlayerIndex;
96
97 if (playerSettings != null && Instance.players.TryGetValue(playerIndex, out var playerCore))
98 {
99 if (Glasses.IsConnected(playerCore.GlassesHandle))
100 {
101 playerCore.Reset(playerSettings, spectatorSettings);
102 }
103 else
104 {
105 Validate(playerSettings);
106 }
107 }
108 }
109
114 internal static void Validate(PlayerSettings playerSettings)
115 {
116 if (playerSettings == null)
117 {
118 return;
119 }
120
121 var scaleSettings = playerSettings.scaleSettings;
122 scaleSettings.contentScaleRatio = Mathf.Clamp(scaleSettings.contentScaleRatio, ScaleSettings.MIN_CONTENT_SCALE_RATIO, float.MaxValue);
123
124 playerSettings.Validate();
125 }
126
127
131 internal static void ScanForNewPlayers()
132 {
133 if (scanningForPlayers)
134 {
135 return;
136 }
137 scanningForPlayers = true;
139
141 scanningForPlayers = false;
142 }
143
144 internal static bool TryGetGlassesHandle(PlayerIndex playerIndex, out GlassesHandle glassesHandle)
145 {
146 if (playerIndex == PlayerIndex.None)
147 {
148 glassesHandle = new GlassesHandle();
149 return false;
150 }
151 var playerAvailable = Instance.players.TryGetValue(playerIndex, out var playerCore);
152 glassesHandle = playerCore?.GlassesHandle ?? new GlassesHandle();
153 return playerAvailable;
154 }
155
156 internal static bool TryGetPlayerIndex(GlassesHandle glassesHandle, out PlayerIndex playerIndex)
157 {
158 foreach (var keyValuePair in Instance.players)
159 {
160 var currentPlayerIndex = keyValuePair.Key;
161 var currentPlayerCore = keyValuePair.Value;
162 if (currentPlayerCore.GlassesHandle == glassesHandle)
163 {
164 playerIndex = currentPlayerIndex;
165 return true;
166 }
167 }
168 playerIndex = PlayerIndex.None;
169 return false;
170 }
171
172 internal static bool AllSupportedPlayersConnected()
173 {
174 if(!TiltFiveSingletonHelper.TryGetISceneInfo(out var sceneInfo))
175 {
176 return false;
177 }
178 var supportedPlayers = sceneInfo.GetSupportedPlayerCount();
179
180 for(PlayerIndex playerIndex = PlayerIndex.One; playerIndex <= (PlayerIndex)supportedPlayers; playerIndex++)
181 {
182 // If any supported player isn't connected, return false
183 if(!IsConnected(playerIndex))
184 {
185 return false;
186 }
187 }
188 // Otherwise they're all connected, and we can return true.
189 return true;
190 }
191
196 internal static bool TryAddPlayer(GlassesHandle glassesHandle, out PlayerIndex playerIndex)
197 {
198 var players = Instance.players;
199 if (players.Count >= GlassesSettings.MAX_SUPPORTED_GLASSES_COUNT)
200 {
201 playerIndex = PlayerIndex.None;
202 return false;
203 }
204
205 if(TryGetPlayerIndex(glassesHandle, out var existingPlayerIndex))
206 {
207 playerIndex = PlayerIndex.None;
208 return false; // This player already exists.
209 }
210
211 foreach (PlayerIndex currentPlayerIndex in Enum.GetValues(typeof(PlayerIndex)))
212 {
213 if (currentPlayerIndex == PlayerIndex.None)
214 {
215 continue;
216 }
217
218 // Assign the smallest (numerically) playerIndex that isn't already assigned.
219 // For example, if player #1 disappeared, and player #2 is still available,
220 // then we assign the specified glasses to a new player #1.
221 if (!players.ContainsKey(currentPlayerIndex))
222 {
223 Glasses.TryGetFriendlyName(glassesHandle, out var friendlyName);
224 players[currentPlayerIndex] = new PlayerCore(glassesHandle, friendlyName);
225
226 Log.Info($"Player {currentPlayerIndex} created. Glasses: {glassesHandle} (\"{friendlyName}\")");
227
228 // Default control should go to the lowest player index.
229 // If this playerIndex is lower than that of any other current players,
230 // reset the default glasses handle.
231
232
233 bool lowestPlayerIndex = false;
234
235 // TODO: Determine whether this is the lowest player index.
236 // Until then, default control stays with player 2 in the above scenario.
237
238 if (lowestPlayerIndex)
239 {
240 Glasses.SetDefaultGlassesHandle(glassesHandle);
241 }
242
243 playerIndex = currentPlayerIndex;
244 return true;
245 }
246 }
247
248 // We shouldn't ever reach this.
249 playerIndex = PlayerIndex.None;
250 return false;
251 }
252
253 internal static void OnEnable(uint supportedPlayers)
254 {
255#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
256 var glassesDevices = Input.glassesDevices;
257 var wandDevices = Input.wandDevices;
258 var leftIndex = (int)ControllerIndex.Left;
259 var rightIndex = (int)ControllerIndex.Right;
260
261 for (var playerIndex = PlayerIndex.One; playerIndex <= PlayerIndex.Four; playerIndex++)
262 {
263 var i = (int)playerIndex - 1;
264 if ((uint)playerIndex > supportedPlayers)
265 {
266 // Remove a GlassesDevice if possible
267 if (glassesDevices[i] != null)
268 {
269 InputSystem.RemoveDevice(glassesDevices[i]);
270 glassesDevices[i] = null;
271 }
272
273 // Remove two WandDevices if possible
274 if (wandDevices[i, leftIndex] != null)
275 {
276 InputSystem.RemoveDevice(wandDevices[i, leftIndex]);
277 wandDevices[i, leftIndex] = null;
278 }
279 if (wandDevices[i, rightIndex] != null)
280 {
281 InputSystem.RemoveDevice(wandDevices[i, rightIndex]);
282 wandDevices[i, rightIndex] = null;
283 }
284 }
285 else
286 {
287 // Create a GlassesDevice if necessary
288 Input.AddGlassesDevice(playerIndex);
289
290 // Create two WandDevices if necessary
291 Input.AddWandDevice(playerIndex, ControllerIndex.Left);
292 Input.AddWandDevice(playerIndex, ControllerIndex.Right);
293 InputSystem.QueueConfigChangeEvent(wandDevices[i, leftIndex]);
294 InputSystem.QueueConfigChangeEvent(wandDevices[i, rightIndex]);
295
296 // Ensure that the wands are associated with their parent glasses
297 glassesDevices[i].LeftWand = wandDevices[i, leftIndex];
298 glassesDevices[i].RightWand = wandDevices[i, rightIndex];
299 }
300
301 if(Application.isPlaying)
302 {
303 // Disable the T5 devices at the start of runtime.
304 // As glasses/wands connect, they will enable their respective devices.
305 if (glassesDevices[i] != null)
306 {
307 InputSystem.DisableDevice(glassesDevices[i]);
308 }
309 if (wandDevices[i, leftIndex] != null)
310 {
311 InputSystem.DisableDevice(wandDevices[i, leftIndex]);
312 }
313 if (wandDevices[i, rightIndex] != null)
314 {
315 InputSystem.DisableDevice(wandDevices[i, rightIndex]);
316 }
317 }
318 }
319#endif
320 }
321
322 internal static void OnDisable()
323 {
324 Glasses.OnDisable();
325 Wand.OnDisable();
326 }
327
328 internal static bool TryGetFirstConnectedPlayer(out PlayerIndex playerIndex)
329 {
330 for(PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
331 {
332 if(IsConnected(i))
333 {
334 playerIndex = i;
335 return true;
336 }
337 }
338
339 playerIndex = PlayerIndex.None;
340 return false;
341 }
342
343#if UNITY_EDITOR
344
349 internal static void DrawGizmos(PlayerSettings playerSettings)
350 {
351 if (playerSettings == null)
352 {
353 return;
354 }
355
356 var gameBoardSettings = playerSettings.gameboardSettings;
357
358 if (gameBoardSettings.currentGameBoard != null)
359 {
360 gameBoardSettings.currentGameBoard.DrawGizmo(playerSettings.scaleSettings, gameBoardSettings);
361 }
362 }
363#endif
364
365 #endregion
366
367
368 #region Private Classes
369
370 private class PlayerCore
371 {
373 public readonly string FriendlyName;
374
375 public PlayerCore(GlassesHandle glassesHandle, string friendlyName)
376 {
377 GlassesHandle = glassesHandle;
378 FriendlyName = friendlyName;
379 }
380
381 internal void Update(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
382 {
383 if (!Glasses.Validate(playerSettings.glassesSettings, spectatorSettings, GlassesHandle))
384 {
385 Glasses.Reset(playerSettings.glassesSettings, spectatorSettings, GlassesHandle);
386 }
387 GetLatestPoseData(playerSettings, spectatorSettings);
388 }
389
390 internal void Reset(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
391 {
392 Glasses.Reset(playerSettings.glassesSettings, spectatorSettings, GlassesHandle);
393 }
394
395
399 private void GetLatestPoseData(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
400 {
401 var glassesSettings = playerSettings.glassesSettings;
402 var rightWandSettings = playerSettings.rightWandSettings;
403 var leftWandSettings = playerSettings.leftWandSettings;
404 var scaleSettings = playerSettings.scaleSettings;
405 var gameboardSettings = playerSettings.gameboardSettings;
406
407 Glasses.Update(GlassesHandle, glassesSettings, scaleSettings, gameboardSettings, spectatorSettings);
408 Wand.Update(GlassesHandle, rightWandSettings, scaleSettings, gameboardSettings);
409 Wand.Update(GlassesHandle, leftWandSettings, scaleSettings, gameboardSettings);
410 }
411 }
412
413 #endregion
414 }
415}
GameBoard currentGameBoard
The game board is the window into the game world, as well as the origin about which the glasses/wand ...
The Glasses API and runtime.
Definition: Glasses.cs:35
static void Reset(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings=null, PlayerIndex playerIndex=PlayerIndex.None)
Reset this T:TiltFive.Glasses.
Definition: Glasses.cs:149
static bool TryGetFriendlyName(PlayerIndex playerIndex, out string friendlyName)
Definition: Glasses.cs:250
static void Update(GlassesSettings glassesSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
Updates this T:TiltFive.Glasses.
Definition: Glasses.cs:201
static bool IsConnected(PlayerIndex playerIndex=PlayerIndex.One)
Indicate if the specified glasses are connected.
Definition: Glasses.cs:231
static bool Validate(GlassesSettings glassesSettings, SpectatorSettings spectatorSettings=null, PlayerIndex playerIndex=PlayerIndex.One)
Validates the specified glassesSettings with the specified glasses core.
Definition: Glasses.cs:182
static void ScanForGlasses()
Definition: Glasses.cs:323
GlassesSettings encapsulates all configuration data used by the Glasses' tracking runtime to compute ...
Provides access to Wand inputs.
Definition: Input.cs:31
The Logger.
Definition: Log.cs:42
static void Info(string m, params object[] list)
INFO logging function call.
Definition: Log.cs:140
readonly string FriendlyName
Definition: Player.cs:373
PlayerCore(GlassesHandle glassesHandle, string friendlyName)
Definition: Player.cs:375
readonly GlassesHandle GlassesHandle
Definition: Player.cs:372
void GetLatestPoseData(PlayerSettings playerSettings, SpectatorSettings spectatorSettings)
Obtains the latest pose for all trackable objects.
Definition: Player.cs:399
Provides access to player settings and functionality.
Definition: Player.cs:16
Dictionary< PlayerIndex, PlayerCore > players
Definition: Player.cs:19
static bool IsConnected(PlayerIndex playerIndex)
Determines whether the specified player has an associated pair of glasses connected.
Definition: Player.cs:32
static bool TryGetFriendlyName(PlayerIndex playerIndex, out string friendlyName)
Attempts to get the friendly name assigned to the specified player's glasses.
Definition: Player.cs:44
ScaleSettings scaleSettings
GameBoardSettings gameboardSettings
WandSettings leftWandSettings
GlassesSettings glassesSettings
WandSettings rightWandSettings
ScaleSettings contains the scale data used to translate between Unity units and the user's physical s...
const float MIN_CONTENT_SCALE_RATIO
static bool TryGetISceneInfo(out ISceneInfo sceneInfo)
The Wand API and runtime.
Definition: Wand.cs:56
static void ScanForWands()
Definition: Wand.cs:204
static void Update(WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings, PlayerIndex playerIndex=PlayerIndex.One)
Definition: Wand.cs:152
Definition: Log.cs:21
ControllerIndex
Since wands are all physically identical (they have no "handedness"), it doesn't make sense to addres...
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)