Land on a Square

Threejs Boilerplate : https://github.com/Sean-Bradley/Three.js-TypeScript-Boilerplate Threejs Course : https://sbcode.net/threejs/ Discount Coupons : https://sbcode.net/coupons#threejs

by seanwasere

HTML

<!--
Threejs Boilerplate : https://github.com/Sean-Bradley/Three.js-TypeScript-Boilerplate
Threejs Course : https://sbcode.net/threejs/
Discount Coupons : https://sbcode.net/coupons#threejs
-->

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
  {
		"imports": {
			"three": "https://cdn.skypack.dev/three@0.146.0/build/three.module",
      "three/": "https://cdn.skypack.dev/three@0.146.0/",   
      "dat.gui": "https://cdn.skypack.dev/dat.gui",
      "cannon-es": "https://cdn.jsdelivr.net/npm/cannon-es@0.19.0/dist/cannon-es.js"
		}
	}
</script>

<div id="instructions">
  <u>LAND ON A SQUARE</u><br />
  W,S to climb/descend<br />
  A,D to yaw<br />
  Numpad 8,5 to pitch<br />
  Numpad 4,6 to bank
</div>

CSS

body {
  overflow: hidden;
  margin: 0px;
}

#instructions {
  color: white;
  position: absolute;
  left: 100px;
  top: 10px;
  font-family: monospace;
}

JavaScript

import * as THREE from 'three';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import {
  GUI
} from 'dat.gui';
import {
  OrbitControls
} from 'three/examples/jsm/controls/OrbitControls';
import {
  Water
} from 'three/examples/jsm/objects/Water';
import {
  Sky
} from "three/examples/jsm/objects/Sky";
import * as CANNON from 'cannon-es'

var stats;
var camera, scene, renderer;
var water, waterCompiled = false;
var light, helper, lightShift = new THREE.Vector3(0, 1, 0);
var clock, delta, numHelipads;
var world, cannonDebugRenderer;
var rotorBody, heliBody, helipadBodies;
var rotorMesh, heliBodyMesh, helipadMeshes;
var v = new THREE.Vector3();
var chaseCamPivot;
var banking = false;
var climbing = false;
var pitching = false;
var yawing = false;
var stableLift = 14.7;
var thrust = new CANNON.Vec3(0, 5, 0);
var keyMap = {};
var onDocumentKey = function(e) {
  keyMap[e.key] = e.type === 'keydown';
};
document.addEventListener('keydown', onDocumentKey, false);
document.addEventListener('keyup', onDocumentKey, false);
const waves = [{
    direction: 45,
    steepness: 0.1,
    wavelength: 7,
  },
  {
    direction: 306,
    steepness: 0.2,
    wavelength: 32,
  },
  {
    direction: 196,
    steepness: 0.3,
    wavelength: 59,
  },
];

function getWaveInfo(x, z, time) {
  const pos = new THREE.Vector3();
  const tangent = new THREE.Vector3(1, 0, 0);
  const binormal = new THREE.Vector3(0, 0, 1);
  Object.keys(waves).forEach((wave) => {
    const w = waves[wave];
    const k = (Math.PI * 2) / w.wavelength;
    const c = Math.sqrt(9.8 / k);
    const d = new THREE.Vector2(
      Math.sin((w.direction * Math.PI) / 180),
      -Math.cos((w.direction * Math.PI) / 180)
    );
    const f = k * (d.dot(new THREE.Vector2(x, z)) - c * time);
    const a = w.steepness / k;
    pos.x += d.y * (a * Math.cos(f));
    pos.y += a * Math.sin(f);
    pos.z += d.x * (a * Math.cos(f));
    tangent.x += -d.x * d.x * (w.steepness * Math.sin(f));
    tangent.y += d.x *...