babylonwander
Version:
a extension tool for babylon's FreeCamera
357 lines (333 loc) • 11.8 kB
text/typescript
import * as BABYLON from "babylonjs"
import "./wander.less"
if (!Object.assign) {
Object.assign = function () {
let json: any = {};
try {
json = arguments[0];
for (let i = 1; i < arguments.length; i++) {
for (let key in arguments[i]) {
json[key] = arguments[i][key]
}
}
} catch (e) {
console.warn(e);
}
return json;
}
Object.defineProperty(Object.prototype, "assign", {"enumerable": false});
}
export default (camera: any, opt?: any) => {
if (!camera.getClassName || camera.getClassName() !== "FreeCamera") {
console.error("babylonWander only support BABYLON.FreeCamera...");
return;
}
let scene: any = camera.getScene();
let engine: any = scene.getEngine();
let canvas: any = engine.getRenderingCanvas();
let page = document.createElement("div");
let controlLeft: any = null;
let controlRight: any = null;
let controlJump: any = null;
let arrowTop: any = null;
let arrowRight: any = null;
let arrowBottom: any = null;
let arrowLeft: any = null;
let canJump: boolean = true;
//[-1,1]
let _x: any = 0, _y: any = 0, _z: any = 0;
//[-.02, .02]
// let _rx: any = 0, _ry: any = 0;
let touchInfoLeft: any = null
let touchInfoRight: any = null
opt = Object.assign({
wrapper: canvas.parentElement,
ellipsoid: new BABYLON.Vector3(.5, 2, .5),
gravity: new BABYLON.Vector3(0, -9.8, 0),
keysLeft: [37, 65],
keysUp: [38, 87],
keysRight: [39, 68],
keysDown: [40, 83],
keysJump: [32],
speed: 1,
jumpingAbility: 30,
jumpingTime: 600,
wanderSensibility: 50,
rotateSensibility: 100
// maxRotateSpeed: .02
}, opt)
function initPage() {
page.setAttribute("class", "babylon-wander show")
page.innerHTML =
`
<div class="control-left">
<div class="arrow-top"></div>
<div class="arrow-right"></div>
<div class="arrow-bottom"></div>
<div class="arrow-left"></div>
<div class="control-center"></div>
</div>
<div class="control-right">
<div class="control-center"></div>
</div>
<div class="control-jump"></div>
`
opt.wrapper && opt.wrapper.appendChild(page)
controlLeft = page.querySelector(".control-left .control-center");
controlRight = page.querySelector(".control-right .control-center");
controlJump = page.querySelector(".control-jump");
arrowTop = page.querySelector(".control-left .arrow-top");
arrowRight = page.querySelector(".control-left .arrow-right");
arrowBottom = page.querySelector(".control-left .arrow-bottom");
arrowLeft = page.querySelector(".control-left .arrow-left");
}
function initCamera() {
camera.checkCollisions = true;
camera.ellipsoid = opt.ellipsoid;
scene.gravity = opt.gravity;
camera._needMoveForGravity = true;
camera.applyGravity = true;
camera.speed = 2;
camera.keysLeft = []
camera.keysUp = []
camera.keysRight = []
camera.keysDown = []
}
function _wander() {
if (camera._localDirection) {
camera._localDirection.copyFromFloats(_x * opt.speed, _y, _z * opt.speed);
camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix);
BABYLON.Vector3.TransformNormalToRef(camera._localDirection, camera._cameraTransformMatrix, camera._transformedDirection);
camera.cameraDirection.addInPlace(camera._transformedDirection);
// camera.rotation.x = Math.max(Math.min(camera.rotation.x + _rx, Math.PI / 2 - .1), -Math.PI / 2 + .1);
// camera.rotation.y += _ry;
if (_y) {
_y = 0;
}
}
}
function jump(e?: any) {
e && e.preventDefault && e.preventDefault();
controlJump.classList.add("active");
if (canJump) {
canJump = false;
_y = opt.jumpingAbility;
window.setTimeout(function () {
canJump = true;
}, opt.jumpingTime)
}
}
function initRender() {
disposeRender();
scene.registerBeforeRender(_wander)
}
function disposeRender() {
scene.unregisterBeforeRender(_wander)
}
function keydown(e: any) {
let keyCode = e.event.keyCode;
if (opt.keysLeft.indexOf(keyCode) != -1) {
arrowLeft.classList.add("active");
_x = -1;
} else if (opt.keysUp.indexOf(keyCode) != -1) {
arrowTop.classList.add("active");
_z = 1;
} else if (opt.keysRight.indexOf(keyCode) != -1) {
arrowRight.classList.add("active");
_x = 1;
} else if (opt.keysDown.indexOf(keyCode) != -1) {
arrowBottom.classList.add("active");
_z = -1;
} else if (opt.keysJump.indexOf(keyCode) != -1) {
jump();
}
}
function keyup(e: any) {
let keyCode = e.event.keyCode;
if (opt.keysLeft.indexOf(keyCode) != -1) {
arrowLeft.classList.remove("active");
_x = 0
} else if (opt.keysUp.indexOf(keyCode) != -1) {
arrowTop.classList.remove("active");
_z = 0;
} else if (opt.keysRight.indexOf(keyCode) != -1) {
arrowRight.classList.remove("active");
_x = 0;
} else if (opt.keysDown.indexOf(keyCode) != -1) {
arrowBottom.classList.remove("active");
_z = 0;
} else if (opt.keysJump.indexOf(keyCode) != -1) {
controlJump.classList.remove("active");
_y = 0;
}
}
function initKeyboardEvent() {
disposeKeyboardEvent();
scene.onKeyboardObservable.add(keydown, 1)
scene.onKeyboardObservable.add(keyup, 2)
}
function disposeKeyboardEvent() {
scene.onKeyboardObservable.removeCallback(keydown)
scene.onKeyboardObservable.removeCallback(keyup)
}
function touchstartLeft(e: any) {
e.preventDefault && e.preventDefault();
e = e.changedTouches ? e.changedTouches[0] : e;
let offsetX: any = getComputedStyle(controlLeft).left;
let offsetY: any = getComputedStyle(controlLeft).top;
touchInfoLeft = {
offsetX: parseFloat(offsetX),
offsetY: parseFloat(offsetY),
clientX: e.clientX,
clientY: e.clientY,
identifier: e.identifier
}
}
function touchstartRight(e: any) {
e.preventDefault && e.preventDefault();
e = e.changedTouches ? e.changedTouches[0] : e;
let offsetX: any = getComputedStyle(controlRight).left;
let offsetY: any = getComputedStyle(controlRight).top;
touchInfoRight = {
offsetX: parseFloat(offsetX),
offsetY: parseFloat(offsetY),
clientX: e.clientX,
clientY: e.clientY,
rotationX: camera.rotation.x,
rotationY: camera.rotation.y,
identifier: e.identifier
}
}
function touchmove(e: any) {
e = e.changedTouches ? e.changedTouches[0] : e;
let difXLeft: any = null;
let difXRight: any = null;
let difYLeft: any = null;
let difYRight: any = null;
let clientX: any = e.clientX;
let clientY: any = e.clientY;
if (touchInfoLeft && e.identifier == touchInfoLeft.identifier) {
difXLeft = clientX - touchInfoLeft.clientX;
difYLeft = clientY - touchInfoLeft.clientY;
controlLeft.style.left = touchInfoLeft.offsetX + difXLeft + "px";
controlLeft.style.top = touchInfoLeft.offsetY + difYLeft + "px";
_x = Math.min(Math.max(-1, difXLeft / opt.wanderSensibility), 1);
_z = Math.min(Math.max(-1, difYLeft / -opt.wanderSensibility), 1);
if (difXLeft > 0) {
arrowRight.classList.add("active")
arrowLeft.classList.remove("active")
} else if (difXLeft < 0) {
arrowLeft.classList.add("active")
arrowRight.classList.remove("active")
}
if (difYLeft > 0) {
arrowBottom.classList.add("active")
arrowTop.classList.remove("active")
} else if (difYLeft < 0) {
arrowTop.classList.add("active")
arrowBottom.classList.remove("active")
}
}
if (touchInfoRight && e.identifier == touchInfoRight.identifier) {
difXRight = clientX - touchInfoRight.clientX;
difYRight = clientY - touchInfoRight.clientY;
controlRight.style.left = touchInfoRight.offsetX + difXRight + "px";
controlRight.style.top = touchInfoRight.offsetY + difYRight + "px";
camera.rotation.x = Math.max(Math.min(touchInfoRight.rotationX + difYRight / opt.rotateSensibility, Math.PI / 2 - .1), -Math.PI / 2 + .1);
camera.rotation.y = touchInfoRight.rotationY + difXRight / opt.rotateSensibility * Math.PI / 2;
// _rx = Math.min(Math.max(-opt.maxRotateSpeed, difXRight / opt.rotateSensibility), opt.maxRotateSpeed);
// _ry = Math.min(Math.max(-opt.maxRotateSpeed, difYRight / -opt.rotateSensibility), opt.maxRotateSpeed);
}
}
function touchend(e: any) {
e = e.changedTouches ? e.changedTouches[0] : e;
/**left*/
if (touchInfoLeft && touchInfoLeft.identifier == e.identifier) {
touchInfoLeft = null;
controlLeft.removeAttribute("style");
arrowTop.classList.remove("active");
arrowRight.classList.remove("active");
arrowBottom.classList.remove("active");
arrowLeft.classList.remove("active");
_x = _z = 0;
}
/**right*/
if (touchInfoRight && touchInfoRight.identifier == e.identifier) {
touchInfoRight = null;
controlRight.removeAttribute("style");
}
// _rx = _ry = 0;
/**jump*/
controlJump.classList.remove("active");
}
function initPannelEvent() {
disposePannelEvent();
/**PC*/
controlLeft.addEventListener("mousedown", touchstartLeft)
controlRight.addEventListener("mousedown", touchstartRight)
controlJump.addEventListener("mousedown", jump)
document.addEventListener("mousemove", touchmove)
document.addEventListener("mouseup", touchend)
/**mobile*/
controlLeft.addEventListener("touchstart", touchstartLeft)
controlRight.addEventListener("touchstart", touchstartRight)
controlJump.addEventListener("touchstart", jump)
document.addEventListener("touchmove", touchmove)
document.addEventListener("touchend", touchend)
}
function disposePannelEvent() {
/**PC*/
controlLeft.removeEventListener("mousedown", touchstartLeft)
controlRight.removeEventListener("mousedown", touchstartRight)
controlJump.removeEventListener("mousedown", jump)
document.removeEventListener("mousemove", touchmove)
document.removeEventListener("mouseup", touchend)
/**mobile*/
controlLeft.removeEventListener("touchstart", touchstartLeft)
controlRight.removeEventListener("touchstart", touchstartRight)
controlJump.removeEventListener("touchstart", jump)
document.removeEventListener("touchmove", touchmove)
document.removeEventListener("touchend", touchend)
}
function initAllEvent() {
initRender();
initKeyboardEvent();
initPannelEvent();
}
function disposeAllEvent() {
disposeRender();
disposeKeyboardEvent();
disposePannelEvent();
}
function disposeAll() {
disposeAllEvent()
opt.wrapper.removeChild(page)
}
initPage();
initCamera()
initAllEvent();
scene.onDisposeObservable.add(disposeAll)
return {
setWrapper: (wrapper: any) => {
opt.wrapper = wrapper;
wrapper.appendChild && wrapper.appendChild(page)
},
getOption: () => opt,
setOption: (newOpt: any) => {
Object.assign(opt, newOpt)
},
show: () => {
initAllEvent();
page.classList.add("show")
},
hide: (disposeEvent?: boolean) => {
if (disposeEvent) {
disposeAllEvent()
} else {
initAllEvent();
}
page.classList.remove("show")
},
dispose: disposeAll
}
}