<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2D Raycasting with Hand Following Character</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; background-color: #87CEEB; }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        const mapWidth = 10; // Number of columns in the map
        const mapHeight = 10; // Number of rows in the map
        const map = [
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 1, 1, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
            [1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
            [1, 1, 1, 1, 0, 0, 0, 1, 1, 1],
        ];

        const player = {
            x: 5, // Initial X position
            y: 5, // Initial Y position
            angle: Math.PI / 4, // Initial angle
            fov: Math.PI / 2, // Field of view (60 degrees)
            speed: 0.1, // Player movement speed
            rotationSpeed: 0.03, // Player rotation speed
            width: 0.5, // Player size (used for collision detection)
            height: 0.5 // Player size (used for collision detection)
        };

        // Cast rays to detect walls
        function castRay(angle) {
            const ray = { x: player.x, y: player.y };
            const stepSize = 0.1; // Step size for raycasting
            let dist = 0;

            while (dist < 1000) {
                ray.x = player.x + Math.cos(angle) * dist;
                ray.y = player.y + Math.sin(angle) * dist;

                const gridX = Math.floor(ray.x);
                const gridY = Math.floor(ray.y);

                // Check if the ray hits a wall
                if (gridX >= 0 && gridX < mapWidth && gridY >= 0 && gridY < mapHeight && map[gridY][gridX] === 1) {
                    return dist;
                }
                dist += stepSize;
            }

            return -1; // No wall hit
        }

        // Render the scene
        function render() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Cast rays in a loop
            const numRays = canvas.width;
            const halfFov = player.fov / 2;
            const rayAngleIncrement = player.fov / numRays;

            for (let i = 0; i < numRays; i++) {
                const angle = player.angle - halfFov + rayAngleIncrement * i;
                const dist = castRay(angle);

                if (dist > 0) {
                    const wallHeight = canvas.height / dist;
                    const colorIntensity = Math.min(255, Math.max(0, (1 / dist) * 255));

                    ctx.fillStyle = `rgb(${colorIntensity}, ${colorIntensity}, ${colorIntensity})`;
                    ctx.fillRect(i, canvas.height / 2 - wallHeight / 2, 1, wallHeight);
                }
            }

            // Draw the player as a circle
            ctx.beginPath();
            ctx.arc(player.x * 50, player.y * 50, 5, 0, Math.PI * 2);
            ctx.fillStyle = "red";
            ctx.fill();

            // Draw the hand following the player
            const handDistance = 0.7; // Distance from the player where the hand will appear
            const handX = player.x + Math.cos(player.angle) * handDistance;
            const handY = player.y + Math.sin(player.angle) * handDistance;

            ctx.beginPath();
            ctx.arc(handX * 50, handY * 50, 10, 0, Math.PI * 2); // Draw the hand as a circle
            ctx.fillStyle = "black"; // Color of the hand
            ctx.fill();
        }

        // Check if the player can move to the given position
        function canMoveTo(newX, newY) {
            const gridX = Math.floor(newX);
            const gridY = Math.floor(newY);

            // Check if the new position is inside the map boundaries and not a wall
            if (gridX >= 0 && gridX < mapWidth && gridY >= 0 && gridY < mapHeight && map[gridY][gridX] === 0) {
                return true;
            }
            return false;
        }

        // Handle player movement and rotation
        function handleInput() {
            let newX = player.x;
            let newY = player.y;

            if (keys["w"]) {
                // Move forward
                newX += Math.cos(player.angle) * player.speed;
                newY += Math.sin(player.angle) * player.speed;

                if (canMoveTo(newX, newY)) {
                    player.x = newX;
                    player.y = newY;
                }
            }

            if (keys["s"]) {
                // Move backward
                newX -= Math.cos(player.angle) * player.speed;
                newY -= Math.sin(player.angle) * player.speed;

                if (canMoveTo(newX, newY)) {
                    player.x = newX;
                    player.y = newY;
                }
            }

            if (keys["a"]) {
                // Rotate left
                player.angle -= player.rotationSpeed;
            }

            if (keys["d"]) {
                // Rotate right
                player.angle += player.rotationSpeed;
            }
        }

        // Handle keyboard input
        const keys = {};
        window.addEventListener("keydown", (e) => {
            keys[e.key] = true;
        });
        window.addEventListener("keyup", (e) => {
            keys[e.key] = false;
        });

        // Game loop
        function gameLoop() {
            handleInput();
            render();
            requestAnimationFrame(gameLoop);
        }

        gameLoop();
    </script>
</body>
</html>
