vr多人_如何構建多人VR網絡應用

vr多人

by Srushtika Neelakantam

通過Srushtika Neelakantam

如何構建多人VR網絡應用 (How to build a multiplayer VR web app)

In this article, we’ll learn about three great frameworks/libraries that allow any web developer to build a VR app that works on any device in minutes. It will also allow networked realtime interaction by peers from all over the world.

在本文中,我們將學習三個偉大的框架/庫,這些框架/庫可讓任何Web開發人員在幾分鐘內構建可在任何設備上運行的VR應用程序。 它還將允許來自世界各地的同行進行網絡實時交互。

Virtual reality (VR) has come to an amazing level where it does not need any introduction. However, from a developer’s perspective, building simple VR apps still seems to be a complex task, let alone networked multiplayer ones.

虛擬現實(VR)達到了驚人的水平,不需要任何介紹。 但是,從開發人員的角度來看,構建簡單的VR應用程序似乎仍然是一項復雜的任務,更不用說聯網的多人游戲了。

我們將建造什么? (What will we build?)

By the end of this tutorial, you will have a VR app similar to the one seen in the above picture. It will have a basic VR scene where multiple users can connect to your app from their mobile phones by simply hitting a URL on their mobile phone’s browsers.

在本教程結束時,您將擁有一個類似于上圖所示的VR應用程序。 它將具有一個基本的VR場景,多個用戶只需在其手機瀏覽器中點擊一個URL,即可從其手機連接到您的應用程序。

Don’t know or understand a lot of the terms I just used? Don’t worry, we’ll have a look at all of it shortly, and it will all start to make sense soon!

不知道或不了解我剛剛使用的許多術語? 不用擔心,我們很快就會看到所有內容,并且很快就會變得有意義!

Basically, for every user who joins your application, a new avatar will appear in your VR scene (Note: I’m just using a fancy term ‘avatar’ for that set of boxes which barely resembles a real human :P ). These avatars will rotate/move in realtime, according to the movement of users’ phones in real life.

基本上,對于每個加入您的應用程序的用戶,都會在您的VR場景中出現一個新的化身(注意:我只是對那些與真實人類:P相似的盒子使用了一個花哨的術語“化身”)。 這些化身將根據現實生活中用戶電話的移動情況實時旋轉/移動。

This app was demo-ed during my talk at WeAreDevelopers World Congress 2018. You can check out the slides below.

在我在WeAreDevelopers World Congress 2018上的演講中,該應用程序進行了演示。您可以查看下面的幻燈片。

跳到現場演示 (Skip to live demo)

The complete project is hosted on Glitch — I think it’s the easiest way to host your community projects or demos. It also allows multiple developers to collaborate on a project remotely. You should totally check it out.

完整的項目托管在Glitch上 -我認為這是托管社區項目或演示的最簡單方法。 它還允許多個開發人員在一個項目上進行遠程協作。 您應該完全檢查一下。

Instructions for the live demo:

現場演示說明:

  • open up the link in a browser window on your computer/mobile.

    在您的計算機/移動設備上的瀏覽器窗口中打開鏈接。
  • open up another instance of the application in another browser window/mobile.

    在另一個瀏覽器窗口/移動設備中打開該應用程序的另一個實例。

You can see the avatar of each of these instances in the other. Try moving the mobile phone in the air and you’ll see that the corresponding avatar seen on the computer browser moves as well. If you have two VR headsets (even cardboards are fine), you and a friend can put them on and see each other’s avatars move in the scene as you are moving your head in real life.

您可以在另一個實例中看到每個實例的頭像。 嘗試在空中移動手機,您會發現在計算機瀏覽器中看到的相應虛擬形象也在移動。 如果您有兩個VR耳機(即使是硬紙板也可以),您和朋友可以戴上它們,并在現實中搖頭時看到彼此的頭像在場景中移動。

Play around a bit or read on further to understand what’s happening and how. You can also check out the complete code, hosted on GitHub. Make sure to read the readme file:

試一試或進一步閱讀以了解發生了什么以及如何發生。 您還可以檢出托管在GitHub上的完整代碼。 確保閱讀自述文件:

Jump to the complete source code on GitHub.

跳轉到GitHub上的完整源代碼 。

我們將使用什么? (What will we use?)

As mentioned before, our aim is to access VR directly in the browsers, without having to download anything. We shall use the WebVR library in order to achieve this.

如前所述,我們的目標是無需下載任何內容即可直接在瀏覽器中訪問VR。 我們將使用WebVR庫來實現此目的。

WebVR is a web framework that allows us to build VR applications which are accessible directly on the web. This completely eliminates heavy downloads and installs, as well as making the VR app device-independent.

WebVR是一個Web框架,允許我們構建可直接在Web上訪問的VR應用程序。 這完全消除了繁重的下載和安裝,并使VR應用程序與設備無關。

However, even though WebVR gives us the ability to leverage the many advantages of the web, it still requires a considerable amount of complex work. This may, in fact, require knowledge of WebGL and other libraries to be able to build a smooth experience.

但是,即使WebVR使我們能夠利用Web的許多優點,它仍然需要大量復雜的工作。 實際上,這可能需要WebGL和其他庫的知識才能建立流暢的體驗。

一個框架 (A-Frame)

This, again, tends to be a bottleneck for the developers of the web to build something that will be eventually served on the web itself. And so, Mozilla’s VR team built a framework on top of WebVR called A-Frame.

同樣,這往往是Web開發人員構建最終將在Web本身上提供服務的瓶頸。 因此,Mozilla的VR團隊在WebVR的基礎上建立了一個稱為A-Frame的框架 。

A-Frame completely eliminates WebVR’s boilerplate code and allows developers to build VR apps with simple HTML custom tags. With, of course, JavaScript making various bits and piece work together, as always.

A-Frame完全消除了WebVR的樣板代碼,并允許開發人員使用簡單HTML自定義標簽構建VR應用程序。 當然,使用JavaScript可以像往常一樣使各個部分零碎協作。

阿比 (Ably)

Further, we’ll use Ably Realtime to implement all the realtime —and multiplayer — functionality in the application. Ably is a realtime data delivery platform that solves the realtime message delivery problem by offering features like Pub/Sub and Presence out of the box.

此外,我們將使用Ably Realtime在應用程序中實現所有實時(和多人游戲)功能。 Ably是一個實時數據傳遞平臺,通過提供開箱即用的Pub / Sub和Presence之類的功能解決了實時消息傳遞問題。

Note: The limits for an Ably free account (that is used in the Live Demo) allow you to have a maximum of two instances of the app running at any time. If you wish to have more instances running, have a look at the Ably self-service package and buy more messages accordingly.

注意 :通過Ably免費帳戶(在Live Demo中使用)的限制,您可以隨時最多運行兩個應用程序實例。 如果希望運行更多實例,請查看Ably 自助服務包并相應購買更多消息。

毛刺 (Glitch)

As you know by now, every WebVR application can be accessed from just a browser. This means we’ll need to host our files in order to be able to access them on a mobile device using a URL.

眾所周知,每個WebVR應用程序都可以通過瀏覽器進行訪問。 這意味著我們將需要托管文件,以便能夠使用URL在移動設備上訪問它們。

Glitch is a very convenient way of doing this. You can simply create a new project. When you are done, a URL is readily available for use on any platform or device instantly.

小故障是一種非常方便的方法。 您可以簡單地創建一個新項目。 完成后,隨時可以在任何平臺或設備上使用URL。

身份驗證和分配唯一ID (Authentication and assigning unique ids)

First things first. We’ll need to setup an auth server that verifies our users’ credentials and authenticates them with Ably, while also assigning a random clientId to each of those. This clientId will serve as a way to identify each of these avatars separately, and handle information such as their respective position updates, and appearance/disappearance as per user login/logout. We’ll set up a simple express server for this, as shown below:

首先是第一件事。 我們需要設置一個身份驗證服務器,以驗證用戶的憑據并通過Ably對其進行身份驗證,同時還要為每個用戶分配一個隨機的clientId 。 此clientId將用作分別識別這些化身中的每個化身的方式,并根據用戶登錄/注銷來處理諸如它們各自的位置更新以及外觀/消失之類的信息。 我們將為此設置一個簡單的快遞服務器 ,如下所示:

If you observe closely, this express server serves the files present in the root directory of the project. So make sure the “index.html” file that you build further on is in the same folder as the “auth-server”.

如果仔細觀察,此Express服務器將提供項目根目錄中存在的文件。 因此,請確保您進一步構建的“ index.html”文件與“ auth-server”位于同一文件夾中。

If you wish to serve these files locally, rather than on Glitch, replace the code for the listener variable with the following:

如果希望在本地而不是在Glitch上提供這些文件,請使用以下代碼替換listener變量的代碼:

Since this is only a tutorial, we are not actually checking any credentials before authenticating the clients. Ideally, the auth server would have a validation step.

由于這只是一個教程,因此我們在驗證客戶端之前實際上并沒有檢查任何憑據。 理想情況下,身份驗證服務器將具有驗證步驟。

The project structure is simple, with the following files all in the same parent folder:

項目結構很簡單,以下文件均位于同一父文件夾中:

  • auth_server.js

    auth_server.js
  • index.html

    index.html
  • main.js

    main.js

入門 (Getting started)

Let’s start by building the basic VR setup for the application. We’ll use A-Frame’s entity-component-system (ECS). ECS makes it easy to build any objects in the scene. Every object is treated as an entity which differs from other entities by the various components (or attributes) that are attached to it.

讓我們開始為應用程序構建基本的VR設置。 我們將使用A-Frame的實體組件系統 (ECS)。 通過ECS,可以輕松構建場景中的任何對象。 每個對象都被視為一個實體,該實體與其他實體的不同之處在于附加的各種組件(或屬性)。

In your HTML file, start off by adding the HTML skeleton code:

在您HTML文件中,首先添加HTML框架代碼:

The references refer to the following, respectively:

這些引用分別引用以下內容:

  1. Ably’s JS client library

    Ably的JS 客戶端庫

  2. JQuery Framework

    jQuery 框架

  3. A-Frame’s JS build

    A-Frame的JS版本

  4. A local JS file (“main.js”) where we’ll add the logic of the app

    本地JS文件(“ main.js”),我們將在其中添加應用程序的邏輯
  5. A-frame’s community contributed text component to conveniently add stylised text to our VR scene.

    A-frame的社區貢獻了文本組件,可將樣式化文本方便地添加到我們的VR場景中。

All the objects we wish to include in our VR scene must go within the a-scene tag in our HTML file, as scene above (pun intended)! This is analogous to the body tag in regular HTML documents.

我們希望包含在VR場景中的所有對象都必須放在HTML文件的a-scene標記內,如上面的場景所示(雙關語意)! 這類似于常規HTML文檔中的body標簽。

Next, we will add all the assets we wish to use within the a-assets tag. Adding all the resources under this tag makes sure that all your assets are pre-loaded before your app shows up. This prevents a crappy first look due to slow loading of part of the resources.

接下來,我們將希望使用的所有資產添加到a-assets標簽中。 在此標簽下添加所有資源,可確保在您的應用顯示之前預加載所有資產。 這樣可以防止由于部分資源加載緩慢而造成的糟糕外觀。

Feel free to use your own resources to give the app a customised feel! You can see that we have added two new tags in the above code snippet, let’s dig into them:

隨意使用您自己的資源給應用程序定制的感覺! 您可以看到我們在上面的代碼片段中添加了兩個新標簽,讓我們對其進行深入研究:

a-asset-item — invokes the three.js file loaders. You can use this to load all file types.

a-asset-item item-調用three.js文件加載器。 您可以使用它來加載所有文件類型。

a-mixin — is a very useful tag that allows code reuse by letting you specify a set of properties (components) to be applied to a single entity. You can give it an id and reference it multiple times as we’ll see. We will have three mixins, each specifying certain attributes for the avatar that we intend to create — the eyes, pupils, and arms.

a-mixin —是一個非常有用的標記,它允許您指定要應用于單個實體的一組屬性(組件),從而允許代碼重用。 您可以為其指定一個id并多次引用它,我們將看到。 我們將有三個混合器,每個混合器指定我們要創建的化身的某些屬性-眼睛,瞳Kong和手臂。

Now, let’s add all the static visual elements in our VR scene.

現在,讓我們在VR場景中添加所有靜態視覺元素。

As you can see, we have implemented the complete app using ECS. However, this is not the only way that you can add objects to the scene. A-Frame comes with a few custom entities such as box, sphere, and so on. These custom entities are called primitives.

如您所見,我們已經使用ECS實施了完整的應用程序。 但是,這不是將對象添加到場景的唯一方法。 A-Frame帶有一些自定義實體,例如框,球等。 這些自定義實體稱為基本體 。

The code contains very easy to follow comments that explain what each of the entity-component sets is trying to implement in our app.

該代碼包含非常易于遵循的注釋,這些注釋解釋了每個實體組件集試圖在我們的應用程序中實現的內容。

For VR newbies, here’s something interesting — a sky is like a layer that covers your 360 deg sphere inside which you assume yourself to be standing while experiencing a VR app. It is generally analogous to the sky in real-life which can be seen on the top and appears to drop down near the horizon. We use a-sky in A-Frame to add a sky and the resource to be used can be either a 360 deg image or just a solid colour.

對于VR新手來說, 這很有趣 -天空就像一層覆蓋360度球面的圖層,您會在其中體驗VR應用程序時保持站立。 它通常類似于現實生活中的天空,可以在頂部看到它,并且似乎在地平線附近掉落。 我們在A框架中使用a-sky來添加天空,并且要使用的資源可以是360度圖像或純色。

Now comes another interesting part. We require a camera entity. This is a special entity offered by A-Frame. It grabs the continuously changing position as well as rotation values of your mobile phone while you are using an A-Frame powered VR app in the browser. The entity takes advantage of the various gyro sensors in your phone to achieve this under-the-hood. In a computer, the camera entity follows the WASD controls to capture the position and rotation.

現在是另一個有趣的部分。 我們需要一個相機實體。 這是A-Frame提供的特殊實體。 當您在瀏覽器中使用由A-Frame驅動的VR應用程序時,它可以捕獲手機不斷變化的位置以及旋轉值。 該實體利用您手機中的各種陀螺儀傳感器來實現這一目標。 在計算機中,攝像頭實體遵循WASD控件來捕獲位置和旋轉。

Here’s how we can add a camera entity. We can optionally give it a shape and animation, which helps us track its movement by serving as a cursor.

這是我們添加相機實體的方法。 我們可以選擇給它一個形狀和動畫,這可以幫助我們通過充當光標來跟蹤它的運動。

By the end of this section, your VR app should ideally look like what’s shown below. But only if you haven’t switched the resources with your custom ones, of course!

到本節結束時,理想情況下,您的VR應用程序應如下圖所示。 但是,當然,只有在您沒有用自定義資源切換資源的情況下!

Voilà! We just finished setting up the basic VR scene.

瞧! 我們剛剛完成了基本VR場景的設置。

It’s now time to add some functionality to it — to make the avatars appear, disappear, and move around in realtime as the users log in and out of your application, or simply move their phone around.

現在是時候向其中添加一些功能了-使化身在用戶登錄和注銷應用程序時實時顯示,消失和移動,或者只是移動電話。

添加實時功能 (Adding realtime functionality)

It’s time to spin up some magic into our VR scene. Using Ably, it is very easy to implement this. We’ll use Pub/Sub and Presence, which are both offered as direct use out-of-the-box features by Ably.

現在是時候為我們的VR場景注入一些魔力了。 使用Ably,很容易實現。 我們將使用Pub / Sub和Presence ,它們都是Ably直接提供的即用型功能。

Start by connecting your client/user to Ably. Since we are using Token Authentication, we’ll simply add a route to the auth server, as shown below:

首先將您的客戶端/用戶連接到Ably。 由于我們使用的是Token Authentication ,我們將簡單地添加一條到auth服務器的路由,如下所示:

Note: we have specified echoMessage: false. This prevents your client from being subscribed to messages published by itself, ensuring lower message count/usage on the whole app. By default, this option is always true.

注意 :我們已指定echoMessage: false 。 這樣可以防止您的客戶端訂閱自己發布的消息,從而確保整個應用程序中的消息數/使用量減少。 默認情況下,此選項始終為true。

After successfully authenticating the client, we’ll store the id returned by the auth server in a variable so we can use it later on.

成功驗證客戶端后,我們會將auth服務器返回的ID存儲在變量中,以便以后使用。

Next, let’s set up the first function that initialises our application. In this function, we set an initial position of the avatar. For simplicity, we’ll restrict the avatar’s rotation/movement to x-axis only, while keeping the coordinates on the other two planes as zero. The initial position on the x-axis is chosen randomly so that multiple avatars do not clutter at the same point in the scene as soon as they appear. We also set some initial attributes such as colour and dimensions.

接下來,讓我們設置第一個函數來初始化我們的應用程序。 在此功能中,我們設置化身的初始位置。 為簡單起見,我們將化身的旋轉/運動僅限制為x軸,同??時將其他兩個平面上的坐標保持為零。 x軸上的初始位置是隨機選擇的,以使多個化身一出現就不會在場景中的同一點處混亂。 我們還設置了一些初始屬性,例如顏色和尺寸。

In order to send this data to Ably, we need to create a channel. I’ve called it vr-channel. After that’s done, we can publish the initial attributes on this channel.

為了將此數據發送到Ably,我們需要創建一個通道。 我稱它為vr-channel 。 完成之后,我們可以在該通道上發布初始屬性。

However, we want to continuously publish this data so all the other users are able to receive it in realtime. In other words, we want to publish data as the position and rotation attributes are changing. This data is directly handed to us by the camera entity in A-Frame. We just need to publish this data on the same channel at a high frequency. In this case, I’m publishing at every 100ms.

但是,我們希望連續發布此數據,以便所有其他用戶都可以實時接收它。 換句話說,我們希望隨著位置和旋轉屬性的變化而發布數據。 這些數據是由A-Frame中的相機實體直接交給我們的。 我們只需要將這些數據高頻率發布在同一頻道上即可。 在這種情況下,我每100毫秒發布一次。

a-box is a primitive in A-Frame that can be conveniently used to create a 3D box with basic attributes such as dimensions, position, rotation, color, and so on.

a-box是A-Frame a-box的基元 ,可方便地用于創建具有基本屬性(例如尺寸,位置,旋轉,顏色等)的3D框。

You can see that there are three subfunctions within the above function that we have not yet discussed. Presence is a common term in the realtime world which gives you the information about a user/device’s online or connection status. In our case, we would:

您可以看到,我們尚未討論上述函數中的三個子函數。 在線狀態是實時世界中的常用術語,它為您提供有關用戶/設備的在線或連接狀態的信息。 就我們而言,我們將:

  • create and make the avatar appear in the scene only when a user comes online (hits the URL)

    僅當用戶在線時(點擊URL)創建并使頭像顯示在場景中
  • and, likewise, make it disappear as soon as a user quits the app (closes the browser window on their phone or browser).

    并且同樣,一旦用戶退出應用程序(關閉手機或瀏覽器上的瀏覽器窗口),使其消失。

Additionally, Ably allows you to subscribe to presence events. A callback is fired every time a new user logs in or an existing user logs out. This is exactly what we require for our app.

此外,Ably允許您訂閱狀態事件。 每當新用戶登錄或現有用戶注銷時,都會觸發回調。 這正是我們對應用程序的要求。

Using channel.presence.get() you can get a list of all the members currently connected to Ably (are online).

使用channel.presence.get() ,可以獲得當前已連接到Ably(在線)的所有成員的列表。

Using channel.presence.subscribe('enter') you can get notified whenever a user becomes connected to Ably (comes online).

使用channel.presence.subscribe('enter')您可以在用戶連接到Ably(聯機)時得到通知。

Using channel.presence.subscribe('leave') you can get notified whenever a user becomes disconnected from Ably (goes offline).

使用channel.presence.subscribe('leave')可以在用戶與Ably斷開連接(脫機)時得到通知。

As soon as a user comes online, we need to subscribe everyone else to the attribute changes of the new user’s avatar. These changes, as you can observe, will be in the attr object due to changing position and rotation. Our goal is to update the avatar as these attributes update.

用戶上線后,我們需要為其他所有人訂閱新用戶頭像的屬性更改。 如您所見,由于位置和旋轉的變化,這些變化將在attr對象中。 我們的目標是在這些屬性更新時更新頭像。

Before that, we need to ensure that the avatar exists at all, or if a new one needs to be created. We do this by using a simple map of avatars where we store the IDs of all the existing avatars, as shown:

在此之前,我們需要確保該頭像完全存在,或者是否需要創建一個新頭像。 我們通過使用一個簡單的頭像映射來實現此目的,其中存儲了所有現有頭像的ID,如下所示:

Next, we need to make all the users subscribe to changes in the attributes of everyone else, apart from themselves. We do so by making them subscribe to the specific event on the same channel to which it is being published, like so:

接下來,我們需要讓所有用戶都訂閱除他們之外的其他所有人的屬性更改。 為此,我們讓他們在發布該事件的同一頻道上訂閱該特定事件,如下所示:

When a new user enters, we need to create a new avatar with all the necessary attributes. The following function gets all the initial attributes over Ably. It creates a new avatar with these attributes, and attaches other parts like eyes, pupils, and arms relative to the position of the main box (representing the head of the avatar). This manual positioning becomes easier with the use of a visual inspector tool that comes with A-Frame.

當新用戶進入時,我們需要創建具有所有必要屬性的新頭像。 以下函數獲取Ably上的所有初始屬性。 它將使用這些屬性創建一個新的化身,并相對于主框(代表化身的頭部)的位置附加其他部分,例如眼睛,瞳Kong和手臂。 通過使用A-Frame附帶的視覺檢查器工具,可以更輕松地進行手動定位。

After we have built all the different parts of an avatar, we bind them all together by attaching them to a root avatar. This gives us a way to perform actions like position updates and so on on the avatar as a whole. You wouldn’t want a zombie-like situation with the head moving in one direction and eyes moving in the other, right? ;) This also makes it easy to delete the whole avatar when a user logs out.

在構建了化身的所有不同部分之后,我們通過將它們附加到根化身上將它們綁定在一起。 這為我們提供了一種在整個虛擬形象上執行諸如位置更新之類的動作的方法。 您不會想要像僵尸一樣的情況,頭部朝一個方向移動,而眼睛朝另一個方向移動,對嗎? ;)這也使用戶注銷時輕松刪除整個頭像。

If an avatar already exists, we simply update its position and rotation from the continually updating data in the attrobject of the respective users.

如果化身已經存在,我們只需根據相應用戶attr對象中不斷更新的數據來更新其位置和旋轉。

Scroll back up to the subscribeToAvatarChanges() function. You will observe that the updateAvatar() is a callback function to a channel subscription which is invoked when the attributes of an existing avatar change. This makes it very easy for us to continually update the actual avatar as well, according to the changing data. We simply update the position and rotation with new values, as shown below:

向上滾動到subscribeToAvatarChanges()函數。 您將觀察到updateAvatar()是通道訂閱的回調函數,當現有頭像的屬性發生更改時將調用該訂閱。 根據不斷變化的數據,這也使我們很容易不斷更新實際頭像。 我們只需用新值更新位置和旋轉,如下所示:

Finally, we need to ensure that the avatar is removed from the scene whenever a user logs out/ goes offline. This can be done using presence again, by handling the leave event mentioned earlier. Here are a few things you need to do when a user logs out:

最后,我們需要確保每當用戶注銷/離線時,將化身從場景中刪除。 通過處理前面提到的leave事件,可以再次使用狀態來完成此操作。 用戶注銷時,需要做以下幾件事:

We start by deleting the corresponding entry in our array and follow it by deleting the complete avatar from the scene.

我們首先刪除數組中的相應條目,然后從場景中刪除完整的頭像。

而已! (That’s it!)

We have now successfully implemented a Multiplayer VR app that runs on the web and works in realtime. Go ahead and test it out with your friends and let them witness the magic! If you have been working in a local envrironment, you might need a local server to host your files, as mentioned above. I personally use Glitch for all my VR projects.

現在,我們已經成功實現了可在網絡上運行并實時運行的Multiplayer VR應用程序。 繼續與您的朋友進行測試,讓他們見證魔術! 如上所述,如果您在本地環境中工作,則可能需要本地服務器來托管文件。 我個人將Glitch用于所有VR項目。

You now know the basics of both A-Frame and Ably, allowing you to build both VR apps and realtime apps or — even better — a collaborative app, like the one we just did.

現在,您已經了解了A-Frame和Ably的基礎知識,從而可以構建VR應用程序和實時應用程序,或者甚至可以像我們剛才那樣構建協作應用程序(甚至更好)。

Ideas are already brewing in your mind? Go ahead and build that app you’ve always wanted to! Here’s the complete source code for this application. Feel free to give a shout to me on Twitter if you get stuck or would like to know more about something.

您的想法已經在醞釀中? 繼續構建您一直想要的應用程序! 這是此應用程序的完整源代碼 。 如果您遇到困難或想了解更多信息,請隨時在Twitter上對我大喊大叫。

翻譯自: https://www.freecodecamp.org/news/how-to-build-a-multiplayer-vr-web-app-7b989964fb38/

vr多人

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394323.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394323.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394323.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

量子測量 -- 確定性的死神

一、測量 -- 確定性的死神 前文已反復提及在量子世界中測量這一過程會產生很多奇異的、反直覺的現象。在第一篇文章中我舉的例子是:用同樣的配方,同樣的火候,同樣的廚具(所有你能想到的變量均相同)煎雞蛋,結…

python增刪改查csv文件_Python--作業2--對員工信息文件,實現增刪改查操作

#!/usr/bin/env python#-*- coding:utf-8 -*-#Author:Huanglinshengimportos#查詢方式一:select * from data_staff.txt where age > 22#查詢方式二:select * from data_staff.txt where dept "IT"#查詢方式三:select * from d…

ios注銷所有通知_您一直想了解的有關iOS中通知的所有信息

ios注銷所有通知by Payal Gupta通過Payal Gupta 您一直想了解的有關iOS中通知的所有信息 (Everything you’ve always wanted to know about notifications in iOS) 漂亮的小警報..? (Pretty Little Alerts..?) Notifications are a way to inform users when new…

vue-x

https://my.oschina.net/wangnian/blog/2055631轉載于:https://www.cnblogs.com/ylblogs/p/10694849.html

leetcode97. 交錯字符串(動態規劃)

給定三個字符串 s1, s2, s3, 驗證 s3 是否是由 s1 和 s2 交錯組成的。 示例 1: 輸入: s1 “aabcc”, s2 “dbbca”, s3 “aadbbcbcac” 輸出: true 解題思路 數組含義:dp[i][j]s1的前i個和s2的前j個能否組成字符串s3的前ij長度的子串 狀態轉移: d…

【LeetCode】19. Remove Nth Node From End of List

Given a linked list, remove the nth node from the end of list and return its head. For example, Given linked list: 1->2->3->4->5, and n 2.After removing the second node from the end, the linked list becomes 1->2->3->5.題意:…

《網絡空間欺騙:構筑欺騙防御的科學基石》一1.1 主動網絡空間防御中網絡空間抵賴與欺騙的視圖...

1.1 主動網絡空間防御中網絡空間抵賴與欺騙的視圖 本文講的是網絡空間欺騙:構筑欺騙防御的科學基石一1.1 主動網絡空間防御中網絡空間抵賴與欺騙的視圖,將抵賴與欺騙納入標準操作規程(SOP):隨著攻擊技術的不斷演進,網…

管樁的彈性模量計算公式_樁基設計計算公式

0.9300.71555.31201018001.130973355樁長21.3mN(KN)φfc(kN/m2)Ap(m2)f’s(kN/m2)A’s(m2)樁直徑(m2)11518.963620.7119001.1309733553000000.0160849541.2標準值19006.29KN單樁承載力設計計算(建筑樁基技術規范08版)根據《建筑樁基技術規范》(JGJ94—2008), 單樁豎向極限承載力…

python函數的作用降低編程復雜度_Python語言程序設計 (第11期) 測驗5: 函數和代碼復用...

共10道單選題和2道編程題,限答1次、限時50分鐘選擇題1.以下選項不是函數作用的是:???????????????????????????????????????????????????????????????????????????????…

restful解決什么問題_當您陷入RESTful,WordPress和一個困難的地方時,如何解決CMS問題...

restful解決什么問題by Jessica Duffin Wolfe杰西卡達芬沃爾夫(Jessica Duffin Wolfe) 當您陷入RESTful,WordPress和一個困難的地方時,如何解決CMS問題 (How to solve a CMS problem when you’re caught between RESTful, WordPress, and a hard place…

InfluxDB的HTTP API寫入操作

一、說明 為了方便,本文主要使用curl來發起http請求,示例當中也是使用curl這個工具來模擬HTTP 請求。 在實際使用中,可以將請求寫入代碼中,通過其他編程語言來模擬HTTP請求。 二、InfluxDB通過HTTP API操作數據庫 1)建…

揭開勒索軟件的真面目

一、前言 2013年9月,戴爾公司的SecureWorks威脅應對部門(CTU)發現了一種名為“CryptoLocker”的勒索軟件,它以郵件附件形式分發,感染計算機并加密近百種格式文件(包括電子表格、數據庫、圖片等)…

leetcode486. 預測贏家(動態規劃)

給定一個表示分數的非負整數數組。 玩家1從數組任意一端拿取一個分數,隨后玩家2繼續從剩余數組任意一端拿取分數,然后玩家1拿,……。每次一個玩家只能拿取一個分數,分數被拿取之后不再可取。直到沒有剩余分數可取時游戲結束。最終…

w550官方例程_急!求索愛w550的刷機所需要的所有文件! 全部分送上!

展開全部W550c行貨軟件升級使用國內行貨W550c手機的朋友,將來是可以在62616964757a686964616fe58685e5aeb931333238646330官方網站使用隨機數據線免費升級的,目前W550c的最新版本是R4AB048但是由于目前官方網站還未提供,大家敬請期待。W550c索…

python的xpath用法介紹_python爬蟲之xpath的基本使用詳解

本篇文章主要介紹了python爬蟲之xpath的基本使用詳解,現在分享給大家,也給大家做個參考。一起過來看看吧一、簡介XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進行遍歷。XPath 是 W3C XSLT 標準的主要元素&#xff…

楊波 微服務技術專家_專家稱,這些是最有效的微服務測試策略

楊波 微服務技術專家by Jake Lumetta杰克盧米塔(Jake Lumetta) 專家稱,這些是最有效的微服務測試策略 (These are the most effective microservice testing strategies, according to the experts) Testing microservices is hard. More specifically, end-to-end…

LRU算法實現

LRU是Last Recent Used 縮寫,做為一種緩存算法,將最近較少使用的緩存失效。memcache采用了該算法。如下采用了一種PHP的實現方式。該算法將每次新增的內容,放到緩存頂部,達到緩存極限時,將緩存底部的內容清除。可以通過…

Java中的阻塞隊列-LinkedBlockingQueue(二)

原文地址:http://benjaminwhx.com/2018/05/11/%E3%80%90%E7%BB%86%E8%B0%88Java%E5%B9%B6%E5%8F%91%E3%80%91%E8%B0%88%E8%B0%88LinkedBlockingQueue/ 在集合框架里,想必大家都用過ArrayList和LinkedList,也經常在面試中問到他們之間的區別。…

自動加密企業關鍵業務數據 賽門鐵克推出全新信息保護解決方案

最新推出的Symantec Information Centric Security解決方案,能夠幫助企業隨時隨地對數據進行自動加密、跟蹤和撤銷,提供卓越的可見性和管控力 近日,全球網絡安全領域的領導者賽門鐵克公司宣布推出一款全新的高級信息保護工具 Symantec Inform…

leetcode312. 戳氣球(動態規劃)

有 n 個氣球,編號為0 到 n-1,每個氣球上都標有一個數字,這些數字存在數組 nums 中。 現在要求你戳破所有的氣球。如果你戳破氣球 i ,就可以獲得 nums[left] * nums[i] * nums[right] 個硬幣。 這里的 left 和 right 代表和 i 相鄰…