🎮ArcadeLab

A Aventura da Mochila Perdida

by RocketHawk87
895 lines30.7 KB
▶ Play
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>A Aventura da Mochila Perdida</title>
    <style>
        :root {
            --bg-color: #2c3e50;
            --panel-bg: #34495e;
            --accent-color: #f1c40f;
            --text-color: #ecf0f1;
            --btn-color: #27ae60;
            --btn-active: #2ecc71;
            --font-family: 'Comic Sans MS', 'Chalkboard SE', 'Arial', sans-serif;
        }

        * {
            box-sizing: border-box;
            user-select: none;
            -webkit-user-select: none;
            margin: 0;
            padding: 0;
        }

        body {
            background-color: var(--bg-color);
            color: var(--text-color);
            font-family: var(--font-family);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: flex-start;
            min-height: 100vh;
            padding: 10px;
        }

        h1 {
            color: var(--accent-color);
            text-align: center;
            margin-bottom: 10px;
            font-size: 24px;
            text-shadow: 2px 2px #000;
        }

        /* Container Principal */
        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 100%;
            max-width: 800px;
            gap: 10px;
        }

        /* Top HUD */
        .hud {
            display: flex;
            justify-content: space-between;
            width: 100%;
            background-color: var(--panel-bg);
            padding: 10px 15px;
            border-radius: 10px;
            border: 3px solid #1abc9c;
            font-size: 16px;
            font-weight: bold;
        }

        .hud-item {
            display: flex;
            align-items: center;
            gap: 5px;
        }

        /* Canvas / Mapa */
        #gameCanvas {
            background-color: #e0d2b4;
            border: 4px solid #d35400;
            border-radius: 8px;
            box-shadow: 0 8px 16px rgba(0,0,0,0.5);
            image-rendering: pixelated;
            max-width: 100%;
            height: auto;
        }

        /* Caixas de Diálogo e Informações */
        .dialog-box {
            width: 100%;
            background-color: var(--panel-bg);
            border: 3px solid #2980b9;
            border-radius: 10px;
            padding: 12px;
            min-height: 60px;
            text-align: center;
            font-size: 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: inset 0 0 10px rgba(0,0,0,0.3);
        }

        /* Painel Inferior: Missão e Inventário */
        .info-panel {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            width: 100%;
        }

        .panel-box {
            background: var(--panel-bg);
            border: 2px solid #8e44ad;
            border-radius: 8px;
            padding: 10px;
            font-size: 13px;
        }

        .panel-box h3 {
            color: var(--accent-color);
            margin-bottom: 5px;
            font-size: 14px;
            border-bottom: 1px solid #8e44ad;
            padding-bottom: 3px;
        }

        .inventory-list {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            margin-top: 5px;
        }

        .inventory-tag {
            background: #2c3e50;
            border: 1px solid #1abc9c;
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 12px;
        }

        /* Controles Virtuais */
        .controls {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;
            width: 100%;
            margin-top: 5px;
        }

        .btn-interact {
            background-color: var(--btn-color);
            color: white;
            border: none;
            padding: 12px 30px;
            font-size: 18px;
            font-weight: bold;
            font-family: var(--font-family);
            border-radius: 25px;
            box-shadow: 0 4px #1e8449;
            cursor: pointer;
            width: 80%;
            max-width: 300px;
            transition: background-color 0.1s, transform 0.1s;
        }

        .btn-interact:active {
            transform: translateY(3px);
            box-shadow: 0 1px #1e8449;
            background-color: var(--btn-active);
        }

        .dpad {
            display: grid;
            grid-template-columns: repeat(3, 50px);
            grid-template-rows: repeat(2, 50px);
            gap: 5px;
            justify-content: center;
        }

        .btn-dir {
            background-color: #34495e;
            border: 2px solid #bdc3c7;
            color: white;
            font-size: 20px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            box-shadow: 0 3px #2c3e50;
        }

        .btn-dir:active {
            transform: translateY(2px);
            box-shadow: 0 1px #2c3e50;
            background-color: #7f8c8d;
        }

        .btn-reset {
            background-color: #e74c3c;
            color: white;
            border: none;
            padding: 6px 12px;
            font-size: 12px;
            border-radius: 5px;
            cursor: pointer;
            margin-top: 5px;
        }

        /* Modal / Pop-up de Desafio e Coleta */
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background: rgba(0, 0, 0, 0.7);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 100;
        }

        .modal {
            background: var(--panel-bg);
            border: 4px solid var(--accent-color);
            border-radius: 15px;
            padding: 20px;
            max-width: 350px;
            width: 90%;
            text-align: center;
            box-shadow: 0 10px 25px rgba(0,0,0,0.8);
        }

        .modal h2 {
            color: var(--accent-color);
            margin-bottom: 10px;
        }

        .modal p {
            margin-bottom: 15px;
            font-size: 16px;
            line-height: 1.4;
        }

        .modal-options {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .btn-option {
            background: #2980b9;
            color: white;
            border: none;
            padding: 10px;
            font-size: 16px;
            border-radius: 8px;
            cursor: pointer;
            font-family: var(--font-family);
        }

        .btn-option:hover {
            background: #3498db;
        }

        .hidden {
            display: none !important;
        }

        @media (max-width: 500px) {
            .info-panel {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>

    <h1>🎒 A Aventura da Mochila Perdida</h1>

    <div class="game-container">
        <!-- HUD Superior -->
        <div class="hud">
            <div class="hud-item">⭐ <span id="xpDisplay">XP: 0</span></div>
            <div class="hud-item">🏆 <span id="levelDisplay">Nível 1</span></div>
            <div class="hud-item">🎒 <span id="itemCountDisplay">Itens: 0/5</span></div>
        </div>

        <!-- Tela Principal do Jogo -->
        <canvas id="gameCanvas" width="640" height="480"></canvas>

        <!-- Mensagem de Diálogo / Dicas -->
        <div id="dialogBox" class="dialog-box">
            Aproxime-se de um personagem ou item para interagir.
        </div>

        <!-- Botão Principal de Interação -->
        <button id="btnInteract" class="btn-interact">🤝 Interagir</button>

        <!-- D-Pad Controles Virtuais para Celular -->
        <div class="controls">
            <div class="dpad">
                <div></div>
                <button class="btn-dir" id="btnUp">▲</button>
                <div></div>
                <button class="btn-dir" id="btnLeft">◄</button>
                <button class="btn-dir" id="btnDown">▼</button>
                <button class="btn-dir" id="btnRight">►</button>
            </div>
        </div>

        <!-- Painel de Missão e Inventário -->
        <div class="info-panel">
            <div class="panel-box">
                <h3>📜 Missão</h3>
                <p id="missionText">Encontre os 5 itens escolares espalhados pela escola e aprenda seus nomes em inglês.</p>
            </div>
            <div class="panel-box">
                <h3>🎒 Inventário</h3>
                <div id="inventoryContainer" class="inventory-list">
                    <em>Inventário: Vazio</em>
                </div>
            </div>
        </div>

        <button id="btnReset" class="btn-reset">🔄 Reiniciar Jogo</button>
    </div>

    <!-- Modal de Coleta / Quiz -->
    <div id="quizModal" class="modal-overlay hidden">
        <div class="modal">
            <h2 id="modalTitle">Novo Item Encontrado!</h2>
            <p id="modalDesc">Você achou um item!</p>
            <div id="modalOptions" class="modal-options"></div>
        </div>
    </div>

    <script>
        // CONFIGURAÇÃO DO CANVAS E VARIÁVEIS GLOBAIS
        const canvas = document.getElementById("gameCanvas");
        const ctx = canvas.getContext("2d");

        // Elementos da UI
        const dialogBox = document.getElementById("dialogBox");
        const xpDisplay = document.getElementById("xpDisplay");
        const levelDisplay = document.getElementById("levelDisplay");
        const itemCountDisplay = document.getElementById("itemCountDisplay");
        const inventoryContainer = document.getElementById("inventoryContainer");
        const missionText = document.getElementById("missionText");
        const quizModal = document.getElementById("quizModal");
        const modalTitle = document.getElementById("modalTitle");
        const modalDesc = document.getElementById("modalDesc");
        const modalOptions = document.getElementById("modalOptions");

        // Estado do Jogo
        let xp = 0;
        let level = 1;
        let collectedItems = [];
        let totalItemsCount = 5;
        let isModalOpen = false;

        // Configuração de Grade/Tamanho (Grid 16x12 tiles de 40px)
        const TILE_SIZE = 40;
        const COLS = 16;
        const ROWS = 12;

        // TECLAS
        const keys = {
            ArrowUp: false,
            ArrowDown: false,
            ArrowLeft: false,
            ArrowRight: false
        };

        // ESTRUTURA DO MAPA (0: Chão, 1: Parede Externa, 2: Parede Interna, 3: Mesa/Balcão, 4: Estante)
        const mapGrid = [
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1],
            [1,0,3,3,1,0,3,3,0,1,0,4,4,4,0,1],
            [1,0,3,3,2,0,3,3,0,2,0,4,4,4,0,1],
            [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
            [1,1,2,1,1,1,2,1,1,1,2,1,1,1,0,1],
            [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
            [1,0,3,3,0,1,0,3,3,0,1,0,3,3,0,1],
            [1,0,3,3,0,1,0,3,3,0,1,0,3,3,0,1],
            [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
            [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
        ];

        // RÓTULOS DAS SALAS
        const roomLabels = [
            { text: "Classroom", x: 2.5 * TILE_SIZE, y: 1.5 * TILE_SIZE },
            { text: "Laboratory", x: 7 * TILE_SIZE, y: 1.5 * TILE_SIZE },
            { text: "Library", x: 12.5 * TILE_SIZE, y: 1.5 * TILE_SIZE }
        ];

        // JOGADOR
        const player = {
            x: 2 * TILE_SIZE,
            y: 10 * TILE_SIZE,
            width: 32,
            height: 32,
            speed: 3,
            direction: 'down',
            isMoving: false,
            animFrame: 0,
            animTimer: 0
        };

        // NPCs
        const npcs = [
            {
                id: 'teacher',
                name: 'Ms. Ana',
                role: 'Teacher',
                x: 2 * TILE_SIZE,
                y: 2 * TILE_SIZE,
                color: '#e74c3c',
                dialog: "Olá! Eu sou uma Teacher, professora. Encontre os itens escolares espalhados pela escola!"
            },
            {
                id: 'student',
                name: 'Leo',
                role: 'Student',
                x: 7 * TILE_SIZE,
                y: 4 * TILE_SIZE,
                color: '#f39c12',
                dialog: "Oi! Eu sou um Student, aluno. Você já encontrou algum item?"
            },
            {
                id: 'librarian',
                name: 'Librarian',
                role: 'Librarian',
                x: 13 * TILE_SIZE,
                y: 4 * TILE_SIZE,
                color: '#9b59b6',
                dialog: "Bem-vindo à Library! Aqui há muitos livros."
            }
        ];

        // ITENS PERDIDOS
        const items = [
            { id: 'book', nameEn: 'Book', namePt: 'livro', icon: '📖', x: 13 * TILE_SIZE + 4, y: 2 * TILE_SIZE + 4, collected: false },
            { id: 'pencil', nameEn: 'Pencil', namePt: 'lápis', icon: '✏️', x: 2 * TILE_SIZE + 4, y: 3 * TILE_SIZE + 4, collected: false },
            { id: 'notebook', nameEn: 'Notebook', namePt: 'caderno', icon: '📓', x: 7 * TILE_SIZE + 4, y: 2 * TILE_SIZE + 4, collected: false },
            { id: 'eraser', nameEn: 'Eraser', namePt: 'borracha', icon: '🧹', x: 2 * TILE_SIZE + 4, y: 8 * TILE_SIZE + 4, collected: false },
            { id: 'ruler', nameEn: 'Ruler', namePt: 'régua', icon: '📏', x: 12 * TILE_SIZE + 4, y: 8 * TILE_SIZE + 4, collected: false }
        ];

        // BANCO DE OPÇÕES PARA DESAFIOS (EXPANSÍVEL)
        const wordOptions = ["Book", "Pencil", "Notebook", "Eraser", "Ruler", "Pen", "Scissors", "Backpack", "Glue", "Sharpener"];

        // CONTROLES TECLADO
        window.addEventListener("keydown", (e) => {
            if (keys.hasOwnProperty(e.key)) {
                keys[e.key] = true;
            }
        });

        window.addEventListener("keyup", (e) => {
            if (keys.hasOwnProperty(e.key)) {
                keys[e.key] = false;
            }
        });

        // CONTROLES VIRTUAIS (MOBILE)
        const setupMobileBtn = (id, keyName) => {
            const btn = document.getElementById(id);
            const startHandler = (e) => { e.preventDefault(); keys[keyName] = true; };
            const endHandler = (e) => { e.preventDefault(); keys[keyName] = false; };
            
            btn.addEventListener("touchstart", startHandler);
            btn.addEventListener("touchend", endHandler);
            btn.addEventListener("mousedown", startHandler);
            btn.addEventListener("mouseup", endHandler);
        };

        setupMobileBtn("btnUp", "ArrowUp");
        setupMobileBtn("btnDown", "ArrowDown");
        setupMobileBtn("btnLeft", "ArrowLeft");
        setupMobileBtn("btnRight", "ArrowRight");

        document.getElementById("btnInteract").addEventListener("click", () => handleInteraction());
        document.getElementById("btnReset").addEventListener("click", () => resetGame());

        // LÓGICA DE DETECÇÃO DE COLISÃO COM PAREDES E MÓVEIS
        function isSolidTile(x, y) {
            const col = Math.floor(x / TILE_SIZE);
            const row = Math.floor(y / TILE_SIZE);

            if (col < 0 || col >= COLS || row < 0 || row >= ROWS) return true;
            const tile = mapGrid[row][col];
            return tile !== 0; // Se não for 0 (chão), é sólido
        }

        function checkCollision(newX, newY) {
            const margin = 4;
            // Checar os 4 cantos da caixa de colisão do jogador
            const p1 = isSolidTile(newX + margin, newY + margin);
            const p2 = isSolidTile(newX + player.width - margin, newY + margin);
            const p3 = isSolidTile(newX + margin, newY + player.height - margin);
            const p4 = isSolidTile(newX + player.width - margin, newY + player.height - margin);

            if (p1 || p2 || p3 || p4) return true;

            // Colisão com NPCs
            for (let npc of npcs) {
                if (Math.abs(newX - npc.x) < 28 && Math.abs(newY - npc.y) < 28) {
                    return true;
                }
            }

            return false;
        }

        // ATUALIZAÇÃO DA POSIÇÃO
        function updatePlayer() {
            if (isModalOpen) return;

            let dx = 0;
            let dy = 0;

            if (keys.ArrowUp) { dy -= player.speed; player.direction = 'up'; }
            if (keys.ArrowDown) { dy += player.speed; player.direction = 'down'; }
            if (keys.ArrowLeft) { dx -= player.speed; player.direction = 'left'; }
            if (keys.ArrowRight) { dx += player.speed; player.direction = 'right'; }

            player.isMoving = (dx !== 0 || dy !== 0);

            if (player.isMoving) {
                // Tenta mover em X
                if (!checkCollision(player.x + dx, player.y)) {
                    player.x += dx;
                }
                // Tenta mover em Y
                if (!checkCollision(player.x, player.y + dy)) {
                    player.y += dy;
                }

                // Animação de passos simples
                player.animTimer++;
                if (player.animTimer > 10) {
                    player.animFrame = (player.animFrame + 1) % 2;
                    player.animTimer = 0;
                }
            } else {
                player.animFrame = 0;
            }

            checkProximityHint();
        }

        // VERIFICAR PROXIMIDADE PARA MOSTRAR DICAS NA DIALOG BOX
        function checkProximityHint() {
            let nearAnything = false;

            // Checa NPCs
            for (let npc of npcs) {
                const dist = Math.hypot((player.x + 16) - (npc.x + 16), (player.y + 16) - (npc.y + 16));
                if (dist < 45) {
                    dialogBox.innerText = `Pressione Interagir para falar com ${npc.name} (${npc.role}).`;
                    nearAnything = true;
                    break;
                }
            }

            // Checa Itens
            if (!nearAnything) {
                for (let item of items) {
                    if (!item.collected) {
                        const dist = Math.hypot((player.x + 16) - (item.x + 16), (player.y + 16) - (item.y + 16));
                        if (dist < 40) {
                            dialogBox.innerText = `Pressione Interagir para pegar o item brilhante!`;
                            nearAnything = true;
                            break;
                        }
                    }
                }
            }

            if (!nearAnything) {
                dialogBox.innerText = "Aproxime-se de um personagem ou item para interagir.";
            }
        }

        // AÇÃO DE INTERAGIR (BOTÃO "INTERAGIR")
        function handleInteraction() {
            if (isModalOpen) return;

            // Tenta interagir com NPC
            for (let npc of npcs) {
                const dist = Math.hypot((player.x + 16) - (npc.x + 16), (player.y + 16) - (npc.y + 16));
                if (dist < 50) {
                    dialogBox.innerText = `[${npc.name} - ${npc.role}]: "${npc.dialog}"`;
                    return;
                }
            }

            // Tenta interagir com Item
            for (let item of items) {
                if (!item.collected) {
                    const dist = Math.hypot((player.x + 16) - (item.x + 16), (player.y + 16) - (item.y + 16));
                    if (dist < 45) {
                        startItemCollection(item);
                        return;
                    }
                }
            }
        }

        // SISTEMA DE COLETA E MINI-QUIZ EDUCATIVO
        function startItemCollection(item) {
            isModalOpen = true;
            modalTitle.innerText = "Novo item encontrado!";
            modalDesc.innerHTML = `${item.icon} Este item é um <strong>${item.nameEn}</strong>!<br>Em português: <strong>${item.namePt}</strong>.`;

            // Gerar opções do Desafio
            modalOptions.innerHTML = "";
            
            const questionText = document.createElement("p");
            questionText.style.fontWeight = "bold";
            questionText.style.marginTop = "10px";
            questionText.innerText = `Desafio: Como se diz "${item.namePt}" em inglês?`;
            modalOptions.appendChild(questionText);

            // Selecionar opções incorretas aleatórias
            let wrongOpts = wordOptions.filter(w => w !== item.nameEn);
            wrongOpts.sort(() => 0.5 - Math.random());
            let choices = [item.nameEn, wrongOpts[0], wrongOpts[1]];
            choices.sort(() => 0.5 - Math.random());

            choices.forEach(choice => {
                const btn = document.createElement("button");
                btn.className = "btn-option";
                btn.innerText = choice;
                btn.onclick = () => {
                    if (choice === item.nameEn) {
                        item.collected = true;
                        collectedItems.push(item);
                        addXP(10);
                        updateInventoryUI();
                        
                        modalTitle.innerText = "Excelente! ✨";
                        modalDesc.innerText = `Você acertou! "${item.nameEn}" adicionado ao seu inventário. (+10 XP)`;
                        modalOptions.innerHTML = "";
                        
                        const btnClose = document.createElement("button");
                        btnClose.className = "btn-option";
                        btnClose.innerText = "Continuar Explorando";
                        btnClose.onclick = () => {
                            quizModal.classList.add("hidden");
                            isModalOpen = false;
                            checkMissionCompletion();
                        };
                        modalOptions.appendChild(btnClose);
                    } else {
                        alert("Ops! Tente novamente.");
                    }
                };
                modalOptions.appendChild(btn);
            });

            quizModal.classList.remove("hidden");
        }

        // SISTEMA DE XP E NÍVEIS
        function addXP(amount) {
            xp += amount;
            if (xp >= 30 && level === 1) {
                level = 2;
                dialogBox.innerText = "🎉 Parabéns! Você subiu para o Nível 2!";
            } else if (xp >= 60 && level === 2) {
                level = 3;
                dialogBox.innerText = "🎉 Incrível! Você alcançou o Nível 3!";
            }
            xpDisplay.innerText = `XP: ${xp}`;
            levelDisplay.innerText = `Nível ${level}`;
        }

        // ATUALIZAÇÃO DO INVENTÁRIO
        function updateInventoryUI() {
            itemCountDisplay.innerText = `Itens: ${collectedItems.length}/${totalItemsCount}`;
            
            if (collectedItems.length === 0) {
                inventoryContainer.innerHTML = "<em>Inventário: Vazio</em>";
                return;
            }

            inventoryContainer.innerHTML = "";
            collectedItems.forEach(item => {
                const tag = document.createElement("span");
                tag.className = "inventory-tag";
                tag.innerText = `${item.icon} ${item.nameEn}`;
                inventoryContainer.appendChild(tag);
            });
        }

        // VERIFICAÇÃO DE CONCLUSÃO DA MISSÃO PRINCIPAL
        function checkMissionCompletion() {
            if (collectedItems.length === totalItemsCount) {
                setTimeout(() => {
                    isModalOpen = true;
                    modalTitle.innerText = "🏆 Missão Completa!";
                    modalDesc.innerHTML = "<strong>Parabéns! Você encontrou todos os itens escolares!</strong><br><br>Recompensa: Você ganhou +50 XP e completou a aventura da mochila!";
                    modalOptions.innerHTML = "";

                    addXP(50);
                    missionText.innerHTML = "<strong style='color:#2ecc71;'>Missão Concluída com Sucesso!</strong>";

                    const btnFinish = document.createElement("button");
                    btnFinish.className = "btn-option";
                    btnFinish.innerText = "Eba!";
                    btnFinish.onclick = () => {
                        quizModal.classList.add("hidden");
                        isModalOpen = false;
                        dialogBox.innerText = "Você recuperou todos os materiais da mochila mágica! Parabéns!";
                    };
                    modalOptions.appendChild(btnFinish);
                    quizModal.classList.remove("hidden");
                }, 300);
            }
        }

        // REINICIAR O JOGO
        function resetGame() {
            xp = 0;
            level = 1;
            collectedItems = [];
            player.x = 2 * TILE_SIZE;
            player.y = 10 * TILE_SIZE;
            items.forEach(i => i.collected = false);
            
            xpDisplay.innerText = `XP: 0`;
            levelDisplay.innerText = `Nível 1`;
            missionText.innerText = "Encontre os 5 itens escolares espalhados pela escola e aprenda seus nomes em inglês.";
            
            updateInventoryUI();
            dialogBox.innerText = "Jogo reiniciado! Aproxime-se de um personagem ou item para interagir.";
        }

        // FUNÇÕES DE RENDERIZAÇÃO GRÁFICA (PIXEL ART EM CANVAS)
        function drawMap() {
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS; c++) {
                    const tile = mapGrid[r][c];
                    const x = c * TILE_SIZE;
                    const y = r * TILE_SIZE;

                    // Chão (Piso escolar)
                    ctx.fillStyle = "#f5e6ca";
                    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE);
                    ctx.strokeStyle = "#e6d5b8";
                    ctx.strokeRect(x, y, TILE_SIZE, TILE_SIZE);

                    if (tile === 1) { // Parede Externa
                        ctx.fillStyle = "#8e44ad";
                        ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE);
                        ctx.fillStyle = "#6c3483";
                        ctx.fillRect(x + 2, y + 2, TILE_SIZE - 4, TILE_SIZE - 4);
                    } else if (tile === 2) { // Parede Interna / Divisória
                        ctx.fillStyle = "#34495e";
                        ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE);
                    } else if (tile === 3) { // Mesa de Madeira
                        ctx.fillStyle = "#d35400";
                        ctx.fillRect(x + 2, y + 2, TILE_SIZE - 4, TILE_SIZE - 4);
                        ctx.fillStyle = "#e67e22";
                        ctx.fillRect(x + 5, y + 5, TILE_SIZE - 10, TILE_SIZE - 10);
                    } else if (tile === 4) { // Estante de Livros
                        ctx.fillStyle = "#7e5109";
                        ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE);
                        ctx.fillStyle = "#f1c40f";
                        ctx.fillRect(x + 4, y + 6, 6, 28);
                        ctx.fillStyle = "#e74c3c";
                        ctx.fillRect(x + 14, y + 6, 6, 28);
                        ctx.fillStyle = "#3498db";
                        ctx.fillRect(x + 24, y + 6, 6, 28);
                    }
                }
            }

            // Nomes das Salas no Chão
            ctx.font = "bold 14px " + getComputedStyle(document.body).fontFamily;
            ctx.fillStyle = "#7f8c8d";
            ctx.textAlign = "center";
            roomLabels.forEach(room => {
                ctx.fillText(room.text, room.x, room.y);
            });
        }

        function drawNPCs() {
            npcs.forEach(npc => {
                // Corpo / Roupa
                ctx.fillStyle = npc.color;
                ctx.fillRect(npc.x + 6, npc.y + 12, 20, 16);

                // Cabeça
                ctx.fillStyle = "#ffcc99";
                ctx.fillRect(npc.x + 8, npc.y + 2, 16, 12);

                // Cabelo
                ctx.fillStyle = "#4a235a";
                ctx.fillRect(npc.x + 8, npc.y, 16, 4);

                // Olhos
                ctx.fillStyle = "#000";
                ctx.fillRect(npc.x + 11, npc.y + 6, 2, 2);
                ctx.fillRect(npc.x + 19, npc.y + 6, 2, 2);

                // Nome acima do NPC
                ctx.font = "10px " + getComputedStyle(document.body).fontFamily;
                ctx.fillStyle = "#000";
                ctx.textAlign = "center";
                ctx.fillText(`${npc.name} (${npc.role})`, npc.x + 16, npc.y - 4);
            });
        }

        function drawItems() {
            items.forEach(item => {
                if (!item.collected) {
                    // Brilho sob o item
                    ctx.fillStyle = "rgba(241, 196, 15, 0.4)";
                    ctx.beginPath();
                    ctx.arc(item.x + 16, item.y + 16, 14, 0, Math.PI * 2);
                    ctx.fill();

                    // Emoji do Item
                    ctx.font = "20px Arial";
                    ctx.textAlign = "center";
                    ctx.fillText(item.icon, item.x + 16, item.y + 22);
                }
            });
        }

        function drawPlayer() {
            const px = player.x;
            const py = player.y;

            // Animação simples de Pernas
            let legOffset = (player.isMoving && player.animFrame === 1) ? 3 : 0;

            // Pernas
            ctx.fillStyle = "#2c3e50";
            ctx.fillRect(px + 8, py + 22, 6, 8 - legOffset);
            ctx.fillRect(px + 18, py + 22, 6, 8 + legOffset);

            // Corpo / Camiseta
            ctx.fillStyle = "#27ae60";
            ctx.fillRect(px + 6, py + 12, 20, 12);

            // Cabeça
            ctx.fillStyle = "#ffe0bd";
            ctx.fillRect(px + 8, py + 2, 16, 12);

            // Cabelo
            ctx.fillStyle = "#d35400";
            ctx.fillRect(px + 6, py, 20, 5);

            // Olhos
            ctx.fillStyle = "#000";
            if (player.direction === 'left') {
                ctx.fillRect(px + 9, py + 6, 2, 3);
            } else if (player.direction === 'right') {
                ctx.fillRect(px + 21, py + 6, 2, 3);
            } else {
                ctx.fillRect(px + 11, py + 6, 2, 3);
                ctx.fillRect(px + 19, py + 6, 2, 3);
            }
        }

        // LOOP PRINCIPAL DO JOGO (GAME LOOP)
        function gameLoop() {
            updatePlayer();

            // Limpa Tela
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Desenha Elementos
            drawMap();
            drawItems();
            drawNPCs();
            drawPlayer();

            requestAnimationFrame(gameLoop);
        }

        // INICIALIZAÇÃO
        updateInventoryUI();
        requestAnimationFrame(gameLoop);

    </script>
</body>
</html>

Game Source: A Aventura da Mochila Perdida

Creator: RocketHawk87

Libraries: none

Complexity: complex (895 lines, 30.7 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: a-aventura-da-mochila-perdida-rockethawk87" to link back to the original. Then publish at arcadelab.ai/publish.