Sanal Gerçeklikte Sonsuz Bir Koşucu Oyunu Nasıl Oluşturulur (3. Bölüm)
Yayınlanan: 2022-03-10Ve böylece yolculuğumuz devam ediyor. Sonsuz bir koşucu VR oyununun nasıl oluşturulacağına dair serimin bu son bölümünde, sizi çok oyunculu bir oyun oluşturmaya bir adım daha yaklaştıracak iki cihaz arasında oyun durumunu nasıl senkronize edebileceğinizi göstereceğim. İstemciden istemciye iletişimde aracı sunucuyu yönetmekten sorumlu olan MirrorVR'ı özellikle tanıtacağım.
Not : Bu oyun VR gözlüğü ile veya VR gözlüğü olmadan oynanabilir. Nihai ürünün demosunu ergo-3.glitch.me adresinde görüntüleyebilirsiniz.
Başlamak için aşağıdakilere ihtiyacınız olacak.
- İnternet erişimi (özellikle glitch.com'a);
- Bu öğreticinin 2. bölümünden tamamlanan bir Glitch projesi. https://glitch.com/edit/#!/ergo-2 adresine gidip “Düzenlemek için Remix”e tıklayarak 2. kısım bitmiş üründen başlayabilirsiniz;
- Bir sanal gerçeklik başlığı (isteğe bağlı, önerilir). (Parçası 15 dolardan sunulan Google Cardboard'u kullanıyorum.)
1. Adım: Puanı Görüntüle
Oyun olduğu gibi çalışır, burada oyuncuya bir meydan okuma verilir: engellerden kaçının. Ancak, nesne çarpışmaları dışında oyun, oyundaki ilerlemeyle ilgili olarak oyuncuya geri bildirim sağlamaz. Bunu düzeltmek için, bu adımda puan görüntüsünü uygulayacaksınız. Puan, kullanıcının görüş alanına yapıştırılmış bir arayüzün aksine, sanal gerçeklik dünyamıza yerleştirilen büyük metin nesnesi olacaktır.
Genel olarak sanal gerçeklikte, kullanıcı arayüzü, kullanıcının kafasına takılmak yerine dünyaya en iyi şekilde entegre edilir.
Nesneyi index.html dosyasına ekleyerek başlayın. Diğer metin öğeleri için yeniden kullanılacak bir text
karışımı ekleyin:
<a-assets> ... <a-mixin text=" font:exo2bold; anchor:center; align:center;"></a-mixin> ... </a-assets>
Ardından, oynatıcıdan hemen önce platforma bir text
öğesi ekleyin:
<!-- Score --> <a-text value="" mixin="text" height="40" width="40" position="0 1.2 -3" opacity="0.75"></a-text> <!-- Player --> ...
Bu, sanal gerçeklik sahnesine bir metin varlığı ekler. Değeri boş olarak ayarlandığından metin şu anda görünmüyor. Ancak, şimdi metin varlığını JavaScript kullanarak dinamik olarak dolduracaksınız. varlıklar/ergo.js'ye gidin. collisions
bölümünden sonra bir score
bölümü ekleyin ve bir dizi global değişken tanımlayın:
-
score
: mevcut oyun skoru. -
countedTrees
: Skora dahil olan tüm ağaçların kimlikleri. (Bunun nedeni, çarpışma testlerinin aynı ağaç için birden çok kez tetiklenebilmesidir.) -
scoreDisplay
: sanal gerçeklik dünyasında bir metin nesnesine karşılık gelen DOM nesnesine başvuru.
/********* * SCORE * *********/ var score; var countedTrees; var scoreDisplay;
Ardından, global değişkenlerimizi başlatmak için bir kurulum işlevi tanımlayın. Aynı şekilde, bir teardown
işlevi tanımlayın.
... var scoreDisplay; function setupScore() { score = 0; countedTrees = new Set(); scoreDisplay = document.getElementById('score'); } function teardownScore() { scoreDisplay.setAttribute('value', ''); }
Game
bölümünde, gameOver
, startGame
ve window.onload
puan kurulumunu ve ayırmayı içerecek şekilde güncelleyin.
/******** * GAME * ********/ function gameOver() { ... teardownScore(); } function startGame() { ... setupScore(); addTreesRandomlyLoop(); } window.onload = function() { setupScore(); ... }
Belirli bir ağaç için puanı artıran bir işlev tanımlayın. Bu işlev, ağacın iki kez sayılmadığından emin olmak için countedTrees
karşı kontrol yapacaktır.
function addScoreForTree(tree_id) { if (countedTrees.has(tree_id)) return; score += 1; countedTrees.add(tree_id); }
Ek olarak, genel değişkeni kullanarak puan görüntüsünü güncellemek için bir yardımcı program ekleyin.
function updateScoreDisplay() { scoreDisplay.setAttribute('value', score); }
Oyuncunun önünden bir engel geçtiğinde bu puan artırma işlevini başlatmak için çarpışma testini uygun şekilde güncelleyin. Hala assets/ergo.js
içinde, collisions
bölümüne gidin. Aşağıdaki kontrolü ekleyin ve güncelleyin.
AFRAME.registerComponent('player', { tick: function() { document.querySelectorAll('.tree').forEach(function(tree) { ... if (position.z > POSITION_Z_LINE_END) { addScoreForTree(tree_id); updateScoreDisplay(); } }) } })
Son olarak, oyun başlar başlamaz skor ekranını güncelleyin. Game
bölümüne gidin ve updateScoreDisplay();
startGame
için:
function startGame() { ... setupScore(); updateScoreDisplay(); ... }
varlıklar/ergo.js ve index.html'nin ilgili kaynak kodu dosyalarıyla eşleştiğinden emin olun. Ardından, önizlemenize gidin. Aşağıdakileri görmelisiniz:
Bu, puan gösterimini tamamlar. Ardından, oyuncunun oyunu istediği gibi tekrar oynayabilmesi için uygun başlangıç ve Game Over menülerini ekleyeceğiz.
2. Adım: Başlat Menüsü Ekle
Artık kullanıcı ilerlemeyi takip edebildiğine göre, oyun deneyimini tamamlamak için son rötuşları ekleyeceksiniz. Bu adımda, kullanıcının oyunları başlatmasına ve yeniden başlatmasına izin veren bir Başlat menüsü ve bir Oyun Bitti menüsü ekleyeceksiniz.
Oyuncunun oyuna başlamak için bir "Başlat" düğmesini tıkladığı Başlat menüsü ile başlayalım. Bu adımın ikinci yarısı için, “Yeniden Başlat” düğmesi olan bir Oyun Bitti menüsü ekleyeceksiniz:
Editörünüzde index.html'ye gidin. Ardından, Mixins
bölümünü bulun. Burada, özellikle büyük metinler için stilleri tanımlayan title
karışımını ekleyin. Daha önce olduğu gibi aynı fontu kullanıyoruz, metni ortaya hizalıyoruz ve metnin türüne uygun bir boyut belirliyoruz. (Aşağıdaki anchor
, bir metin nesnesinin konumuna sabitlendiği yer olduğuna dikkat edin.)
<a-assets> ... <a-mixin text=" font:exo2bold; height:40; width:40; opacity:0.75; anchor:center; align:center;"></a-mixin> </a-assets>
Ardından, ikincil başlıklar için ikinci bir karışım ekleyin. Bu metin biraz daha küçüktür, ancak bunun dışında başlıkla aynıdır.
<a-assets> ... <a-mixin text=" font:exo2bold; height:10; width:10; opacity:0.75; anchor:center; align:center;"></a-mixin> </a-assets>
Üçüncü ve son karışım için, ikincil başlıklardan bile daha küçük olan açıklayıcı metin özelliklerini tanımlayın.
<a-assets> ... <a-mixin text=" font:exo2bold; height:5; width:5; opacity:0.75; anchor:center; align:center;"></a-mixin> </a-assets>
Tüm metin stilleri tanımlandığında, artık dünyadaki metin nesnelerini tanımlayacaksınız. Başlat menüsü için boş bir kapsayıcı ile Score
bölümünün altına yeni bir Menus
bölümü ekleyin:
<!-- Score --> ... <!-- Menus --> <a-entity> <a-entity position="0 1.1 -3"> </a-entity> </a-entity>
Başlat menüsü kabının içinde, başlık olmayan tüm metinler için bir başlık ve bir kap tanımlayın:
... <a-entity ...> <a-entity position="0 1 0"> </a-entity> <a-text value="ERGO" mixin="title"></a-text> </a-entity> </a-entity>
Başlıksız metin kutusunun içine oyunu oynamak için talimatlar ekleyin:
<a-entity...> <a-text value="Turn left and right to move your player, and avoid the trees!" mixin="copy"></a-text> </a-entity>
Başlat menüsünü tamamlamak için "Başlat" yazan bir düğme ekleyin:
<a-entity...> ... <a-text value="Start" position="0 0.75 0" mixin="heading"></a-text> <a-box position="0 0.65 -0.05" width="1.5" height="0.6" depth="0.1"></a-box> </a-entity>
Başlat menüsü HTML kodunuzun aşağıdakilerle eşleştiğini iki kez kontrol edin:
<!-- Menus --> <a-entity> <a-entity position="0 1.1 -3"> <a-entity position="0 1 0"> <a-text value="Turn left and right to move your player, and avoid the trees!" mixin="copy"></a-text> <a-text value="Start" position="0 0.75 0" mixin="heading"></a-text> <a-box position="0 0.65 -0.05" width="1.5" height="0.6" depth="0.1"></a-box> </a-entity> <a-text value="ERGO" mixin="title"></a-text> </a-entity> </a-entity>
Önizlemenize gidin ve aşağıdaki Başlat menüsünü göreceksiniz:
Yine Menus
bölümünde (doğrudan start
menüsünün altında), aynı karışımları kullanarak game-over
menüsünü ekleyin:
<!-- Menus --> <a-entity> ... <a-entity position="0 1.1 -3"> <a-text value="?" mixin="heading" position="0 1.7 0"></a-text> <a-text value="Score" mixin="copy" position="0 1.2 0"></a-text> <a-entity> <a-text value="Restart" mixin="heading" position="0 0.7 0"></a-text> <a-box position="0 0.6 -0.05" width="2" height="0.6" depth="0.1"></a-box> </a-entity> <a-text value="Game Over" mixin="title"></a-text> </a-entity> </a-entity>
JavaScript dosyanıza, entity/ergo.js'ye gidin . Game
bölümünden önce yeni bir Menus
bölümü oluşturun. Ek olarak, üç boş işlev tanımlayın: setupAllMenus
, hideAllMenus
ve showGameOverMenu
.
/******** * MENU * ********/ function setupAllMenus() { } function hideAllMenus() { } function showGameOverMenu() { } /******** * GAME * ********/
Ardından, Game
bölümünü üç yerde güncelleyin. gameOver
Game Over menüsünü gösterin:
function gameOver() { ... showGameOverMenu(); } ``` In `startGame`, hide all menus: ``` function startGame() { ... hideAllMenus(); }
Ardından, window.onload
içinde, startGame
için doğrudan çağrıyı kaldırın ve bunun yerine setupAllMenus
. Dinleyicinizi aşağıdakilerle eşleşecek şekilde güncelleyin:
window.onload = function() { setupAllMenus(); setupScore(); setupTrees(); }
Menu
bölümüne geri gidin. Çeşitli DOM nesnelerine referansları kaydedin:
/******** * MENU * ********/ var menuStart; var menuGameOver; var menuContainer; var isGameRunning = false; var startButton; var restartButton; function setupAllMenus() { menuStart = document.getElementById('start-menu'); menuGameOver = document.getElementById('game-over'); menuContainer = document.getElementById('menu-container'); startButton = document.getElementById('start-button'); restartButton = document.getElementById('restart-button'); }
Ardından, startGame
için hem "Başlat" hem de "Yeniden Başlat" düğmelerini bağlayın:
function setupAllMenus() { ... startButton.addEventListener('click', startGame); restartButton.addEventListener('click', startGame); }
showStartMenu
tanımlayın ve setupAllMenus
:
function setupAllMenus() { ... showStartMenu(); } function hideAllMenus() { } function showGameOverMenu() { } function showStartMenu() { }
Üç boş işlevi doldurmak için birkaç yardımcı işleve ihtiyacınız olacak. Bir A-Frame VR varlığını temsil eden bir DOM öğesini kabul eden ve onu gösteren veya gizleyen aşağıdaki iki işlevi tanımlayın. showAllMenus
üzerinde her iki işlevi de tanımlayın:
... var restartButton; function hideEntity(el) { el.setAttribute('visible', false); } function showEntity(el) { el.setAttribute('visible', true); } function showAllMenus() { ...
İlk hideAllMenus
. Nesneleri görüş alanından kaldıracak, ardından her iki menü için de tıklama dinleyicilerini kaldıracaksınız:
function hideAllMenus() { hideEntity(menuContainer); startButton.classList.remove('clickable'); restartButton.classList.remove('clickable'); }
İkinci olarak, showGameOverMenu
. Burada, her iki menünün yanı sıra Game Over menüsü ve 'Yeniden Başlat' düğmesinin tıklama dinleyicisi için kapsayıcıyı geri yükleyin. Ancak, 'Başlat' düğmesinin tıklama dinleyicisini kaldırın ve 'Başlat' menüsünü gizleyin.
function showGameOverMenu() { showEntity(menuContainer); hideEntity(menuStart); showEntity(menuGameOver); startButton.classList.remove('clickable'); restartButton.classList.add('clickable'); }
Üçüncüsü, showStartMenu
. Burada, showGameOverMenu
gerçekleştirdiği tüm değişiklikleri tersine çevirin.
function showStartMenu() { showEntity(menuContainer); hideEntity(menuGameOver); showEntity(menuStart); startButton.classList.add('clickable'); restartButton.classList.remove('clickable'); }
Kodunuzun ilgili kaynak dosyalarla eşleştiğini iki kez kontrol edin. Ardından, önizlemenize gidin ve aşağıdaki davranışı gözlemleyeceksiniz:
Bu, Başlat ve Oyun Bitti menülerini tamamlar.
Tebrikler! Artık uygun bir başlangıç ve uygun bir bitiş ile tamamen işleyen bir oyununuz var. Ancak, bu eğitimde bir adımımız daha kaldı: Oyun durumunu farklı oyuncu cihazları arasında senkronize etmemiz gerekiyor. Bu bizi çok oyunculu oyunlara bir adım daha yaklaştıracak.
3. Adım: Oyun Durumunu MirrorVR ile Senkronize Etme
Önceki bir öğreticide, bir sunucu ile bir istemci arasında tek yönlü iletişimi kolaylaştırmak için soketler arasında gerçek zamanlı bilgilerin nasıl gönderileceğini öğrendiniz. Bu adımda, aracı sunucuyu istemciden istemciye iletişimde yöneten MirrorVR adlı bu öğreticinin tam teşekküllü bir ürününün üzerine inşa edeceksiniz.
Not : MirrorVR hakkında daha fazla bilgiyi buradan edinebilirsiniz.
index.html'ye gidin. Burada, MirrorVR'ı yükleyeceğiz ve kameraya, uygulanabilir olduğunda bir mobil cihazın görünümünü yansıtması gerektiğini belirten bir bileşen ekleyeceğiz. Socket.io bağımlılığını ve MirrorVR 0.2.3'ü içe aktarın.
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script> <script src="https://cdn.jsdelivr.net/gh/alvinwan/[email protected]/dist/mirrorvr.min.js"></script>
Ardından, camera-listener
adlı bir bileşen ekleyin:
<a-camera camera-listener ...>
varlıklar/ergo.js'ye gidin. Bu adımda, mobil cihaz komutlar gönderecek ve masaüstü cihaz yalnızca mobil cihazı yansıtacaktır.
Bunu kolaylaştırmak için, masaüstü ve mobil cihazları ayırt edecek bir yardımcı programa ihtiyacınız var. Dosyanızın sonuna, shuffle
sonra bir mobileCheck
işlevi ekleyin:
/** * Checks for mobile and tablet platforms. */ function mobileCheck() { var check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[aw])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); return check; };
İlk olarak, oyun başlangıcını senkronize edeceğiz. Oyun bölümünün startGame
, sonuna bir mirrorVR
bildirimi ekleyin.
function startGame() { ... if (mobileCheck()) { mirrorVR.notify('startGame', {}) } }
Mobil istemci artık bir oyunun başlamasıyla ilgili bildirimler gönderir. Şimdi masaüstünün yanıtını uygulayacaksınız.
Pencere yükleme dinleyicisinde bir setupMirrorVR
işlevi çağırın:
window.onload = function() { ... setupMirrorVR(); }
MirrorVR kurulumu için Game
bölümünün üzerinde yeni bir bölüm tanımlayın:
/************ * MirrorVR * ************/ function setupMirrorVR() { mirrorVR.init(); }
Ardından, mirrorVR için başlatma işlevine anahtar sözcük bağımsız değişkenleri ekleyin. Özellikle, oyun başlatma bildirimleri için işleyiciyi tanımlayacağız. Ayrıca bir oda kimliği belirteceğiz; bu, uygulamanızı yükleyen herkesin anında senkronize edilmesini sağlar.
function setupMirrorVR() { mirrorVR.init({ roomId: 'ergo', state: { startGame: { onNotify: function(data) { hideAllMenus(); setupScore(); updateScoreDisplay(); } }, } }); }
Game Over için aynı senkronizasyon işlemini tekrarlayın. gameOver
Game
bölümünde, mobil cihazlar için bir kontrol ekleyin ve buna göre bir bildirim gönderin:
function gameOver() { ... if (mobileCheck()) { mirrorVR.notify('gameOver', {}); } }
MirrorVR
bölümüne gidin ve bir gameOver
dinleyicisi ile anahtar kelime argümanlarını güncelleyin:
function setupMirrorVR() { mirrorVR.init({ state: { startGame: {... }, gameOver: { onNotify: function(data) { gameOver(); } }, } }) }
Ardından, ağaçların eklenmesi için aynı senkronizasyon işlemini tekrarlayın. Trees
bölümünde addTreesRandomly
öğesine gidin. Hangi şeritlerin yeni ağaçlar aldığını takip edin. Ardından, return
direktifinden hemen önce ve buna göre bir bildirim gönderin:
function addTreesRandomly(...) { ... var numberOfTreesAdded ... var position_indices = []; trees.forEach(function (tree) { if (...) { ... position_indices.push(tree.position_index); } }); if (mobileCheck()) { mirrorVR.notify('addTrees', position_indices); } return ... }
MirrorVR
bölümüne gidin ve anahtar sözcük argümanlarını ağaçlar için yeni bir dinleyiciyle mirrorVR.init
olarak güncelleyin:
function setupMirrorVR() { mirrorVR.init({ state: { ... gameOver: {... }, addTrees: { onNotify: function(position_indices) { position_indices.forEach(addTreeTo) } }, } }) }
Son olarak, oyun skorunu senkronize ediyoruz. Score
bölümündeki updateScoreDisplay
, uygun olduğunda bir bildirim gönderin:
function updateScoreDisplay() { ... if (mobileCheck()) { mirrorVR.notify('score', score); } }
Skor değişiklikleri için bir dinleyici ile mirrorVR
başlatmayı son kez güncelleyin:
function setupMirrorVR() { mirrorVR.init({ state: { addTrees: { }, score: { onNotify: function(data) { score = data; updateScoreDisplay(); } } } }); }
Kodunuzun bu adım için uygun kaynak kod dosyalarıyla eşleştiğini iki kez kontrol edin. Ardından, masaüstü önizlemenize gidin. Ek olarak, aynı URL'yi mobil cihazınızda açın. Mobil cihazınız web sayfasını yükler yüklemez, masaüstünüz hemen mobil cihazın oyununu yansıtmaya başlamalıdır.
İşte bir demo. Masaüstü imlecinin hareket etmediğine dikkat edin, bu, mobil aygıtın masaüstü önizlemesini kontrol ettiğini gösterir.
Bu, artırılmış projenizi mirrorVR ile tamamlar.
Bu üçüncü adım, birkaç temel oyun durumu senkronizasyon adımını tanıttı; Bunu daha sağlam hale getirmek için daha fazla akıl sağlığı kontrolü ve daha fazla senkronizasyon noktası ekleyebilirsiniz.
Çözüm
Bu öğreticide, sonsuz koşucu oyununuza son rötuşlar eklediniz ve bir masaüstü istemcisinin bir mobil istemciyle gerçek zamanlı senkronizasyonunu uyguladınız ve mobil cihazın ekranını masaüstünüze etkili bir şekilde yansıttınız. Bu, sanal gerçeklikte sonsuz bir koşucu oyunu oluşturma serisini sonlandırıyor. A-Frame VR teknikleriyle birlikte, 3B modelleme, müşteriden müşteriye iletişim ve diğer yaygın olarak uygulanabilir kavramları öğrendiniz.
Sonraki adımlar şunları içerebilir:
- Daha Gelişmiş Modelleme
Bu, potansiyel olarak üçüncü taraf bir yazılımda oluşturulan ve içe aktarılan daha gerçekçi 3B modeller anlamına gelir. Örneğin, (MagicaVoxel) voksel sanatı oluşturmayı basitleştirir ve (Blender) eksiksiz bir 3D modelleme çözümüdür. - Daha Fazla Karmaşıklık
Gerçek zamanlı strateji oyunu gibi daha karmaşık oyunlar, verimliliği artırmak için üçüncü taraf bir motordan yararlanabilir. Bu, derlenmiş (Unity3d) bir oyun yayınlamak yerine A-Frame ve webVR'den tamamen uzaklaşmak anlamına gelebilir.
Diğer yollar arasında çok oyunculu destek ve daha zengin grafikler bulunur. Bu eğitim serisinin sonunda, artık daha fazlasını keşfedeceğiniz bir çerçeveniz var.