結論
ExWebSocketBehaviorから直接GameObjectをいじらずに、いったんテキストでメインclassに転送してからvoid Update()で動かせばよろしい。
背景
unityでネットワークを使うのにwebsocket-sharpとかいうのがあるらしい。
単にwebsocketを使うだけならググればたくさん出てくるのでそちらに任せるとして。(例↓)
みょんなことから友人にWebsocket-sharp.dll(ビルド済み)をもらったので、これで遊ぼう。
スマホのジャイロをパソコンに送って、パソコン上の何かGameObjectを動かせたら楽しそうだと思ったのだ。
過ち
perplexityにサンプルを書かせてテキトウに編集して、次のように構想した。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;
using WebSocketSharp.Server;
using System;
public class websocketManager : MonoBehaviour
{
//websocket受信時に動かしたい何かしらのGameObject
public GameObject[] myGameObject;
WebSocketServer ws;
// Start is called before the first frame update
void Start()
{
//ポート番号を指定
ws = new WebSocketServer(12345);
//クライアントからの通信時の挙動を定義したクラス、「ExWebSocketBehavior」を登録
ws.AddWebSocketService<ExWebSocketBehavior>("/");
//サーバ起動
ws.Start();
}
private void OnApplicationQuit()
{
Debug.Log("サーバ停止");
ws.Stop();
}
// Update is called once per frame
void Update()
{//何も書いていない
}
public class ExWebSocketBehavior : WebSocketBehavior
{
//誰かがメッセージを送信してきたときに呼ばれるメソッド
protected override void OnMessage(MessageEventArgs e)
{
string str = e.Data;
Debug.Log("受信データ: " + str); // ここで文字列や数値を受信
//ここでmyGameObjectの処理をしたい。
//↓これが動かない(今はテキトウに(1,2,3)とかしてるけど文字列をparseするとかを予定)
myGameObject[0].transform.localPosition = new Vector3(1, 2, 3);
}
}
}
エラーが出た。
'websocketManager.myGameObject' で、オブジェクト参照が必要です
よく考えてみればそれもそうか。myGameObject
は上位(websocketManager)のclass内変数なわけで、下位(ExWebSocketBehavior)のclassから参照も編集もできるわけないよな。
よっし、じゃあパプる(perplexityに相談する)ぞ。
メインのclassの先頭で
//websocketなclassからも参照できるようにするコード
public static websocketManager Instance;
void Awake()
{
Instance = this;
}
をしてから、ExWebSocketBehavior
の中で
websocketManager.Instance.myGameObjects[0]
といった感じでアクセスできるようになるらしい。確かにエラーも何も出ていないが…
でもplayしてみても何も動かない。うーん?
原因
UnityではGameObjectの操作はメインスレッドでしか実行できないらしい。ExWebSocketBehaviorのようなメインでないところからは直接GameObjectをいじれない模様。
解決
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;
using WebSocketSharp.Server;
using System;
public class websocketManager : MonoBehaviour
{
+ public static websocketManager Instance;
+ void Awake()
+ {
+ Instance = this;
+ }
//websocket受信時に動かしたい何かしらのGameObject
public GameObject[] myGameObject;
+ //websocketで受信したテキストをそのまま格納するリスト
+ List<string> strlist = new List<string>();
WebSocketServer ws;
// Start is called before the first frame update
void Start()
{
//ポート番号を指定
ws = new WebSocketServer(12345);
//クライアントからの通信時の挙動を定義したクラス、「ExWebSocketBehavior」を登録
ws.AddWebSocketService<ExWebSocketBehavior>("/");
//サーバ起動
ws.Start();
}
private void OnApplicationQuit()
{
Debug.Log("サーバ停止");
ws.Stop();
}
// Update is called once per frame
void Update()
{
+ if (strlist.Count > 0)
+ {
+ string str = strlist[0];
+ strlist.RemoveAt(0);
+ //ここで受信した文字列を処理する
+ //処理結果をイイカンジに反映させる
+ myGameObject[0].transform.localPosition = new Vector3(1, 2, 3);
+ }
}
public class ExWebSocketBehavior : WebSocketBehavior
{
//誰かがメッセージを送信してきたときに呼ばれるメソッド
protected override void OnMessage(MessageEventArgs e)
{
string str = e.Data;
Debug.Log("受信データ: " + str); // ここで文字列や数値を受信
- //ここでmyGameObjectの処理をしたい。
- //↓これが動かない(今はテキトウに(1,2,3)とかしてるけど文字列をparseするとかを予定)
- myGameObject[0].transform.localPosition = new Vector3(1, 2, 3);
+ //ここでは何も処理せず、ただメインに受信した文字列を投げる
+ websocketManager.Instance.strlist.Add(str);
}
}
}