blaze-2d
Version:
A fast and simple WebGL 2 2D game engine written in TypeScript
127 lines (126 loc) • 4.68 kB
JavaScript
import { vec2 } from "gl-matrix";
import Blaze from "../../blaze";
/**
* Creates a virtual joystick which can be used to control a {@link Player}'s movement on a touch device.
*
* @param element The element to append the joystick to
* @param player The player to control
*/
export function createVirtualJoystick(element, player) {
const styles = document.createElement("style");
styles.innerHTML = `
.blz-joystick {
display: flex;
position: fixed;
left: 5%;
bottom: 5%;
border-radius: 50%;
width: 8rem;
height: 8rem;
background-color: rgba(0,0,0,0.5);
border: .5rem solid rgba(255,255,255, 0.1);
justify-content: centre;
align-items: centre;
}
.blz-joystick .blz-stick {
border-radius: 50%;
width: 70%;
height: 70%;
background: radial-gradient(black, #1f1f1f, #444444);
transform-origin: centre;
}
`;
document.head.appendChild(styles);
const joystick = document.createElement("div");
joystick.classList.add("blz-joystick");
const stick = document.createElement("div");
stick.classList.add("blz-stick");
joystick.appendChild(stick);
element.appendChild(joystick);
const setKey = Blaze.getCanvas().keys.setKey;
const calculateMovementKeys = (angle) => {
const bleed = 30;
const deg = (angle / Math.PI) * 180;
const fDeg = 0;
const bDeg = 180;
const bDeg2 = -180;
const rDeg = 90;
const lDeg = -90;
const frDeg = 45;
const flDeg = -45;
const brDeg = 135;
const blDeg = -135;
setKey(player.keys.forward, false);
setKey(player.keys.back, false);
setKey(player.keys.left, false);
setKey(player.keys.right, false);
if (deg > fDeg - bleed && deg < fDeg + bleed) {
setKey(player.keys.forward, true);
}
else if (deg > rDeg - bleed && deg < rDeg + bleed) {
setKey(player.keys.right, true);
}
else if (deg > lDeg - bleed && deg < lDeg + bleed) {
setKey(player.keys.left, true);
}
else if (deg > bDeg - bleed || deg < bDeg2 + bleed) {
setKey(player.keys.back, true);
}
else if (deg > frDeg - bleed && deg < frDeg + bleed) {
setKey(player.keys.forward, true);
setKey(player.keys.right, true);
}
else if (deg > flDeg - bleed && deg < flDeg + bleed) {
setKey(player.keys.forward, true);
setKey(player.keys.left, true);
}
else if (deg > brDeg - bleed && deg < brDeg + bleed) {
setKey(player.keys.back, true);
setKey(player.keys.right, true);
}
else if (deg > blDeg - bleed && deg < blDeg + bleed) {
setKey(player.keys.back, true);
setKey(player.keys.left, true);
}
};
const angleOrigin = vec2.fromValues(0, -1);
const calculateStickPos = (e) => {
// find touch that targets joystick
let touch;
for (const t of Array.from(e.changedTouches)) {
if (t.target === joystick || joystick.contains(t.target)) {
touch = t;
break;
}
}
if (!touch)
return;
e.preventDefault();
const joyRect = joystick.getBoundingClientRect();
const radius = joyRect.width / 2;
const centreX = joyRect.left + joyRect.width / 2;
const centreY = joyRect.top + joyRect.height / 2;
const touchX = touch.pageX;
const touchY = touch.pageY;
const distX = Math.abs(centreX - touchX);
const distY = Math.abs(centreY - touchY);
const dist = Math.sqrt(distX * distX + distY * distY);
const touchVec = vec2.fromValues(touchX - centreX, touchY - centreY);
vec2.normalize(touchVec, touchVec);
vec2.scale(touchVec, touchVec, Math.min(radius * 0.75, dist));
stick.style.transform = `translate(${touchVec[0]}px, ${touchVec[1]}px)`;
// get angle between -Math.PI and Math.PI (0 is directly up)
const angle = vec2.angle(angleOrigin, touchVec);
calculateMovementKeys(touchVec[0] >= 0 ? angle : 0 - angle);
};
joystick.addEventListener("touchstart", calculateStickPos);
joystick.addEventListener("touchmove", calculateStickPos);
joystick.addEventListener("touchend", () => {
stick.style.transform = "";
setKey(player.keys.forward, false);
setKey(player.keys.back, false);
setKey(player.keys.left, false);
setKey(player.keys.right, false);
});
}
//# sourceMappingURL=controls.js.map