AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
PlayerController.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using UnityEngine;
5 using UnityEngine.Networking;
7 
8 namespace HoloToolkit.Unity.SharingWithUNET
9 {
13  [NetworkSettings(sendInterval = 0.033f)]
14  public class PlayerController : NetworkBehaviour, IInputClickHandler
15  {
16  private static PlayerController _Instance = null;
20  public static PlayerController Instance
21  {
22  get
23  {
24  return _Instance;
25  }
26  }
27 
33  public GameObject bullet;
34 
35  public bool CanShareAnchors;
36 
40  private Transform sharedWorldAnchorTransform;
41 
45  private UNetAnchorManager anchorManager;
46 
50  [SyncVar]
51  private Vector3 localPosition;
52 
56  [SyncVar]
57  private Quaternion localRotation;
58 
64  [Command(channel = 1)]
65  public void CmdTransform(Vector3 postion, Quaternion rotation)
66  {
67  localPosition = postion;
68  localRotation = rotation;
69  }
70 
74  [SyncVar(hook = "AnchorEstablishedChanged")]
75  bool AnchorEstablished;
76 
82  [Command]
83  private void CmdSendAnchorEstablished(bool Established)
84  {
85  AnchorEstablished = Established;
86  if (Established && SharesSpatialAnchors && !isLocalPlayer)
87  {
88  Debug.Log("remote device likes the anchor");
89 #if UNITY_WSA
90  anchorManager.AnchorFoundRemotely();
91 #endif
92  }
93  }
94 
99  void AnchorEstablishedChanged(bool update)
100  {
101  Debug.LogFormat("AnchorEstablished for {0} was {1} is now {2}", PlayerName, AnchorEstablished, update);
102  AnchorEstablished = update;
103  // only draw the mesh for the player if the anchor is found.
104  GetComponentInChildren<MeshRenderer>().enabled = update;
105  }
106 
110  [SyncVar(hook = "PlayerNameChanged")]
111  string PlayerName;
112 
117  [Command]
118  private void CmdSetPlayerName(string playerName)
119  {
120  PlayerName = playerName;
121  }
122 
127  void PlayerNameChanged(string update)
128  {
129  Debug.LogFormat("Player name changing from {0} to {1}", PlayerName, update);
130  PlayerName = update;
131  // Special case for spectator view
132  if (PlayerName.ToLower() == "spectatorviewpc")
133  {
134  gameObject.SetActive(false);
135  }
136  }
137 
138 #pragma warning disable 0414
139  [SyncVar(hook = "PlayerIpChanged")]
143  string PlayerIp;
144 #pragma warning restore 0414
145 
150  [Command]
151  private void CmdSetPlayerIp(string playerIp)
152  {
153  PlayerIp = playerIp;
154  }
155 
160  void PlayerIpChanged(string update)
161  {
162  PlayerIp = update;
163  }
164 
168  [SyncVar(hook = "SharesAnchorsChanged")]
169  public bool SharesSpatialAnchors;
170 
175  [Command]
176  private void CmdSetCanShareAnchors(bool canShareAnchors)
177  {
178  Debug.Log("CMDSetCanShare " + canShareAnchors);
179  SharesSpatialAnchors = canShareAnchors;
180  }
181 
186  void SharesAnchorsChanged(bool update)
187  {
188  SharesSpatialAnchors = update;
189  Debug.LogFormat("{0} {1} share", PlayerName, SharesSpatialAnchors ? "does" : "does not");
190  }
191 
195  private NetworkDiscoveryWithAnchors networkDiscovery;
196 
197  void Awake()
198  {
199  networkDiscovery = NetworkDiscoveryWithAnchors.Instance;
200  anchorManager = UNetAnchorManager.Instance;
201  }
202 
203  private void Start()
204  {
205  if (SharedCollection.Instance == null)
206  {
207  Debug.LogError("This script required a SharedCollection script attached to a GameObject in the scene");
208  Destroy(this);
209  return;
210  }
211 
212  if (isLocalPlayer)
213  {
214  // If we are the local player then we want to have airtaps
215  // sent to this object so that projectiles can be spawned.
216  InputManager.Instance.AddGlobalListener(gameObject);
217  InitializeLocalPlayer();
218  }
219  else
220  {
221  Debug.Log("remote player");
222  GetComponentInChildren<MeshRenderer>().material.color = Color.red;
223  AnchorEstablishedChanged(AnchorEstablished);
224  SharesAnchorsChanged(SharesSpatialAnchors);
225  }
226 
227  sharedWorldAnchorTransform = SharedCollection.Instance.gameObject.transform;
228  transform.SetParent(sharedWorldAnchorTransform);
229  }
230 
231  private void Update()
232  {
233  // If we aren't the local player, we just need to make sure that the position of this object is set properly
234  // so that we properly render their avatar in our world.
235  if (!isLocalPlayer && string.IsNullOrEmpty(PlayerName) == false)
236  {
237  transform.localPosition = Vector3.Lerp(transform.localPosition, localPosition, 0.3f);
238  transform.localRotation = localRotation;
239  return;
240  }
241 
242  if (!isLocalPlayer)
243  {
244  return;
245  }
246 
247  // if our anchor established state has changed, update everyone
248  if (AnchorEstablished != anchorManager.AnchorEstablished)
249  {
250  CmdSendAnchorEstablished(anchorManager.AnchorEstablished);
251  }
252 
253  // if our anchor isn't established, we shouldn't bother sending transforms.
254  if (AnchorEstablished == false)
255  {
256  return;
257  }
258 
259  // if we are the remote player then we need to update our worldPosition and then set our
260  // local (to the shared world anchor) position for other clients to update our position in their world.
261  transform.position = CameraCache.Main.transform.position;
262  transform.rotation = CameraCache.Main.transform.rotation;
263 
264  // For UNET we use a command to signal the host to update our local position
265  // and rotation
266  CmdTransform(transform.localPosition, transform.localRotation);
267  }
268 
272  private void InitializeLocalPlayer()
273  {
274  if (isLocalPlayer)
275  {
276  Debug.Log("Setting instance for local player ");
277  _Instance = this;
278  Debug.LogFormat("Set local player name {0} IP {1}", networkDiscovery.broadcastData, networkDiscovery.LocalIp);
279  CmdSetPlayerName(networkDiscovery.broadcastData);
280  CmdSetPlayerIp(networkDiscovery.LocalIp);
281 #if UNITY_WSA
282 #if UNITY_2017_2_OR_NEWER
283  CanShareAnchors = !UnityEngine.XR.WSA.HolographicSettings.IsDisplayOpaque;
284 #else
285  CanShareAnchors = !Application.isEditor && UnityEngine.VR.VRDevice.isPresent;
286 #endif
287 #endif
288  Debug.LogFormat("local player {0} share anchors ", (CanShareAnchors ? "does" : "does not"));
289  CmdSetCanShareAnchors(CanShareAnchors);
290  }
291  }
292 
293  private void OnDestroy()
294  {
295  if (isLocalPlayer)
296  {
297  InputManager.Instance.RemoveGlobalListener(gameObject);
298  }
299  }
300 
305  public override void OnStartLocalPlayer()
306  {
307  GetComponentInChildren<MeshRenderer>().material.color = Color.blue;
308  }
309 
315  [Command]
316  void CmdFire()
317  {
318  Vector3 bulletDir = transform.forward;
319  Vector3 bulletPos = transform.position + bulletDir * 1.5f;
320 
321  // The bullet needs to be transformed relative to the shared anchor.
322  GameObject nextBullet = (GameObject)Instantiate(bullet, sharedWorldAnchorTransform.InverseTransformPoint(bulletPos), Quaternion.Euler(bulletDir));
323  nextBullet.GetComponentInChildren<Rigidbody>().velocity = bulletDir * 1.0f;
324  NetworkServer.Spawn(nextBullet);
325 
326  // Clean up the bullet in 8 seconds.
327  Destroy(nextBullet, 8.0f);
328  }
329 
330  public void OnInputClicked(InputClickedEventData eventData)
331  {
332  if (isLocalPlayer)
333  {
334  CmdFire();
335  }
336  }
337 
338  [Command]
339  private void CmdSendSharedTransform(GameObject target, Vector3 pos, Quaternion rot)
340  {
341  UNetSharedHologram ush = target.GetComponent<UNetSharedHologram>();
342  ush.CmdTransform(pos, rot);
343  }
344 
351  public void SendSharedTransform(GameObject target, Vector3 pos, Quaternion rot)
352  {
353  if (isLocalPlayer)
354  {
355  CmdSendSharedTransform(target, pos, rot);
356  }
357  }
358  }
359 }
This script exists as a stub to allow other scripts to find the shared world anchor transform...
Input Manager is responsible for managing input sources and dispatching relevant events to the approp...
Definition: InputManager.cs:19
Controls player behavior (local and remote).
void CmdTransform(Vector3 postion, Quaternion rotation)
Sets the localPosition and localRotation on clients.
void SendSharedTransform(GameObject target, Vector3 pos, Quaternion rot)
For sending transforms for holograms which do not frequently change.
Inherits from UNet&#39;s NetworkDiscovery script. Adds automatic anchor management on discovery...
bool AnchorEstablished
Tracks if we have a shared anchor established
Creates, exports, and imports anchors as required.
override void OnStartLocalPlayer()
Called when the local player starts. In general the side effect should not be noticed as the players&#39;...
Interface to implement to react to simple click input.
void OnInputClicked(InputClickedEventData eventData)
The purpose of this class is to provide a cached reference to the main camera. Calling Camera...
Definition: CameraCache.cs:12
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
GameObject bullet
The game object that represents the &#39;bullet&#39; for this player. Must exist in the spawnable prefabs on ...
static Camera Main
Returns a cached reference to the main camera and uses Camera.main if it hasn&#39;t been cached yet...
Definition: CameraCache.cs:20
bool SharesSpatialAnchors
Tracks if the player can share spatial anchors
Describes an input event that involves a tap.
void CmdTransform(Vector3 postion, Quaternion rotation)
Sets the localPosition and localRotation on clients.