world – 5th – The “Invisible” Mobile Controller – Gestures for 3D Worlds

Moving a 3D character on a smartphone usually means cluttering the screen with ugly joysticks and transparent buttons. For our multiplayer project, we wanted something better. We built an Invisible Gesture Controller that turns the entire screen into a touch-sensitive pad.

The Strategy: Mapping Keys to Gestures

Our game engine already listens for specific keys like W (Walk), Shift (Run), and Space (Jump). Instead of rewriting the engine, we built a “Touch Wrapper” that translates finger movements into these virtual key presses.

1. Browser Normalization (CSS)

To make a web game feel like a native app, you have to kill the browser’s default behaviors. Without this, the phone will try to zoom or “select text” while you are trying to play.

code CSS

/* Add this to stop mobile browser interference */
body { 
    touch-action: none;          /* Disable pinch-to-zoom and scroll */
    user-select: none;           /* Disable text highlighting */
    -webkit-touch-callout: none; /* Disable long-press menus */
    -webkit-tap-highlight-color: transparent; /* Remove blue tap boxes */
}

2. The Touch Logic (JavaScript)

This is the heart of the mobile support. It handles rotation, toggle-walking, sprinting, and vertical swipes for actions.

code JavaScript

let touchStartX = 0, touchStartY = 0, lastTapTime = 0;

function setupMobileControls() {
    // CAPTURE START POSITION
    window.addEventListener('touchstart', (e) => {
        touchStartX = e.touches[0].clientX;
        touchStartY = e.touches[0].clientY;
    }, { passive: false });

    // ROTATION: Horizontal slide
    window.addEventListener('touchmove', (e) => {
        if (!isStarted || !localPlayer) return;
        let dx = e.touches[0].clientX - touchStartX;
        
        if (Math.abs(dx) > 5) {
            localPlayer.rotation.y -= dx * 0.01; // Rotate character
            touchStartX = e.touches[0].clientX;  // Reset baseline
        }
        e.preventDefault(); // Stop page "bounce"
    }, { passive: false });

    // TAPS & SWIPES: Logic for Walk, Run, Jump, and Camera
    window.addEventListener('touchend', (e) => {
        let dx = e.changedTouches[0].clientX - touchStartX;
        let dy = e.changedTouches[0].clientY - touchStartY;
        let now = Date.now();
        let isDoubleTap = (now - lastTapTime) < 300;

        if (isStarted) {
            // SWIPE UP -> JUMP (Space)
            if (dy < -50 && Math.abs(dx) < 50) {
                keys[' '] = true;
                setTimeout(() => keys[' '] = false, 100);
            } 
            // SWIPE DOWN -> CAMERA VIEW (V)
            else if (dy > 50 && Math.abs(dx) < 50) {
                toggleCameraView(); 
            }
            // TAP LOGIC
            else if (Math.abs(dx) < 10 && Math.abs(dy) < 10) {
                if (isDoubleTap) {
                    // Double Tap: Toggle between Running and Walking
                    if (keys['shift']) {
                        keys['shift'] = false; keys['w'] = true;
                    } else {
                        keys['w'] = true; keys['shift'] = true;
                    }
                } else {
                    // Single Tap: Start/Stop Walking
                    if (keys['w'] || keys['shift']) {
                        keys['w'] = false; keys['shift'] = false; // Stop
                    } else {
                        keys['w'] = true; // Start Walk
                    }
                }
                lastTapTime = now;
            }
        }
    }, { passive: false });
}

How the Gestures Work:

  • Rotation: Sliding your finger left or right updates the localPlayer.rotation.y. It’s sensitive and smooth, allowing for quick 360-degree turns.
  • The “Tap to Move” Toggle: On a keyboard, you hold ‘W’. On mobile, holding your finger down is tiring. We changed it to a Toggle: Tap once to start walking, tap again to stop.
  • Double-Tap to Sprint: Just like Minecraft or other mobile titles, a quick double-tap switches the state from Walking to Running (Shift).
  • Swipe Down for Selfie: We mapped the Camera Flip (V) to a downward swipe. It’s an intuitive gesture for switching perspectives.
  • Swipe Up to Jump: A vertical flick triggers the jump physics instantly.

The Result

By using gestures instead of buttons, we kept the screen 100% clean. This maximizes the immersion of the 3D world and makes the game feel like a premium mobile app rather than a website.

Next time you log in from your phone, try the swipe-down to see your character’s face!

https://chat.deepseek.com/