Treasure Island VR with A-Frame

Image for post
Image for post
Treasure Island VR

Aye, there be treasure here, mateys!

Image for post
Image for post
Our treasure chest full of gold coins

Experience The Island

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Treasure Island VR (Will take some time to load)</title>
<meta name="description" content="Treasure Island VR">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="gray-translucent" />
<script src="aframe-master/dist/aframe-v1.0.4.min.js"></script>
<script src="aframe-environment-component-master/dist/aframe-environment-component.min.js"></script>
<script src="aframe-extras-master/dist/aframe-extras.min.js"></script>
<script src="superframe-master/components/thumb-controls/dist/aframe-thumb-controls-component.min.js"></script>
<script src="superframe-master/components/text-geometry/dist/aframe-text-geometry-component.min.js"></script>
<script src="aframe-lensflare-component-master/dist/aframe-lensflare-component.min.js"></script>
<!-- Video Player Styling -->
<style type="text/css">
#video-permission {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: white;
z-index: 10000;
display: none;
}
#video-permission-button {
position: fixed;
top: calc(50% - 1em);
left: calc(50% - 60px);
width: 120px;
height: 2em;
}
</style>
<script type="text/javascript">function playSound() {//alert("TEST Sound playing functional!!!");
}
// Solves Google mute of audio problem https://stackoverflow.com/questions/47921013/play-sound-on-click-in-a-frame?answertab=active#tab-top
AFRAME.registerComponent('audiohandler', {
init:function() {
let playing = false;
let audio = document.querySelector("#playAudio");
this.el.addEventListener('click', () => {
if(!playing) {
audio.play();
} else {
audio.pause();
audio.currentTime = 0;
}
playing = !playing;
});
}
})
</script>

</head>
<body>
<div id="video-permission">
<button id="video-permission-button">Allow VR Video</button>
</div>
<button id="playButton" type="button">Play Music</button>
<audio id="playAudio" autoplay loop>
<!-- <source src="https://rocketvirtual.com/A-Frame_WebXR/assets/mp3/Romanzeandante.mp3" type="audio/mpeg"> -->
</audio>
<a-scene background="color: #FAFAFA">
<a-assets>
<!-- Our font -->
<a-asset-item id="optimerBoldFont" src="assets/fonts/optimer_bold.typeface.json"></a-asset-item>
<img crossorigin="anonymous" id="flare-asset" src="assets/img/adjustflare.jpg">
<a-asset-item id="Building" src="assets/gltf/New_Building_final1.glb" nav-agent="speed: 1.5; active: true"></a-asset-item>
<a-asset-item id="Building_skeleton" src="assets/gltf/New_Building_final_skeleton1.glb" nav-agent="speed: 1.5; active: true"></a-asset-item>
<a-asset-item crossorigin="anonymous" id="Island" src="assets/gltf/Islands.glb"></a-asset-item>
<a-asset-item crossorigin="anonymous" id="Palm" src="assets/gltf/PalmMinimal.glb"></a-asset-item>
<img crossorigin="anonymous" src="assets/img/play2.png" id="play" >
<img crossorigin="anonymous" src="assets/img/pause.png" id="pause" >
<img crossorigin="anonymous" src="assets/img/volume-normal.png" id="volume-normal" >
<img crossorigin="anonymous" src="assets/img/volume-mute.png" id="volume-mute" >
<img crossorigin="anonymous" src="assets/img/seek-back.png" id="seek-back" >
<video crossorigin="anonymous" id="video-src" src="assets/video/MP_beach.mp4"></video>
<img crossorigin="anonymous" src="assets/img/coins.jpg" id="coins">
<img crossorigin="anonymous" src="assets/img/TreasureCard.png" id="treasurecard">
</a-assets>
<!-- nav-mesh: protecting us from running thru walls -->
<a-entity id="navmesh-Island" gltf-model="url(assets/gltf/navmeshTI.gltf)" scale="" visible="false" nav-mesh=""></a-entity>
<!-- Basic movement and teleportation -->
<a-entity id="cameraRig" movement-controls="constrainToNavMesh: true;" navigator="cameraRig: #cameraRig; cameraHead: #head; collisionEntities: .collision; ignoreEntities: .clickable" position="0 0 0" rotation="0 180 0">
<!-- camera -->
<a-entity id="head" camera="active: true" position="0 1.6 0" look-controls="pointerLockEnabled: true; reverseMouseDrag: true" ></a-entity>
<!-- Left Controller -->
<a-entity class="leftController" hand-controls="hand: left; handModelStyle: lowPoly; color: #15ACCF" tracked-controls vive-controls="hand: left" oculus-touch-controls="hand: left" windows-motion-controls="hand: left" visible="true"></a-entity>
<!-- Right Controller -->
<a-entity class="rightController" hand-controls="hand: right; handModelStyle: lowPoly; color: #15ACCF" tracked-controls vive-controls="hand: right" oculus-touch-controls="hand: right" windows-motion-controls="hand: right" laser-controls raycaster="showLine: true; far: 10; interval: 0; objects: .clickable, a-link;" line="color: lawngreen; opacity: 0.5" visible="true"></a-entity>
</a-entity>
<a-entity id="Meeting_Structure" gltf-model="#Building" position="-10 -0.07 12" rotation="0 0 0" scale="0.019 0.019 0.019" shadow=""></a-entity><!-- Sky -->
<a-sky color="#55D6F6"></a-sky>
<!-- Place the Sun -->
<a-sphere id="flare" radius="0.05" color="yellow" lensflare="createLight:false; relative: true; src: #flare-asset; position:-109.093 10.428 -46.857; lightColor:yellow; intensity: 5; lightDecay: 500" position="-109.093 26.20844 -14.03708"></a-sphere>
<!-- Island terrain -->
<a-entity id="The_Island" gltf-model="#Island" position="-29.71322 -5.19691 23.18321" scale="75 75 75" visible="true" shadow="cast: false; receive: true"></a-entity>
<!-- Ocean -->
<a-ocean position="-28.98488 -1.76439 22.54954" scale="3 3 3" width="50" depth="50" opacity=".75" ocean="density: 45; amplitude: -0.1; speed: 0.75; speedVariance: 0.1"></a-ocean>
<a-entity light="type: ambient; intensity: 0.89"></a-entity><!-- Shadow Camera -->
<a-entity light="intensity: .5; castShadow: true; shadowCameraLeft: -50; shadowCameraBottom: -50; shadowCameraRight: 50; shadowCameraTop: 50; shadowCameraVisible: false" position="-52.39331 48.67142 -2.25727"></a-entity>
<!-- Palm Trees These are a little heavy, but they really look nice... -->
<a-entity id="Palm_Tree1" gltf-model="#Palm" position="-60.19575 -0.18477 -20.35598" rotation="0 0 0" scale=".002 .003 .002" shadow></a-entity>
<a-entity id="Palm_Tree2" gltf-model="#Palm" position="-14.97217 -0.76341 -16.69816" rotation="-3.741 111.923 9.209" scale=".002 .003 .002" shadow></a-entity>
<a-entity id="Palm_Tree3" gltf-model="#Palm" position="-22.06368 -0.1212 -35.6895" rotation="-3.285 61.159 11.798" scale=".002 .002 .002" shadow></a-entity>
<a-entity id="Palm_Tree4" gltf-model="#Palm" position="-29.31117 -0.40163 0.262" rotation="0 78.26 0" scale=".002 .003 .002" shadow></a-entity>
<!-- Small Terrain Map On Wall -->
<a-entity id="Islands_small_map" gltf-model="#Island" position="0.64705 1.66753 3.31628" rotation="-89.87473270201606 125.90518364881788 -125.19586189844593" scale="0.806 1.0 0.806" shadow visible=""></a-entity>
<a-entity position="1.25239 2.34349 3.31628" rotation="0 180 0" scale="0.2 0.2 0.2" text-geometry="value: Treasure Island VR" material="color: #FFFFFF"></a-entity><a-entity id="Meeting_Structure_skeleton" gltf-model="#Building_skeleton" position="0.84773 1.5403 3.2393" rotation="-89.87473270201606 125.90518364881788 -125.19586189844593" scale="0.00019 0.00019 0.00019" shadow=""></a-entity><!-- 13 Bridges allowing us to move around the island on multiple levels. -->
<a-box id="bridge-1" position="-51.02139 -0.46314 12.85726" rotation="-90 -52.796 0" scale="1 2.532 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-2" position="-48.48011 -0.84417 -23.91551" rotation="-90 0 0" scale="4.304 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-3" position="-15.68861 4.7949 25.79727" rotation="-75.752 112.335 -91.715" scale="5.080 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-4" position="-12.01506 -0.52461 63.6735" rotation="-90 6.825 0" scale="5.31906 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-5" position="-47.94579 -0.10505 68.83707" rotation="-90 0 0" scale="1 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-6" position="-12.30953 -0.34999 35.37341" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-7" position="-20.82265 -0.29084 -0.3377" rotation="-90 0 0" scale="4.504 0.868 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-8" position="16.2233 -0.53012 11.56199" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-9" position="-3.59464 3.156 16.24416" rotation="-69.518 1.707 -91.206" scale="3.066 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-10" position="-8.59872 1.16195 11.92651" rotation="-78.18295593457648 -168.72461151012482 93.4591566683545" scale="3.8152 0.4676 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-11" position="23.36806 -2.96524 -12.2864" rotation="-77.23757557261062 116.60092201368845 -155.9797383152348" scale="1 6.4158 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-12" position="-64.53757 -0.36763 36.50537" rotation="-90 -52.796 0" scale="1 2.532 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-13" position="12.81913 -0.34999 51.0507" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<!-- Our Treasure Chest in glTF format Link to license: https://creativecommons.org/licenses/by/4.0/ Location: https://sketchfab.com/3d-models/old-chest-efc357374ecf4d17a36e85f1237e624c -->
<a-entity id="Treasure" gltf-model="url(assets/gltf/testChest2.glb)" position="-30.54377 -5.15361 41.89098" rotation="0 -48.819441891916924 0" scale=".01 .01 .01" visible="true"></a-entity>
<a-plane id="fillWithGold" position="-30.53062 -4.68798 41.89179" rotation="-89.67878113608133 66.30955154608043 -113.66164852466733" width="4" height="4" color="#EBE3B6" material="src: #coins" visible="true" scale="0.261 0.117 0.407"></a-plane><!-- Treasure Card -->
<a-plane id="tellAboutCard" position="-1.18813 1.66753 3.31628" rotation="0 180 0" scale="0.367 0.22404 1" width="4" height="4" color="#EBE3B6" material="src: #treasurecard" shadow="" visible="true" scale="1 1 1"></a-plane>
<!-- Controls for display of video screen, seems to work nicely, javascript below </scene> tag below -->

<!-- MEDIAS HOLDER -->
<a-sound id="alert-sound" src="src: url(assets/wav/action.wav)" autoplay="false" position="0 0 0"></a-sound>
<a-video id="video-screen" src="#video-src" position="-0.02132 1.89195 -3.56798" rotation="0 0 0" scale="0.50761 0.49394 1" width="8" height="4" rotation="0 0 0" visible="true"></a-video>
<!-- END MEDIAS HOLDER -->
<!-- CONTROLS -->
<a-image class="clickable" id="control-back" width="0.4" height="0.4" src="#seek-back" position="-0.42425 0.565 -3.47602" rotation="0 1.2570694025170261 0" visible="false" scale="0.85 0.85 0.85"></a-image>
<a-image class="clickable" id="control-play" width="0.4" height="0.4" src="#play" position="-0.00457 0.565 -3.47602" rotation="0 1.2570694025170261 0"></a-image>
<a-image class="clickable" id="control-volume" width="0.4" height="0.4" src="#volume-mute" position="0.38786 0.565 -3.47602" rotation="0 1.2570694025170261 0" visible="false" scale="0.75 0.75 0.75"></a-image>
<!-- END CONTROLS -->
<!-- PROGRESSBAR -->
<a-entity id="progress-bar" geometry="primitive:plane;height:0.1;width:4" material="opacity:0;transparent:true;visible:false" position="-0.00457 0.835 -3.47602" rotation="0 1.2570694025170261 0" >
<a-plane id="progress-bar-track" width="4" height="0.1" color="gray" position="" opacity="0.2" material="" visible="false" geometry=""></a-plane>
<a-plane id="progress-bar-fill" width="2.496982785433659" height="0.1" color="#7198e5" position="-0.7515086072831705 0 0" geometry="" visible="false" material=""></a-plane>
<!-- END PROGRESSBAR -->
</a-scene>
<script>//Google Code for un-audio mute
// Existing code unchanged.
window.onload = function() {
var context = new AudioContext();
// Setup all nodes
}// One-liner to resume playback when user interacted with the page.
document.querySelector('button').addEventListener('click', function() {
context.resume().then(() => {
console.log('Playback resumed successfully');
});
});

var AVideoPlayer = function() {
// Vals
this.duration = 0;
this.current_progress = 0;
this.progressWidth = 4;
this.paused = true;
// Elems
this.elProgressBar = null;
this.elProgressTrack = null;
this.elProgressFill = null;
this.elAlertSound = null;
this.elVideo = null;
this.elVideoScreen = null;
this.elControlBack = null;
this.elControlPlay = null;
this.elControlVolume = null;
this._initElements = function() {
this.elProgressBar = document.getElementById('progress-bar');
this.elProgressTrack = document.getElementById('progress-bar-track');
this.elProgressFill = document.getElementById('progress-bar-fill');
this.elAlertSound = document.getElementById('alert-sound');
this.elVideo = document.getElementById('video-src');
this.elVideoScreen = document.getElementById('video-screen');
this.elControlBack = document.getElementById('control-back');
this.elControlPlay = document.getElementById('control-play');
this.elControlVolume = document.getElementById('control-volume');
}
/**
* PROGRESS
*/
this.setProgress = function(progress) {
var new_progress = this.progressWidth*progress;
this._setProgressWidth(new_progress);
var progress_coord = this._getProgressCoord();
if (progress_coord != undefined) {
progress_coord.x = -(this.progressWidth-new_progress)/2;
this._setProgressCoord(progress_coord);
}
}
this._getProgressCoord = function() {
return AFRAME.utils.coordinates.parse(this.elProgressFill.getAttribute("position"))
}
this._getProgressWidth = function() {
return parseFloat(this.elProgressFill.getAttribute("width"));
}
this._setProgressCoord = function(coord) {
this.elProgressFill.setAttribute("position", coord);
}
this._setProgressWidth = function(width) {
this.elProgressFill.setAttribute("width", width);
}
/*
* UI SETTERS
*/
this.isProgressBarVisible = function(isVisible) {
this.elProgressTrack.setAttribute("visible", isVisible);
this.elProgressFill.setAttribute("visible", isVisible);
}
this.isControlVisible = function(isVisible) {
this.elControlBack.setAttribute("visible", isVisible);
this.elControlVolume.setAttribute("visible", isVisible);
this.elVideoScreen.setAttribute("visible", isVisible);
}
/*
* EVENTS
*/
this._addPlayerEvents = function() {
var that = this;
this.elVideo.pause();
this.elVideo.onplay = function() {
that.duration = this.duration;
}
this.elVideo.ontimeupdate = function() {
if (that.duration > 0) {
that.current_progress = this.currentTime/that.duration;
}
that.setProgress(that.current_progress);
}
}
this._addControlsEvent = function() {
var that = this;
this.elControlPlay.addEventListener('click', function () {
that._playAudioAlert();
if (that.elVideo.paused) {
this.setAttribute('src', '#pause');
that.elVideo.play();
that.paused = false;
that.isProgressBarVisible(true);
that.isControlVisible(true);
} else {
this.setAttribute('src', '#play');
that.elVideo.pause();
that.paused = true;
that.isProgressBarVisible(false);
that.isControlVisible(false);
}
});
this.elControlVolume.addEventListener('click', function () {
that._playAudioAlert();
if (that.elVideo.muted) {
that.elVideo.muted = false;
this.setAttribute('src', '#volume-normal');
} else {
that.elVideo.muted = true;
this.setAttribute('src', '#volume-mute');
}
});
this.elControlBack.addEventListener('click', function () {
that._playAudioAlert();
that.elVideo.currentTime = 0;
});
}
this._addProgressEvent = function() {
var that = this;
this.elProgressBar.addEventListener('click', function (e) {
if (e.detail == undefined || e.detail.intersection == undefined || that.duration === 0) {
return;
}
let seekedPosition = (e.detail.intersection.point.x+(that.progressWidth/2))/that.progressWidth;
try {
let seekedTime = seekedPosition*that.duration;
that.elVideo.currentTime = seekedTime;
} catch (e) {
}
});
}
this._playAudioAlert = function() {
if (this.elAlertSound.components !== undefined && this.elAlertSound.components.sound !== undefined) {
this.elAlertSound.components.sound.playSound();
}
}
/**
* MOBILE PATCH TO PLAY VIDEO
*/
this._mobileFriendly = function() {
if (AFRAME.utils.device.isMobile()) {
var that = this;
let video_permission = document.getElementById('video-permission');
let video_permission_button = document.getElementById('video-permission-button');
video_permission.style.display = 'block';
video_permission_button.addEventListener("click", function() {
video_permission.style.display = 'none';
that.elVideo.play();
that.elVideo.pause();
}, false);
}
}
this.init = function() {
this._initElements();
//this._determinateProgressWidth();
this.setProgress(this.current_progress);
this._addPlayerEvents();
this._addControlsEvent();
this._addProgressEvent();
this._mobileFriendly();
}
this.init();
}
let scene = document.querySelector('a-scene');
var cursor = document.querySelector('a-cursor');
/**
* CINEMA MODE
*/
scene.lightOff = function() {
scene.islightOn = true;
scene.removeAttribute('animation__fogback');
scene.setAttribute('animation__fog', "property: fog.color; to: #0c192a; dur: 800; easing: easeInQuad;");
}
scene.lightOn = function() {
scene.islightOn = false;
scene.removeAttribute('animation__fog');
scene.setAttribute('animation__fogback', "property: fog.color; to: #dbdedb; dur: 800");
}
/**
* AVideoPlayer
*/
var videoPlayer = new AVideoPlayer();
document.querySelector('#control-play').addEventListener('click', function () {
if (videoPlayer.paused) {
scene.lightOn()
} else {
scene.lightOff();
}
});
</script>
</body>
</html>

Creating The Island

Image for post
Image for post
Heightmap of island
Image for post
Image for post
Colormap of island
Image for post
Image for post
glTF 3D terrain model of island in windows object viewer
Image for post
Image for post
Terrain map of island with sun in a-frame inspector
<!-- Island terrain -->
<a-entity id="The_Island" gltf-model="#Island" position="-29.71322 -5.19691 23.18321" scale="75 75 75" visible="true" shadow="cast: false; receive: true"></a-entity>
<!-- Ocean -->
<a-ocean position="-28.98488 -1.76439 22.54954" scale="3 3 3" width="50" depth="50" opacity=".75" ocean="density: 45; amplitude: -0.1; speed: 0.75; speedVariance: 0.1"></a-ocean>
<!-- Sky -->
<a-sky color="#55D6F6"></a-sky>
<!-- Place the Sun -->
<a-sphere id="flare" radius="0.05" color="yellow" lensflare="createLight:false; relative: true; src: #flare-asset; position:-109.093 10.428 -46.857; lightColor:yellow; intensity: 5; lightDecay: 500" position="-109.093 26.20844 -14.03708"></a-sphere>
<!-- Palm Trees These are a little heavy, but they really look nice...        -->
<a-entity id="Palm_Tree1" gltf-model="#Palm" position="-60.19575 -0.18477 -20.35598" rotation="0 0 0" scale=".002 .003 .002" shadow></a-entity>
<a-entity id="Palm_Tree2" gltf-model="#Palm" position="-14.97217 -0.76341 -16.69816" rotation="-3.741 111.923 9.209" scale=".002 .003 .002" shadow></a-entity>
<a-entity id="Palm_Tree3" gltf-model="#Palm" position="-22.06368 -0.1212 -35.6895" rotation="-3.285 61.159 11.798" scale=".002 .002 .002" shadow></a-entity>
<a-entity id="Palm_Tree4" gltf-model="#Palm" position="-29.31117 -0.40163 0.262" rotation="0 78.26 0" scale=".002 .003 .002" shadow></a-entity>

Office Building

<a-entity id="Meeting_Structure" gltf-model="#Building" position="-10 -0.07 12" rotation="0 0 0" scale="0.019 0.019 0.019" shadow=""></a-entity>
Image for post
Image for post
Inside our office building
<!-- Small Terrain Map On Wall    -->
<a-entity id="Islands_small_map" gltf-model="#Island" position="0.64705 1.66753 3.31628" rotation="-89.87473270201606 125.90518364881788 -125.19586189844593" scale="0.806 1.0 0.806" shadow visible=""></a-entity>
<a-entity position="1.25239 2.34349 3.31628" rotation="0 180 0" scale="0.2 0.2 0.2" text-geometry="value: Treasure Island VR" material="color: #FFFFFF"></a-entity><a-entity id="Meeting_Structure_skeleton" gltf-model="#Building_skeleton" position="0.84773 1.5403 3.2393" rotation="-89.87473270201606 125.90518364881788 -125.19586189844593" scale="0.00019 0.00019 0.00019" shadow=""></a-entity>

Video Player

Image for post
Image for post
Handy .MP4 video player code for whatever we want to show or say
<a-assets><video crossorigin="anonymous" id="video-src" src="assets/video/MP_beach.mp4"></video>
Image for post
Image for post
Ramps for traversing island terrain
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Treasure Island VR</title>
<meta name="description" content="Treasure Island VR">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="gray-translucent" />
<script src="aframe-master/dist/aframe-v1.0.4.min.js"></script>
<script src="https://recast-api.donmccurdy.com/aframe-inspector-plugin-recast.js"></script></head>
<body>
<a-scene inspector-plugin-recast><a-assets><a-asset-item id="Building" src="assets/gltf/New_Building_final1.glb" nav-agent="speed: 1.5; active: true"></a-asset-item><a-asset-item crossorigin="anonymous" id="Island" src="assets/gltf/Islands.glb"></a-asset-item></a-assets><a-entity id="Meeting_Structure" gltf-model="#Building" position="-10 -0.07 12" rotation="0 0 0" scale="0.019 0.019 0.019" shadow=""></a-entity><!-- Island terrain -->
<a-entity id="The_Island" gltf-model="#Island" position="-29.71322 -5.19691 23.18321" scale="75 75 75" visible="true" shadow="cast: false; receive: true"></a-entity>
<a-entity light="type: ambient; intensity: 0.89"></a-entity><!-- Bridges allowing us to move around the island. -->
<a-box id="bridge-1" position="-51.02139 -0.46314 12.85726" rotation="-90 -52.796 0" scale="1 2.532 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-2" position="-48.48011 -0.84417 -23.91551" rotation="-90 0 0" scale="4.304 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-3" position="-15.68861 4.7949 25.79727" rotation="-75.752 112.335 -91.715" scale="5.080 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-4" position="-12.01506 -0.52461 63.6735" rotation="-90 6.825 0" scale="5.31906 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-5" position="-47.94579 -0.10505 68.83707" rotation="-90 0 0" scale="1 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-6" position="-12.30953 -0.34999 35.37341" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-7" position="-20.82265 -0.29084 -0.3377" rotation="-90 0 0" scale="4.504 0.868 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-8" position="16.2233 -0.53012 11.56199" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-9" position="-3.59464 3.156 16.24416" rotation="-69.518 1.707 -91.206" scale="3.066 1 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-10" position="-8.59872 1.16195 11.92651" rotation="-78.18295593457648 -168.72461151012482 93.4591566683545" scale="3.8152 0.4676 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-11" position="23.36806 -2.96524 -12.2864" rotation="-77.23757557261062 116.60092201368845 -155.9797383152348" scale="1 6.4158 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-12" position="-64.53757 -0.36763 36.50537" rotation="-90 -52.796 0" scale="1 2.532 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
<a-box id="bridge-13" position="12.81913 -0.34999 51.0507" rotation="-90 0 0" scale="1 1.854 0.143" width="4" height="4" color="#FFFFFF" shadow="receive: true"></a-box>
</a-scene></body>
</html>

Creating A Navmesh

Image for post
Image for post
Navigation Mesh Being Created
<!-- nav-mesh: protecting us from running thru walls  -->
<a-entity id="navmesh-Island" gltf-model="url(assets/gltf/navmeshTI.gltf)" scale="" visible="false" nav-mesh=""></a-entity>
Image for post
Image for post
Light blue visible navmesh created
<a-entity id=”cameraRig” movement-controls=”constrainToNavMesh: true;”

Treasure Chest Of Gold

Image for post
Image for post
Free treasure chest model
Image for post
Image for post
Gold coins image used to fill our treasure chest
<a-plane id="fillWithGold" position="-30.53062 -4.68798 41.89179" rotation="-89.67878113608133 66.30955154608043 -113.66164852466733" width="4" height="4" color="#EBE3B6" material="src: #coins" visible="true" scale="0.261 0.117 0.407"></a-plane>
Image for post
Image for post
Model viewer showing our empty chest
Image for post
Image for post
Model imported into Blender
Image for post
Image for post
Output our model with the animations box unchecked

The Assets

Image for post
Image for post
Treasure Card to inform visitor
Treasure Reveal Video

Written by

Founder, VR coder, Sci-Fi Blogger with ideas for human technological-evolution.