Header Banner

Aplikasi Game BENAR ATAU SALAH (Game KAMERA BENAR SALAH)

 <!DOCTYPE html>

<html lang="id">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>GAME KAMERA BENAR ATAU SALAH</title>

    <style>

        /* === RESET & VARIABEL === */

        :root {

            --primary: #2563eb;

            --primary-hover: #1d4ed8;

            --success: #16a34a;

            --danger: #dc2626;

            --warning: #eab308;

            --dark: #1e293b;

            --light: #f8fafc;

            --gray: #94a3b8;

            --border: #cbd5e1;

            --bg: #e2e8f0;

        }


        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            user-select: none;

        }


        body {

            background-color: #000;

            display: flex;

            justify-content: center;

            align-items: center;

            height: 100vh;

            width: 100vw;

            overflow: hidden;

        }


        /* === LAYOUT UTAMA 16:9 === */

        #app-container {

            position: relative;

            background-color: var(--bg);

            width: 100%;

            max-width: 100vw;

            max-height: 100vh;

            aspect-ratio: 16 / 9;

            overflow: hidden;

            box-shadow: 0 0 20px rgba(0,0,0,0.5);

            display: flex;

            flex-direction: column;

        }


        /* === HEADER UTAMA === */

        header {

            position: absolute;

            top: 0;

            left: 0;

            right: 0;

            height: 60px;

            padding: 0 20px;

            display: flex;

            justify-content: space-between;

            align-items: center;

            z-index: 50;

            pointer-events: none;

        }


        .btn-header {

            pointer-events: auto;

            background: rgba(255, 255, 255, 0.9);

            border: 2px solid var(--dark);

            color: var(--dark);

            padding: 8px 16px;

            border-radius: 8px;

            font-weight: bold;

            cursor: pointer;

            display: flex;

            align-items: center;

            gap: 8px;

            box-shadow: 0 4px 6px rgba(0,0,0,0.1);

            transition: all 0.2s;

        }

        

        .btn-header:hover { background: var(--dark); color: white; }


        #btn-stop-game { display: none; background: var(--danger); color: white; border-color: var(--danger); }

        #btn-stop-game:hover { background: #b91c1c; }


        /* === FOOTER CREATOR === */

        footer {

            position: absolute;

            bottom: 10px;

            left: 0;

            right: 0;

            text-align: center;

            font-size: 14px;

            font-weight: bold;

            color: var(--dark);

            z-index: 40;

            opacity: 0.7;

        }


        /* === HALAMAN === */

        .screen {

            position: absolute;

            top: 0; left: 0; right: 0; bottom: 0;

            display: flex;

            flex-direction: column;

            padding: 60px 20px 40px 20px;

            z-index: 10;

            background-color: var(--bg);

            transition: opacity 0.3s;

        }

        

        .hidden { display: none !important; opacity: 0; z-index: -1; }


        /* === BERANDA === */

        #home-screen {

            align-items: center;

            justify-content: center;

        }


        .app-title {

            font-size: 3.5vw;

            color: var(--dark);

            text-transform: uppercase;

            text-shadow: 2px 2px 0px white;

            margin-bottom: 30px;

            text-align: center;

        }


        .info-panel {

            background: white;

            padding: 20px 40px;

            border-radius: 15px;

            box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1);

            display: flex;

            gap: 40px;

            margin-bottom: 40px;

            border: 3px solid var(--border);

        }


        .info-item { text-align: center; }

        .info-label { font-size: 1vw; color: var(--gray); font-weight: bold; }

        .info-value { font-size: 1.5vw; color: var(--dark); font-weight: 900; }


        .btn-group { display: flex; gap: 20px; flex-wrap: wrap; justify-content: center; }


        .btn-main {

            padding: 15px 30px;

            font-size: 1.2vw;

            font-weight: bold;

            border-radius: 12px;

            cursor: pointer;

            border: none;

            display: flex;

            align-items: center;

            gap: 10px;

            box-shadow: 0 4px 6px rgba(0,0,0,0.2);

            transition: transform 0.1s, filter 0.2s;

        }

        

        .btn-main:active { transform: scale(0.95); }

        .btn-main:disabled { background: var(--gray); cursor: not-allowed; transform: none; }

        

        .btn-start { background: var(--success); color: white; }

        .btn-start:hover:not(:disabled) { background: #15803d; }

        .btn-camera { background: var(--primary); color: white; }

        .btn-settings { background: var(--warning); color: var(--dark); }


        /* === PENGATURAN GURU (MODAL/SCREEN) === */

        #settings-screen {

            background: white;

            overflow-y: auto;

            padding: 20px;

            z-index: 30;

        }


        .settings-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 2px solid var(--border); padding-bottom: 10px;}

        .settings-header h2 { font-size: 24px; color: var(--dark); }

        .btn-close { background: var(--danger); color: white; border: none; padding: 8px 15px; border-radius: 5px; cursor: pointer; font-weight: bold; }


        .settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }

        

        .form-group { margin-bottom: 15px; }

        .form-group label { display: block; font-weight: bold; margin-bottom: 5px; color: var(--dark); }

        .form-control { width: 100%; padding: 10px; border: 2px solid var(--border); border-radius: 8px; font-size: 14px; }

        textarea.form-control { resize: vertical; min-height: 80px; }


        .bank-soal-section { margin-top: 30px; border-top: 2px solid var(--border); padding-top: 20px;}

        .bank-soal-header { display: flex; justify-content: space-between; margin-bottom: 15px; }

        

        .table-container { overflow-x: auto; max-height: 300px; border: 1px solid var(--border); border-radius: 8px; }

        table { width: 100%; border-collapse: collapse; }

        th, td { padding: 12px; text-align: left; border-bottom: 1px solid var(--border); font-size: 14px; }

        th { background: var(--light); position: sticky; top: 0; }

        .btn-sm { padding: 5px 10px; font-size: 12px; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px; color: white;}

        .btn-edit { background: var(--warning); color: black; }

        .btn-del { background: var(--danger); }

        

        /* Modal Form Soal */

        #modal-soal { position: absolute; top:0; left:0; right:0; bottom:0; background: rgba(0,0,0,0.8); z-index: 100; display: flex; justify-content: center; align-items: center; }

        .modal-content { background: white; width: 90%; max-width: 600px; padding: 20px; border-radius: 10px; }


        /* === LAYOUT GAME === */

        #game-screen {

            justify-content: flex-start;

            align-items: center;

            padding-top: 60px;

        }


        .game-top-panel {

            width: 90%;

            display: flex;

            justify-content: space-between;

            align-items: center;

            background: white;

            padding: 10px 20px;

            border-radius: 12px;

            box-shadow: 0 4px 6px rgba(0,0,0,0.1);

            margin-bottom: 15px;

            border: 2px solid var(--dark);

        }


        .score-box { display: flex; align-items: center; gap: 10px; font-size: 1.5vw; font-weight: bold; color: var(--dark); }

        .score-val { background: var(--bg); padding: 5px 15px; border-radius: 8px; border: 2px solid var(--border); }

        .score-btn { background: var(--primary); color: white; border: none; width: 30px; height: 30px; border-radius: 5px; cursor: pointer; font-size: 20px; font-weight: bold; line-height: 1; }


        .question-panel {

            flex-grow: 1;

            text-align: center;

            padding: 0 20px;

        }

        .question-number { font-size: 1vw; color: var(--gray); font-weight: bold; }

        .question-text { font-size: 2vw; font-weight: 900; color: var(--dark); line-height: 1.2; margin-top: 5px; }


        .timer-box { font-size: 2.5vw; font-weight: 900; color: var(--danger); background: #fee2e2; padding: 5px 20px; border-radius: 10px; border: 2px solid var(--danger); }


        /* === KAMERA CONTAINER (15:6) === */

        .camera-wrapper {

            position: relative;

            width: 90%;

            aspect-ratio: 15 / 6;

            background: #000;

            border: 4px solid var(--dark);

            border-radius: 15px;

            overflow: hidden;

            box-shadow: 0 10px 25px rgba(0,0,0,0.3);

        }


        #video-feed { width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); /* Mirror */ }


        /* Garis Tengah & Area */

        .camera-divider {

            position: absolute;

            top: 0; bottom: 0; left: 50%;

            width: 4px;

            background-color: black;

            transform: translateX(-50%);

            z-index: 5;

        }


        .cam-box {

            position: absolute;

            top: 0; bottom: 0;

            width: 50%;

            border: 4px solid black;

            z-index: 4;

            pointer-events: none;

            transition: background-color 0.3s;

        }

        .cam-box.left { left: 0; border-right: none; }

        .cam-box.right { right: 0; border-left: none; }


        .box-label {

            position: absolute;

            bottom: 10px;

            left: 50%;

            transform: translateX(-50%);

            font-size: 2vw;

            font-weight: 900;

            color: black;

            background: rgba(255,255,255,0.7);

            padding: 5px 15px;

            border-radius: 8px;

            border: 2px solid black;

        }


        /* Overlay Jawaban */

        #answer-reveal {

            position: absolute;

            top: 50%; left: 50%;

            transform: translate(-50%, -50%);

            background: var(--warning);

            color: black;

            padding: 15px 40px;

            font-size: 3vw;

            font-weight: 900;

            border: 6px solid black;

            border-radius: 15px;

            z-index: 10;

            box-shadow: 0 10px 20px rgba(0,0,0,0.5);

            display: none;

        }

        

        .overlay-green { background-color: rgba(22, 163, 74, 0.6) !important; }

        .overlay-red { background-color: rgba(220, 38, 38, 0.6) !important; }


        /* Test Camera Modal */

        #test-cam-modal { position: absolute; top:0; left:0; right:0; bottom:0; background: rgba(0,0,0,0.9); z-index: 100; display: flex; flex-direction:column; justify-content: center; align-items: center; }

        #test-video { width: 60%; aspect-ratio: 16/9; background: #222; border: 2px solid white; transform: scaleX(-1); object-fit: cover; }

    </style>

</head>

<body>


<div id="app-container">

    <!-- Header Controls -->

    <header>

        <button id="btn-stop-game" class="btn-header" onclick="stopGame()">

            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect></svg>

            Hentikan Game

        </button>

        <div style="flex-grow: 1;"></div>

        <button id="btn-fullscreen" class="btn-header" onclick="toggleFullscreen()">

            <svg id="icon-fs-enter" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path></svg>

            <span id="text-fs">Layar Penuh</span>

        </button>

    </header>


    <!-- 1. HALAMAN BERANDA -->

    <div id="home-screen" class="screen">

        <h1 class="app-title">GAME KAMERA BENAR ATAU SALAH</h1>

        

        <div class="info-panel">

            <div class="info-item">

                <div class="info-label">Jumlah Soal</div>

                <div class="info-value" id="info-jml-soal">0 Soal</div>

            </div>

            <div class="info-item">

                <div class="info-label">Waktu Per Soal</div>

                <div class="info-value" id="info-waktu">10 Detik</div>

            </div>

        </div>


        <div class="btn-group">

            <button class="btn-main btn-start" id="btn-start" onclick="startGame()">

                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>

                Mulai Game

            </button>

            <button class="btn-main btn-camera" onclick="openTestCamera()">

                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>

                Aktifkan / Uji Kamera

            </button>

            <button class="btn-main btn-settings" onclick="showScreen('settings-screen')">

                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>

                Pengaturan Guru

            </button>

        </div>

    </div>


    <!-- 2. PENGATURAN GURU & BANK SOAL -->

    <div id="settings-screen" class="screen hidden">

        <div class="settings-header">

            <h2>Pengaturan Guru & Konfigurasi Pembelajaran</h2>

            <button class="btn-close" onclick="showScreen('home-screen')">Kembali ke Beranda</button>

        </div>


        <div class="settings-grid">

            <div>

                <div class="form-group">

                    <label>Jenjang Pendidikan & Kelas</label>

                    <input type="text" id="cfg-jenjang" class="form-control" value="SMP / Kelas 7">

                </div>

                <div class="form-group">

                    <label>Mata Pelajaran</label>

                    <input type="text" id="cfg-mapel" class="form-control" value="Pendidikan Agama Islam">

                </div>

                <div class="form-group">

                    <label>Topik / Materi Pembelajaran</label>

                    <input type="text" id="cfg-topik" class="form-control" value="Meneladani Sifat-Sifat Allah SWT melalui Asmaulhusna">

                </div>

            </div>

            <div>

                <div class="form-group">

                    <label>Waktu Per Soal (Detik)</label>

                    <input type="number" id="cfg-waktu" class="form-control" value="10" min="5" max="60">

                </div>

                <div class="form-group">

                    <label>Tujuan Pembelajaran</label>

                    <textarea id="cfg-tujuan" class="form-control">Menjelaskan Al-Alim, Al-Khabir, As-Sami', Al-Bashir, Al-Aziz, menganalisis bukti fenomena, & melafalkan dalil naqli.</textarea>

                </div>

                <div class="form-group">

                    <label>Petunjuk / Aturan Tambahan</label>

                    <textarea id="cfg-aturan" class="form-control">Berdirilah di area kamera yang sesuai dengan jawaban pilihan kelompok kalian (Kiri untuk A. BENAR, Kanan untuk B. SALAH).</textarea>

                </div>

            </div>

        </div>

        <button class="btn-main btn-start" style="padding: 10px 20px; font-size:14px; margin-top:10px;" onclick="saveConfig()">Simpan Konfigurasi</button>


        <div class="bank-soal-section">

            <div class="bank-soal-header">

                <h2>Bank Soal</h2>

                <button class="btn-main btn-camera" style="padding: 8px 15px; font-size:14px; border-radius:5px;" onclick="openModalSoal()">+ Tambah Soal</button>

            </div>

            <div class="table-container">

                <table>

                    <thead>

                        <tr>

                            <th width="5%">No</th>

                            <th width="45%">Pertanyaan</th>

                            <th width="15%">Kunci</th>

                            <th width="15%">Kesulitan</th>

                            <th width="20%">Aksi</th>

                        </tr>

                    </thead>

                    <tbody id="table-soal-body">

                        <!-- Data Soal dirender JS -->

                    </tbody>

                </table>

            </div>

        </div>

    </div>


    <!-- 3. GAMEPLAY SCREEN -->

    <div id="game-screen" class="screen hidden">

        <!-- Top Panel (Skor, Soal, Timer) -->

        <div class="game-top-panel">

            <div class="score-box">

                <span>Tim Kiri (A)</span>

                <button class="score-btn" onclick="updateScore('A', -1)">-</button>

                <div class="score-val" id="score-a">0</div>

                <button class="score-btn" onclick="updateScore('A', 1)">+</button>

            </div>

            

            <div class="question-panel">

                <div class="question-number" id="game-q-num">Soal 1 dari 10</div>

                <div class="question-text" id="game-q-text">Pertanyaan akan muncul di sini...</div>

            </div>


            <div class="score-box">

                <div class="timer-box" id="game-timer">10</div>

            </div>


            <div class="score-box">

                <button class="score-btn" onclick="updateScore('B', -1)">-</button>

                <div class="score-val" id="score-b">0</div>

                <button class="score-btn" onclick="updateScore('B', 1)">+</button>

                <span>Tim Kanan (B)</span>

            </div>

        </div>


        <!-- Camera Area 15:6 -->

        <div class="camera-wrapper">

            <video id="game-video" autoplay playsinline muted></video>

            

            <!-- Kotak Pembatas -->

            <div class="cam-box left" id="box-left">

                <div class="box-label">A. BENAR</div>

            </div>

            <div class="camera-divider"></div>

            <div class="cam-box right" id="box-right">

                <div class="box-label">B. SALAH</div>

            </div>


            <!-- Overlay Jawaban Tengah -->

            <div id="answer-reveal">JAWABAN A</div>

        </div>

    </div>


    <!-- Footer Creator -->

    <footer>Creator: Samrin Umasugi</footer>

</div>


<!-- Modal Tambah/Edit Soal -->

<div id="modal-soal" class="hidden">

    <div class="modal-content">

        <h3 id="modal-title" style="margin-bottom:15px; color:var(--dark);">Tambah Soal</h3>

        <input type="hidden" id="soal-id">

        <div class="form-group">

            <label>Pertanyaan</label>

            <textarea id="soal-pertanyaan" class="form-control" rows="3"></textarea>

        </div>

        <div class="form-group">

            <label>Kunci Jawaban</label>

            <select id="soal-kunci" class="form-control">

                <option value="A">A. Benar</option>

                <option value="B">B. Salah</option>

            </select>

        </div>

        <div class="form-group">

            <label>Tingkat Kesulitan</label>

            <select id="soal-kesulitan" class="form-control">

                <option value="Mudah">Mudah</option>

                <option value="Sedang" selected>Sedang</option>

                <option value="Sulit">Sulit</option>

            </select>

        </div>

        <div class="form-group">

            <label>Pembahasan (Opsional, untuk arsip)</label>

            <textarea id="soal-pembahasan" class="form-control" rows="2"></textarea>

        </div>

        <div style="display:flex; gap:10px; justify-content:flex-end; margin-top:20px;">

            <button class="btn-main" style="padding:8px 15px; font-size:14px; background:var(--gray);" onclick="closeModalSoal()">Batal</button>

            <button class="btn-main btn-start" style="padding:8px 15px; font-size:14px;" onclick="saveSoal()">Simpan Soal</button>

        </div>

    </div>

</div>


<!-- Modal Test Kamera -->

<div id="test-cam-modal" class="hidden">

    <h2 style="color:white; margin-bottom:20px;">Uji Coba Kamera</h2>

    <video id="test-video" autoplay playsinline muted></video>

    <div style="margin-top:20px; display:flex; gap:15px;">

        <button class="btn-main btn-start" onclick="closeTestCamera()">Tutup & Simpan</button>

    </div>

</div>


<script>

    // === DATA & STATE MANAGEMENT ===

    const DEFAULT_QUESTIONS = [

        { id: 1, pertanyaan: "Allah Maha Mengetahui segala sesuatu, baik yang tampak maupun gaib. Ini adalah makna dari Al-Alim.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "A", pembahasan: "Al-Alim berarti Maha Mengetahui.", tingkat_kesulitan: "Mudah" },

        { id: 2, pertanyaan: "Al-Khabir berarti Allah Maha Mendengar segala ucapan hamba-Nya.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "B", pembahasan: "Al-Khabir berarti Maha Teliti/Waspada, Maha Mendengar adalah As-Sami'.", tingkat_kesulitan: "Sedang" },

        { id: 3, pertanyaan: "Bukti Allah As-Sami' adalah Allah mengabulkan doa hamba-Nya yang diucapkan dalam hati.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "A", pembahasan: "Allah Maha Mendengar segalanya termasuk yang di dalam hati.", tingkat_kesulitan: "Mudah" },

        { id: 4, pertanyaan: "Al-Bashir menunjukkan bahwa penglihatan Allah terbatas pada hal-hal yang besar saja.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "B", pembahasan: "Allah Maha Melihat segala sesuatu, bahkan yang terkecil sekalipun.", tingkat_kesulitan: "Sedang" },

        { id: 5, pertanyaan: "Sifat Al-Aziz berarti Allah Maha Perkasa dan tidak ada yang bisa mengalahkan-Nya.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "A", pembahasan: "Al-Aziz bermakna Maha Perkasa/Mulia.", tingkat_kesulitan: "Mudah" },

        { id: 6, pertanyaan: "Kita meneladani sifat Al-Alim dengan cara bermalas-malasan dalam belajar.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "B", pembahasan: "Harusnya rajin belajar.", tingkat_kesulitan: "Mudah" },

        { id: 7, pertanyaan: "Berhati-hati dalam bertindak karena menyadari Allah Maha Teliti adalah wujud meneladani Al-Khabir.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "A", pembahasan: "Sikap hati-hati cerminan Al-Khabir.", tingkat_kesulitan: "Sedang" },

        { id: 8, pertanyaan: "Allah As-Sami' berarti Allah hanya mendengar doa yang diucapkan dengan suara keras.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "B", pembahasan: "Allah mendengar suara sekecil apapun.", tingkat_kesulitan: "Mudah" },

        { id: 9, pertanyaan: "Menjauhi perbuatan maksiat walau saat sendirian adalah cerminan iman kepada Al-Bashir.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "A", pembahasan: "Merasa diawasi oleh Allah Yang Maha Melihat.", tingkat_kesulitan: "Sedang" },

        { id: 10, pertanyaan: "Menyombongkan diri adalah sikap yang sejalan dengan keimanan kepada sifat Al-Aziz.", jenis_soal: "Benar-Salah", pilihan: ["Benar", "Salah"], kunci_jawaban: "B", pembahasan: "Justru bertentangan, karena hanya Allah yang berhak sombong/perkasa.", tingkat_kesulitan: "Sulit" }

    ];


    let bankSoal = JSON.parse(localStorage.getItem('kameraGame_soal')) || DEFAULT_QUESTIONS;

    let configGame = JSON.parse(localStorage.getItem('kameraGame_config')) || {

        jenjang: "SMP / Kelas 7", mapel: "Pendidikan Agama Islam", topik: "Meneladani Sifat-Sifat Allah SWT melalui Asmaulhusna",

        waktu: 10, tujuan: "", aturan: ""

    };


    let streamGlobal = null;

    let currentQuestionIndex = 0;

    let gameTimerInterval = null;

    let timeLeft = 10;

    let scoreA = 0;

    let scoreB = 0;

    let isPlaying = false;


    // === AUDIO API UNTUK EFEK SUARA OFFLINE ===

    const AudioContext = window.AudioContext || window.webkitAudioContext;

    const audioCtx = new AudioContext();


    function playTone(freq, type, duration) {

        if(audioCtx.state === 'suspended') audioCtx.resume();

        const osc = audioCtx.createOscillator();

        const gain = audioCtx.createGain();

        osc.type = type;

        osc.frequency.value = freq;

        osc.connect(gain);

        gain.connect(audioCtx.destination);

        osc.start();

        gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + duration);

        osc.stop(audioCtx.currentTime + duration);

    }

    function soundCorrect() { playTone(600, 'sine', 0.2); setTimeout(()=>playTone(800, 'sine', 0.4), 200); }

    function soundWrong() { playTone(300, 'sawtooth', 0.5); }

    function soundTick() { playTone(1000, 'square', 0.05); }


    // === INISIALISASI & NAVIGASI ===

    function initApp() {

        updateHomeInfo();

        loadConfigToForm();

        renderTableSoal();

    }


    function showScreen(screenId) {

        document.querySelectorAll('.screen').forEach(el => el.classList.add('hidden'));

        document.getElementById(screenId).classList.remove('hidden');

    }


    function updateHomeInfo() {

        document.getElementById('info-jml-soal').innerText = `${bankSoal.length} Soal`;

        document.getElementById('info-waktu').innerText = `${configGame.waktu} Detik`;

        

        const btnStart = document.getElementById('btn-start');

        if(bankSoal.length === 0) {

            btnStart.disabled = true;

            btnStart.title = "Bank soal kosong!";

        } else {

            btnStart.disabled = false;

            btnStart.title = "";

        }

    }


    // === FULLSCREEN API ===

    function toggleFullscreen() {

        const app = document.documentElement; // Buat fullscreen seluruh halaman

        const fsBtnText = document.getElementById('text-fs');

        

        if (!document.fullscreenElement) {

            if (app.requestFullscreen) { app.requestFullscreen(); }

            else if (app.webkitRequestFullscreen) { app.webkitRequestFullscreen(); }

            fsBtnText.innerText = "Keluar Layar Penuh";

        } else {

            if (document.exitFullscreen) { document.exitFullscreen(); }

            else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); }

            fsBtnText.innerText = "Layar Penuh";

        }

    }


    document.addEventListener('fullscreenchange', () => {

        const fsBtnText = document.getElementById('text-fs');

        if (!document.fullscreenElement) {

            fsBtnText.innerText = "Layar Penuh";

        } else {

            fsBtnText.innerText = "Keluar Layar Penuh";

        }

    });


    // === KAMERA API ===

    async function startCamera(videoElementId) {

        try {

            if(streamGlobal) {

                streamGlobal.getTracks().forEach(track => track.stop());

            }

            const stream = await navigator.mediaDevices.getUserMedia({ video: { width: {ideal: 1280}, height: {ideal: 720}, facingMode: "user" } });

            streamGlobal = stream;

            const videoEl = document.getElementById(videoElementId);

            videoEl.srcObject = stream;

            videoEl.play();

            return true;

        } catch (err) {

            alert("Gagal mengakses kamera! Pastikan browser memiliki izin akses kamera.");

            console.error(err);

            return false;

        }

    }


    function stopCamera() {

        if (streamGlobal) {

            streamGlobal.getTracks().forEach(track => track.stop());

            streamGlobal = null;

        }

    }


    // Modal Uji Kamera

    async function openTestCamera() {

        document.getElementById('test-cam-modal').classList.remove('hidden');

        await startCamera('test-video');

    }

    function closeTestCamera() {

        document.getElementById('test-cam-modal').classList.add('hidden');

        stopCamera();

    }


    // === PENGATURAN & CRUD SOAL ===

    function loadConfigToForm() {

        document.getElementById('cfg-jenjang').value = configGame.jenjang;

        document.getElementById('cfg-mapel').value = configGame.mapel;

        document.getElementById('cfg-topik').value = configGame.topik;

        document.getElementById('cfg-waktu').value = configGame.waktu;

        document.getElementById('cfg-tujuan').value = configGame.tujuan;

        document.getElementById('cfg-aturan').value = configGame.aturan;

    }

    

    function saveConfig() {

        configGame = {

            jenjang: document.getElementById('cfg-jenjang').value,

            mapel: document.getElementById('cfg-mapel').value,

            topik: document.getElementById('cfg-topik').value,

            waktu: parseInt(document.getElementById('cfg-waktu').value) || 10,

            tujuan: document.getElementById('cfg-tujuan').value,

            aturan: document.getElementById('cfg-aturan').value

        };

        localStorage.setItem('kameraGame_config', JSON.stringify(configGame));

        updateHomeInfo();

        alert("Konfigurasi berhasil disimpan!");

    }


    function renderTableSoal() {

        const tbody = document.getElementById('table-soal-body');

        tbody.innerHTML = '';

        bankSoal.forEach((soal, index) => {

            const tr = document.createElement('tr');

            tr.innerHTML = `

                <td>${index + 1}</td>

                <td>${soal.pertanyaan}</td>

                <td>${soal.kunci_jawaban}</td>

                <td>${soal.tingkat_kesulitan}</td>

                <td>

                    <button class="btn-sm btn-edit" onclick="editSoal(${soal.id})">Edit</button>

                    <button class="btn-sm btn-del" onclick="hapusSoal(${soal.id})">Hapus</button>

                </td>

            `;

            tbody.appendChild(tr);

        });

        localStorage.setItem('kameraGame_soal', JSON.stringify(bankSoal));

        updateHomeInfo();

    }


    function openModalSoal(id = null) {

        document.getElementById('modal-soal').classList.remove('hidden');

        if(id) {

            document.getElementById('modal-title').innerText = "Edit Soal";

            const soal = bankSoal.find(s => s.id === id);

            document.getElementById('soal-id').value = soal.id;

            document.getElementById('soal-pertanyaan').value = soal.pertanyaan;

            document.getElementById('soal-kunci').value = soal.kunci_jawaban;

            document.getElementById('soal-kesulitan').value = soal.tingkat_kesulitan;

            document.getElementById('soal-pembahasan').value = soal.pembahasan;

        } else {

            document.getElementById('modal-title').innerText = "Tambah Soal";

            document.getElementById('soal-id').value = '';

            document.getElementById('soal-pertanyaan').value = '';

            document.getElementById('soal-kunci').value = 'A';

            document.getElementById('soal-kesulitan').value = 'Sedang';

            document.getElementById('soal-pembahasan').value = '';

        }

    }


    function closeModalSoal() { document.getElementById('modal-soal').classList.add('hidden'); }


    function saveSoal() {

        const id = document.getElementById('soal-id').value;

        const baru = {

            id: id ? parseInt(id) : Date.now(),

            pertanyaan: document.getElementById('soal-pertanyaan').value,

            jenis_soal: "Benar-Salah",

            pilihan: ["Benar", "Salah"],

            kunci_jawaban: document.getElementById('soal-kunci').value,

            tingkat_kesulitan: document.getElementById('soal-kesulitan').value,

            pembahasan: document.getElementById('soal-pembahasan').value

        };

        

        if(!baru.pertanyaan) return alert("Pertanyaan tidak boleh kosong!");


        if(id) {

            const idx = bankSoal.findIndex(s => s.id === parseInt(id));

            bankSoal[idx] = baru;

        } else {

            bankSoal.push(baru);

        }

        closeModalSoal();

        renderTableSoal();

    }


    function hapusSoal(id) {

        if(confirm("Yakin ingin menghapus soal ini?")) {

            bankSoal = bankSoal.filter(s => s.id !== id);

            renderTableSoal();

        }

    }

    function editSoal(id) { openModalSoal(id); }


    // === GAMEPLAY LOGIC ===

    async function startGame() {

        if (bankSoal.length === 0) {

            alert("Bank soal belum tersedia! Silakan tambahkan soal terlebih dahulu.");

            return;

        }

        

        showScreen('game-screen');

        const camReady = await startCamera('game-video');

        if(!camReady) {

            showScreen('home-screen');

            return;

        }


        document.getElementById('btn-stop-game').style.display = 'flex';

        isPlaying = true;

        currentQuestionIndex = 0;

        scoreA = 0;

        scoreB = 0;

        document.getElementById('score-a').innerText = scoreA;

        document.getElementById('score-b').innerText = scoreB;

        

        resetBoxColors();

        loadQuestion();

    }


    function stopGame() {

        isPlaying = false;

        clearInterval(gameTimerInterval);

        stopCamera();

        document.getElementById('btn-stop-game').style.display = 'none';

        showScreen('home-screen');

    }


    function updateScore(team, val) {

        if(!isPlaying) return;

        if(team === 'A') { scoreA += val; document.getElementById('score-a').innerText = scoreA; }

        if(team === 'B') { scoreB += val; document.getElementById('score-b').innerText = scoreB; }

    }


    function loadQuestion() {

        if(currentQuestionIndex >= bankSoal.length) {

            alert(`Game Selesai!\nSkor Tim A: ${scoreA}\nSkor Tim B: ${scoreB}`);

            stopGame();

            return;

        }


        const q = bankSoal[currentQuestionIndex];

        document.getElementById('game-q-num').innerText = `Soal ${currentQuestionIndex + 1} dari ${bankSoal.length}`;

        document.getElementById('game-q-text').innerText = q.pertanyaan;

        

        timeLeft = configGame.waktu;

        document.getElementById('game-timer').innerText = timeLeft;

        resetBoxColors();


        gameTimerInterval = setInterval(() => {

            timeLeft--;

            document.getElementById('game-timer').innerText = timeLeft;

            if(timeLeft > 0 && timeLeft <= 3) soundTick();


            if(timeLeft <= 0) {

                clearInterval(gameTimerInterval);

                revealAnswer(q.kunci_jawaban);

            }

        }, 1000);

    }


    function revealAnswer(kunci) {

        const overlay = document.getElementById('answer-reveal');

        const boxLeft = document.getElementById('box-left');

        const boxRight = document.getElementById('box-right');


        overlay.innerText = `JAWABAN ${kunci}`;

        overlay.style.display = 'block';


        if(kunci === 'A') {

            boxLeft.classList.add('overlay-green');

            boxRight.classList.add('overlay-red');

            soundCorrect();

        } else {

            boxRight.classList.add('overlay-green');

            boxLeft.classList.add('overlay-red');

            soundCorrect(); // Gunakan suara yang sama atau bedakan sesuai selera

        }


        // Tahan 3 detik lalu lanjut soal

        setTimeout(() => {

            overlay.style.display = 'none';

            currentQuestionIndex++;

            loadQuestion();

        }, 3000);

    }


    function resetBoxColors() {

        document.getElementById('box-left').className = 'cam-box left';

        document.getElementById('box-right').className = 'cam-box right';

        document.getElementById('answer-reveal').style.display = 'none';

    }


    // Jalankan init saat pertama kali

    window.onload = initApp;

</script>


</body>

</html>

Posting Komentar

0 Komentar

Chat WhatsApp