Added touch events, joysticks now work on mobile
This commit is contained in:
@ -199,7 +199,7 @@ if scale < 1:
|
|||||||
<legend>Translation & Rotation</legend>
|
<legend>Translation & Rotation</legend>
|
||||||
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<button id="control-mode-toggle" type="button">Switch to Keyboard Controls (WASD + QE)</button>
|
<button id="control-mode-toggle" type="button">Switch to Keyboard/Joystick Controls</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="slider-controls">
|
<div id="slider-controls">
|
||||||
|
|||||||
96
script.js
96
script.js
@ -24,13 +24,13 @@ class Joystick {
|
|||||||
|
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
||||||
this.ctx.fillStyle = '#5554';
|
this.ctx.fillStyle = rootStyles.getPropertyValue('--primary-dark-blue');
|
||||||
this.ctx.fill();
|
this.ctx.fill();
|
||||||
|
|
||||||
|
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.arc(this.nubX, this.nubY, this.radius / 3, 0, Math.PI * 2);
|
this.ctx.arc(this.nubX, this.nubY, this.radius / 3, 0, Math.PI * 2);
|
||||||
this.ctx.fillStyle = '#445bcaff';
|
this.ctx.fillStyle = rootStyles.getPropertyValue('--accent-blue');
|
||||||
this.ctx.fill();
|
this.ctx.fill();
|
||||||
|
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
@ -61,6 +61,11 @@ class Joystick {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.nubX = this.x;
|
||||||
|
this.nubY = this.y;
|
||||||
|
}
|
||||||
|
|
||||||
getX() {
|
getX() {
|
||||||
return (this.nubX - this.x) / this.radius;
|
return (this.nubX - this.x) / this.radius;
|
||||||
}
|
}
|
||||||
@ -464,7 +469,7 @@ controlModeToggle.addEventListener('click', () => {
|
|||||||
// Switch to slider mode
|
// Switch to slider mode
|
||||||
sliderControls.style.display = 'block';
|
sliderControls.style.display = 'block';
|
||||||
keyboardControls.style.display = 'none';
|
keyboardControls.style.display = 'none';
|
||||||
controlModeToggle.textContent = 'Switch to Keyboard Controls (WASD + QE)';
|
controlModeToggle.textContent = 'Switch to Keyboard/Joystick Controls';
|
||||||
|
|
||||||
// Reset manual input state
|
// Reset manual input state
|
||||||
Object.keys(keyState).forEach(key => keyState[key] = false);
|
Object.keys(keyState).forEach(key => keyState[key] = false);
|
||||||
@ -637,8 +642,15 @@ applyCustomBtn.addEventListener('click', () => {
|
|||||||
|
|
||||||
function convertTouchToCanvas(inCoords) {
|
function convertTouchToCanvas(inCoords) {
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
const x = inCoords.x - rect.left - canvas.width / 2;
|
|
||||||
const y = inCoords.y - rect.top - canvas.height / 2;
|
// Calculate the scale factor between display size and canvas internal size
|
||||||
|
const scaleX = canvas.width / rect.width;
|
||||||
|
const scaleY = canvas.height / rect.height;
|
||||||
|
|
||||||
|
// Convert client coordinates to canvas coordinates, accounting for scaling
|
||||||
|
const x = (inCoords.x - rect.left) * scaleX - canvas.width / 2;
|
||||||
|
const y = (inCoords.y - rect.top) * scaleY - canvas.height / 2;
|
||||||
|
|
||||||
return { x, y };
|
return { x, y };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,6 +671,74 @@ canvas.addEventListener('mouseup', (event) => {
|
|||||||
rightJoystick.deactivate();
|
rightJoystick.deactivate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Touch event listeners for mobile/tablet support
|
||||||
|
canvas.addEventListener('touchstart', (event) => {
|
||||||
|
event.preventDefault(); // Prevent scrolling and default touch behavior
|
||||||
|
|
||||||
|
for (let i = 0; i < event.touches.length; i++) {
|
||||||
|
const touch = event.touches[i];
|
||||||
|
const canvasCoords = convertTouchToCanvas({ x: touch.clientX, y: touch.clientY });
|
||||||
|
// alert(`X: ${canvasCoords.x}, Y: ${canvasCoords.y}`);
|
||||||
|
leftJoystick.checkShouldActivate(canvasCoords.x, canvasCoords.y);
|
||||||
|
rightJoystick.checkShouldActivate(canvasCoords.x, canvasCoords.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('touchmove', (event) => {
|
||||||
|
event.preventDefault(); // Prevent scrolling while using joysticks
|
||||||
|
|
||||||
|
for (let i = 0; i < event.touches.length; i++) {
|
||||||
|
const touch = event.touches[i];
|
||||||
|
const canvasCoords = convertTouchToCanvas({ x: touch.clientX, y: touch.clientY });
|
||||||
|
leftJoystick.processTouch(canvasCoords.x, canvasCoords.y);
|
||||||
|
rightJoystick.processTouch(canvasCoords.x, canvasCoords.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('touchend', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// If no touches remain, deactivate both joysticks
|
||||||
|
if (event.touches.length === 0) {
|
||||||
|
leftJoystick.deactivate();
|
||||||
|
rightJoystick.deactivate();
|
||||||
|
} else {
|
||||||
|
// Check if the remaining touches are still in range of the joysticks
|
||||||
|
let leftStillActive = false;
|
||||||
|
let rightStillActive = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < event.touches.length; i++) {
|
||||||
|
const touch = event.touches[i];
|
||||||
|
const canvasCoords = convertTouchToCanvas({ x: touch.clientX, y: touch.clientY });
|
||||||
|
|
||||||
|
if (leftJoystick.touchInRange(canvasCoords.x, canvasCoords.y)) {
|
||||||
|
leftStillActive = true;
|
||||||
|
}
|
||||||
|
if (rightJoystick.touchInRange(canvasCoords.x, canvasCoords.y)) {
|
||||||
|
rightStillActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!leftStillActive) {
|
||||||
|
leftJoystick.deactivate();
|
||||||
|
leftJoystick.reset();
|
||||||
|
}
|
||||||
|
if (!rightStillActive) {
|
||||||
|
rightJoystick.deactivate();
|
||||||
|
rightJoystick.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('touchcancel', (event) => {
|
||||||
|
// Handle touch cancellation (e.g., when system interrupts)
|
||||||
|
leftJoystick.deactivate();
|
||||||
|
leftJoystick.reset();
|
||||||
|
rightJoystick.deactivate();
|
||||||
|
rightJoystick.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* END LISTENER CODE
|
* END LISTENER CODE
|
||||||
* BEGIN DYNAMIC DOM FUNCTIONS
|
* BEGIN DYNAMIC DOM FUNCTIONS
|
||||||
@ -934,9 +1014,6 @@ function animate() {
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(canvas.width / 2, canvas.height / 2);
|
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||||
|
|
||||||
leftJoystick.draw();
|
|
||||||
rightJoystick.draw();
|
|
||||||
|
|
||||||
// Update speeds based on control mode
|
// Update speeds based on control mode
|
||||||
if (isManualInputMode) {
|
if (isManualInputMode) {
|
||||||
const maxSpeed = parseFloat(keyboardMaxSpeed.value);
|
const maxSpeed = parseFloat(keyboardMaxSpeed.value);
|
||||||
@ -986,6 +1063,9 @@ function animate() {
|
|||||||
drawGrid(ctx, canvas.width * 2, gridSquareSize, xGridOffset, yGridOffset);
|
drawGrid(ctx, canvas.width * 2, gridSquareSize, xGridOffset, yGridOffset);
|
||||||
drawRobot(ctx, robot, robot.gyroHeading);
|
drawRobot(ctx, robot, robot.gyroHeading);
|
||||||
|
|
||||||
|
leftJoystick.draw();
|
||||||
|
rightJoystick.draw();
|
||||||
|
|
||||||
// Do it all over again
|
// Do it all over again
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
|
|||||||
Reference in New Issue
Block a user