Skip to content

Instantly share code, notes, and snippets.

@TakahiroMiyaura
Last active October 11, 2018 03:02
Show Gist options
  • Save TakahiroMiyaura/50b02f60a60211daec7a04510d076467 to your computer and use it in GitHub Desktop.
Save TakahiroMiyaura/50b02f60a60211daec7a04510d076467 to your computer and use it in GitHub Desktop.
Mixed Reality Toolkit のUNETサンプルをベースにマルチプレーヤーな撃ちゲーを作ってみる ~ vuforia で位置合わせ編 ~ ref: https://qiita.com/miyaura/items/11f94c73a870b1913cfa
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
#if !UNITY_EDITOR && UNITY_WSA
using Windows.Networking;
using Windows.Networking.Connectivity;
#endif
namespace HoloToolkit.Unity.SharingWithUNET
{
/// <summary>
/// Inherits from UNet's NetworkDiscovery script.
/// Adds automatic anchor management on discovery.
/// If the script detects that it should be the server then
/// the script starts the anchor creation and export process.
/// If the script detects that it should be a client then the
/// script kicks off the anchor ingestion process.
/// </summary>
public class NetworkDiscoveryWithAnchors : NetworkDiscovery
{
/// <summary>
/// Enables the Singleton pattern for this script.
/// </summary>
private static NetworkDiscoveryWithAnchors _Instance;
public static NetworkDiscoveryWithAnchors Instance
{
get
{
NetworkDiscoveryWithAnchors[] objects = FindObjectsOfType<NetworkDiscoveryWithAnchors>();
if (objects.Length != 1)
{
Debug.LogFormat("Expected exactly 1 {0} but found {1}", typeof(NetworkDiscoveryWithAnchors).ToString(), objects.Length);
}
else
{
_Instance = objects[0];
}
return _Instance;
}
}
/// <summary>
/// Class to track discovered session information.
/// </summary>
public class SessionInfo
{
public string SessionName;
public string SessionIp;
}
/// <summary>
/// Tracks if we are currently connected to a session.
/// </summary>
public bool Connected
{
get
{
// We are connected if we are the server or if we aren't running discovery
return (isServer || !running);
}
}
/// <summary>
/// Event raised when the list of sessions changes.
/// </summary>
public event EventHandler<EventArgs> SessionListChanged;
/// <summary>
/// Keeps track of current remote sessions.
/// </summary>
[HideInInspector]
public Dictionary<string, SessionInfo> remoteSessions = new Dictionary<string, SessionInfo>();
/// <summary>
/// Event raised when connected or disconnected.
/// </summary>
public event EventHandler<EventArgs> ConnectionStatusChanged;
/// <summary>
/// Controls how often a broadcast should be sent to clients
/// looking to join our session.
/// </summary>
public int BroadcastInterval = 1000;
/// <summary>
/// Keeps track of the IP address of the system that sent the
/// broadcast. We will use this IP address to connect and
/// download anchor data.
/// </summary>
public string ServerIp { get; private set; }
/// <summary>
/// Keeps track of the local IP address.
/// </summary>
public string LocalIp { get; set; }
/// <summary>
/// Sanity checks that our scene has everything we need to proceed.
/// </summary>
/// <returns>true if we have what we need, false otherwise.</returns>
private bool CheckComponents()
{
if (NetworkManager.singleton == null)
{
Debug.Log("Need a NetworkManager in the scene");
return false;
}
return true;
}
private void Awake()
{
#if !UNITY_EDITOR && UNITY_WSA
// Find our local IP
foreach (HostName hostName in NetworkInformation.GetHostNames())
{
if (hostName.DisplayName.Split(".".ToCharArray()).Length == 4)
{
Debug.Log("Local IP " + hostName.DisplayName);
LocalIp = hostName.DisplayName;
break;
}
}
#else
LocalIp = "editor" + UnityEngine.Random.Range(0, 999999).ToString(); ;
#endif
}
private void Start()
{
// Initializes NetworkDiscovery.
Initialize();
if (!CheckComponents())
{
Debug.Log("Invalid configuration detected. Network Discovery disabled.");
Destroy(this);
return;
}
broadcastInterval = BroadcastInterval;
// Add our computer name to the broadcast data for use in the session name.
broadcastData = GetLocalComputerName() + '\0';
// Start listening for broadcasts.
StartAsClient();
}
/// <summary>
/// Gets the local computer name if it can.
/// </summary>
/// <returns></returns>
private string GetLocalComputerName()
{
#if !UNITY_EDITOR && UNITY_WSA
foreach (HostName hostName in NetworkInformation.GetHostNames())
{
if (hostName.Type == HostNameType.DomainName)
{
Debug.Log("My name is " + hostName.DisplayName);
return hostName.DisplayName;
}
}
return "NotSureWhatMyNameIs";
#else
return System.Environment.ExpandEnvironmentVariables("%ComputerName%");
#endif
}
/// <summary>
/// If we haven't received a broadcast by the time this gets called
/// we will start broadcasting and start creating an anchor.
/// </summary>
private void MaybeInitAsServer()
{
StartCoroutine(InitAsServer());
}
private IEnumerator InitAsServer()
{
Debug.Log("Acting as host");
#if !UNITY_EDITOR && UNITY_WSA
NetworkManager.singleton.serverBindToIP = true;
NetworkManager.singleton.serverBindAddress = LocalIp;
#endif
// StopBroadcast will also 'StopListening'
StopBroadcast();
// Work-around when building to the HoloLens with "Compile with .NET Native tool chain".
// Need a frame of delay after StopBroadcast() otherwise clients won't connect.
yield return null;
// Starting as a 'host' makes us both a client and a server.
// There are nuances to this in UNet's sync system, so do make sure
// to test behavior of your networked objects on both a host and a client
// device.
NetworkManager.singleton.StartHost();
// Work-around when building to the HoloLens with "Compile with .NET Native tool chain".
// Need a frame of delay between StartHost() and StartAsServer() otherwise clients won't connect.
yield return null;
// Start broadcasting for other clients.
StartAsServer();
}
/// <summary>
/// Called by UnityEngine when a broadcast is received.
/// </summary>
/// <param name="fromAddress">When the broadcast came from</param>
/// <param name="data">The data in the broad cast. Not currently used, but could
/// be used for differentiating rooms or similar.</param>
public override void OnReceivedBroadcast(string fromAddress, string data)
{
ServerIp = fromAddress.Substring(fromAddress.LastIndexOf(':') + 1);
SessionInfo sessionInfo;
if (remoteSessions.TryGetValue(ServerIp, out sessionInfo) == false)
{
Debug.Log("new session: " + fromAddress);
Debug.Log(data);
remoteSessions.Add(ServerIp, new SessionInfo() { SessionIp = ServerIp, SessionName = data });
SignalSessionListEvent();
}
}
/// <summary>
/// Call to stop listening for sessions.
/// </summary>
public void StopListening()
{
StopBroadcast();
remoteSessions.Clear();
}
/// <summary>
/// Call to start listening for sessions.
/// </summary>
public void StartListening()
{
StopListening();
StartAsClient();
}
/// <summary>
/// Call to join a session
/// </summary>
/// <param name="session">Information about the session to join</param>
public void JoinSession(SessionInfo session)
{
StopListening();
// We have to parse the server IP to make the string friendly to the windows APIs.
ServerIp = session.SessionIp;
NetworkManager.singleton.networkAddress = ServerIp;
// And join the networked experience as a client.
NetworkManager.singleton.StartClient();
SignalConnectionStatusEvent();
}
/// <summary>
/// Call to create a session
/// </summary>
/// <param name="SessionName">The name of the session if a name can't be calculated</param>
public void StartHosting(string SessionName)
{
StopListening();
#if !UNITY_EDITOR && UNITY_WSA
NetworkManager.singleton.serverBindToIP = true;
NetworkManager.singleton.serverBindAddress = LocalIp;
#endif
// Starting as a 'host' makes us both a client and a server.
// There are nuances to this in UNet's sync system, so do make sure
// to test behavior of your networked objects on both a host and a client
// device.
NetworkManager.singleton.StartHost();
// Start broadcasting for other clients.
StartAsServer();
SignalSessionListEvent();
SignalConnectionStatusEvent();
}
/// <summary>
/// Called when sessions have been added or removed
/// </summary>
void SignalSessionListEvent()
{
EventHandler<EventArgs> sessionListChanged = SessionListChanged;
if (sessionListChanged != null)
{
sessionListChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Called when we have joined or left a session.
/// </summary>
void SignalConnectionStatusEvent()
{
EventHandler<EventArgs> connectionEvent = this.ConnectionStatusChanged;
if (connectionEvent != null)
{
connectionEvent(this, EventArgs.Empty);
}
}
}
}
[Command]
void CmdFire()
{
Vector3 bulletDir = transform.forward;
Vector3 bulletPos = transform.position + bulletDir * 1.5f;
// The bullet needs to be transformed relative to the shared anchor.
GameObject nextBullet = (GameObject)Instantiate(bullet);
nextBullet.transform.position= sharedWorldAnchorTransform.InverseTransformPoint(bulletPos);
// アンカー配下のカメラの正面方向に弾を向ける
nextBullet.transform.rotation = Quaternion.FromToRotation(nextBullet.transform.forward,sharedWorldAnchorTransform.InverseTransformDirection(transform.forward));
nextBullet.GetComponentInChildren<Rigidbody>().velocity = nextBullet.transform.forward * 1.0f;
NetworkServer.Spawn(nextBullet);
// Clean up the bullet in 8 seconds.
Destroy(nextBullet, 8.0f);
}
private void Update()
{
sessionList = networkDiscovery.remoteSessions;
SessionIndex = Mathf.Min(SessionIndex, sessionList.Count);
// this will force a recalculation of the buttons.
ScrollSessions(SessionIndex);
}
// Copyright(c) 2018 Takahiro Miyaura
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
using HoloToolkit.Unity;
using HoloToolkit.Unity.InputModule;
using UnityEngine;
using Vuforia;
public class SetWorldAnchor : MonoBehaviour, IInputClickHandler
{
public VuforiaBehaviour Behaviour;
public GameObject HologramCollectionObject;
public GameObject UIContainer;
public void OnInputClicked(InputClickedEventData eventData)
{
//オブジェクトの有効化
UIContainer.SetActive(true);
//Vuforiaの機能を無効化
Behaviour.enabled = false;
//ARマーカの座標系の情報を取得
var markerRotation = transform.rotation.eulerAngles;
var markerPosition = transform.position;
// 基準点の座標系としてマーカーの認識地点に設定する
HologramCollectionObject.transform.position = markerPosition;
HologramCollectionObject.transform.Rotate(new Vector3(0f, markerRotation.y, 0f));
// 基準点を有効化する
HologramCollectionObject.SetActive(true);
// アンカーを設置する。
WorldAnchorManager.Instance.AttachAnchor(HologramCollectionObject, "HologramCollection");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment