2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Websocketで、異空間通信。その2

Last updated at Posted at 2024-02-21

概要

メタバースを使った、自動運転シュミレーターを提供します。

方針を転換する。

今まで、neosvrの世界でセンサーを作り、その情報を外に出して、エージェントが環境として読み込み自己判断させようとしていたが、

これからは、エージェントも環境も外で作り、表示のみneosvrで表示する。

上記に従い以下を実験する。

エージェント(ローバー)が環境で、自動運転するシュミレータを作り、結果をwebsocketに出力、neosvrで受け取り、BOXを移動させる。
websocketサーバーは、elixirで準備します。
設定は、ローバーが、8の字運転を続けるシュミレーターです。
各ポイントは、以下です。
var point1 = {
'x': 260,
'y': 148
};
var point2 = {
'x': 278,
'y': 169
};
var point4 = {
'x': 161,
'y': 278
};
var point3 = {
'x': 141,
'y': 257
};
ローバーは、ステートマシンを持っていて、ポイントをクリアすれば、次のポイントに向かいます。
ローバーは、getDistanceとgetDegreeでポイントまでの距離と方角を得て、自分で判断します。
環境は、60fpsで更新し、ローバーを移動し、位置を更新します。
ローバーは、位置を受け取り、方向を出力します。
さらに、ローバーの位置情報をwebsocketで、垂れ流しします。
neosvrは、ローバーの位置情報をwebsocketで受け取り、BOXを移動させます。

手順

websocketサーバーの準備

いつものやつです、省略。

エージェントと環境の準備

Plunkerに設置。
image.png

サンプルコード



function getDistance(x, y, x2, y2) {
  var distance = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
  return distance;
}
function getDegree(x, y, x2, y2) {
  var radian = Math.atan2(y - y2, x - x2);
  var degree = radian * 180 / Math.PI + 180;
  return degree;
}
function draw() {
  ctx.save();
  ctx.translate(point1.x, point1.y);
  ctx.fillStyle = "red";
  ctx.fillRect(-5, -5, 5, 5);
  ctx.restore();
  ctx.save();
  ctx.translate(point2.x, point2.y);
  ctx.fillStyle = "red";
  ctx.fillRect(-5, -5, 5, 5);
  ctx.restore();
  ctx.save();
  ctx.translate(point3.x, point3.y);
  ctx.fillStyle = "red";
  ctx.fillRect(-5, -5, 5, 5);
  ctx.restore();
  ctx.save();
  ctx.translate(point4.x, point4.y);
  ctx.fillStyle = "red";
  ctx.fillRect(-5, -5, 5, 5);
  ctx.restore();
  ctx.save();
  ctx.translate(car.x, car.y);
  ctx.fillStyle = "maroon";
  ctx.fillRect(-3, -3, 3, 3);       
  ctx.restore();
}
var koko;
var canvas;
var ctx;
var state = 2;
var r = 0;
var car = {
  'px': 0,
  'py': 0,
  'x': 210,
  'y': 210,
  'r': 0
};
var point1 = {
  'x': 260,
  'y': 148
};
var point2 = {
  'x': 278,
  'y': 169
};
var point4 = {
  'x': 161,
  'y': 278
};
var point3 = {
  'x': 141,
  'y': 257
};
function hand(p) {
  var d = getDistance(car.x, car.y, p.x, p.y);
  if (d < 5) 
  {
    return;
  } 
  var f = getDegree(car.x, car.y, p.x, p.y);
  var e = getDegree(car.px, car.py, car.x, car.y);
  var s = Math.abs(f - e);
  if (s < 5) 
  {
    return;
  }  
  if (s < 180)
  {
    if (e < f)
    {
      r = 10;
    }
    if (e > f)
    {
      r = -10;
    }
  }
  else
  {
    if (e < f)
    {
      r = -10;
    }
    if (e > f)
    {
      r = 10;
    }
  }
}
function send() {
  var mes = "[";
  mes += car.x / 30;
  mes += "; 0.5; ";
  mes += car.y / 30;
  mes += "]";
  koko.value = mes;
  socket.send(mes);
}
function loop2() {
  var dis;
  car.px = car.x;
  car.py = car.y;
	car.r += r * Math.PI / 180;
	car.x += Math.cos(car.r) * 0.3;
	car.y += Math.sin(car.r) * 0.3;
  switch (state)
  {
  case 0:        
    dis = getDistance(point4.x, point4.y, car.x, car.y);
    if (dis < 5)
    {
      state = 1;
      break;
    }
    hand(point4);
  break;
  case 1:
    dis = getDistance(point3.x, point3.y, car.x, car.y);
    if (dis < 5)
    {
      state = 2;
      break;
    }
    hand(point3);
  break;
  case 2:
    dis = getDistance(point2.x, point2.y, car.x, car.y);
    if (dis < 5)
    {
      state = 3;
      break;
    }
    hand(point2);
  break;
  case 3:        
    dis = getDistance(point1.x, point1.y, car.x, car.y);
    if (dis < 5)
    {
      state = 0;
      break;
    }
    hand(point1);
  break;         
  }
}

canvas = document.getElementById('canvas');
koko = document.getElementById('koko');
canvas.width = canvas.height = 300;
ctx = canvas.getContext('2d');
function loop() {
	draw();
  loop2();
  send();
  requestAnimationFrame(loop);
}

let url = "ws://localhost:50002/";
let socket = new WebSocket(url);
socket.onmessage = function(event) {
  //alert(event.data);
};
socket.onclose = event => alert(`Closed`);
socket.onopen = function(event) {
  alert('open');
  loop();
};
socket.onerror = event => alert(`err`);





成果物

メタバースの準備

2024-02-20 21.14.33.jpg

手順
DevToolTipを装着
新規作成>3Dモデル>Boxをクリック
Transform->Interaction->TouchButtonを追加
追加コンポーネント->network->WebsocketClient
logixtooltipを装着
TouchButtonのインターフェースを取り出す 右ドラッグしてRキー
WebsocketClientのインターフェースを取り出す
boxのスロットルを取り出す インスペクタ左上の「●Box」の文字部分を右ドラッグしてRキー
ノードブラウザを表示
Interaction>ButtonEventsをスポーン
network->websocket->WebsocketConnectをスポーン
network->websocket->WebsocketTextMessageReceiverをスポーン
Users>HostUserをスポーン
actions->writeをスポーン
variables->stringをスポーン
Operation>Parse>ParserFloat3をスポーン
下の様に、俺コードでつなぐ。

{w0, _, _, _, _, _, _, _, _, _} = ButtonEvents [Obj.Box.TouchButton]
{} = WebsocketConnect [w0, FrooxEngine.WebSocketClient, "ws://localhost:50002/", HostUser]
{w2, w3} = WebsocketTextMessageReceiver [w0, FrooxEngine.WebSocketClient]
{w4} = Write [w2, w3]
{w5} = String [w4]
{w6} = ParserFloat3 [w5]
{} = Obj.Box.Slot.Position [w6]

起動

websocketサーバーを起動
クライアントを起動
neosvrを起動

動作確認

メタバース上のBOXが動けば、成功です。

以上。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?