🎮ArcadeLab

Galaksi Penyamaran

by DriftGlider72
328 lines12.8 KB
▶ Play
<!DOCTYPE html>
<html lang="ms">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Galaksi Penyamaran</title>
    <style>
        * { margin:0; padding:0; box-sizing:border-box; font-family:Arial, sans-serif; touch-action: none; }
        body { 
            background: linear-gradient(180deg, #000022 0%, #220044 100%); 
            color:white; text-align:center; overflow:hidden; 
            height: 100vh; display: flex; flex-direction: column;
        }
        
        #skrinSoalan { 
            font-size: 20px; background:rgba(34, 68, 136, 0.8); 
            padding: 10px; margin: 5px auto; border-radius:8px; 
            width: 95%; border:2px solid #6699ff; font-weight:bold;
        }
        #status { 
            font-size: 18px; display:flex; justify-content:space-around; 
            margin: 5px auto; width: 90%; font-weight:bold;
        }
        #kawasanPermainan { 
            position:relative; width: 100%; flex-grow: 1;
            border-top:2px solid #555; overflow:hidden;
            background: radial-gradient(circle at top, #1a0033 0%, #000011 100%);
        }

        #kapal {
            position:absolute; bottom: 80px; left:50%; transform:translateX(-50%);
            width: 60px; height: 80px; font-size: 45px;
            transition:left 0.05s linear; filter:drop-shadow(0 0 8px #00ccff);
            z-index: 10;
        }

        .peluru {
            position:absolute; width: 8px; height: 22px; 
            background: linear-gradient(to top, #00ffff, #ffffff);
            border-radius:50%; box-shadow:0 0 10px #00ffff, 0 0 20px #00ffff;
            z-index: 15;
            pointer-events: none;
        }
        .kesan-letupan {
            position:absolute; width: 70px; height: 70px;
            background:radial-gradient(circle, #ffff00 0%, #ff6600 50%, transparent 70%);
            border-radius:50%; opacity:0; transform:scale(0);
            animation: meletup 0.4s forwards;
            z-index: 20;
            pointer-events: none;
        }
        @keyframes meletup {
            0% { transform:scale(0); opacity:1; }
            100% { transform:scale(2); opacity:0; }
        }

        .watak {
            position:absolute; width: 70px; height: 90px;
            font-size: 35px;
            display:flex; flex-direction:column; align-items:center;
            z-index: 5;
        }
        .kotak-jawapan {
            background:rgba(255,255,255,0.95); color:black;
            font-size: 18px; font-weight:bold; padding: 4px 6px;
            border-radius:5px; margin-bottom: 2px; min-width: 45px;
        }

        #sinarHijau {
            position:absolute; top:0; left:50%; transform:translateX(-50%);
            width: 10px; height: 100%; background:lime; opacity:0;
            box-shadow:0 0 20px lime, 0 0 40px lime;
            transition:opacity 0.4s; z-index:25;
        }
        #mesejTamat {
            position:absolute; top:50%; left:50%; transform:translate(-50%, -50%);
            font-size: 32px; font-weight:bold; display:none;
            background:rgba(0,0,0,0.85); padding: 20px 30px;
            border-radius:12px; border:3px solid white; z-index:30;
        }
        .bintang {
            position:absolute; background:white; border-radius:50%;
            animation:kelip 2s infinite; pointer-events: none;
        }
        @keyframes kelip { 0%,100% {opacity:0.3;} 50% {opacity:1;} }

        #kawalan {
            display: flex; justify-content: space-between; align-items: center;
            padding: 10px 20px; height: 80px; background: rgba(0,0,0,0.4);
        }
        .btn-kiriKanan, .btn-tembak {
            width: 70px; height: 60px; font-size: 25px; font-weight: bold;
            border: none; border-radius: 10px; background: rgba(102, 153, 255, 0.6);
            color: white; cursor: pointer; user-select: none;
        }
        .btn-kiriKanan:active, .btn-tembak:active { background: rgba(102, 153, 255, 0.9); transform: scale(0.95); }
        .kumpul-kiriKanan { display: flex; gap: 10px; }
    </style>
</head>
<body>

<div id="skrinSoalan">Soalan akan muncul di sini</div>
<div id="status">
    <div>🎯 Mata: <span id="nilaiMata">0</span>/100</div>
    <div>❤️ Nyawa: <span id="nilaiNyawa">3</span></div>
</div>

<div id="kawasanPermainan">
    <div id="kapal">🚀</div>
    <div id="sinarHijau"></div>
    <div id="mesejTamat"></div>
</div>

<div id="kawalan">
    <div class="kumpul-kiriKanan">
        <button class="btn-kiriKanan" id="btnKiri">⬅️</button>
        <button class="btn-kiriKanan" id="btnKanan">➡️</button>
    </div>
    <button class="btn-tembak" id="btnTembak">🔫 TEMBAK</button>
</div>

<script>
let mata = 0;
let nyawa = 3;
let soalanSemasa = {};
let kelajuanKapal = 6;
let peluruAktif = [];
let sasaranWatak = [];
let sedangGerakKiri = false;
let sedangGerakKanan = false;

const kapal = document.getElementById("kapal");
const kawasan = document.getElementById("kawasanPermainan");
const sinarHijau = document.getElementById("sinarHijau");
const mesejTamat = document.getElementById("mesejTamat");

// Bunyi ringkas
function mainBunyi(jenis){
    try {
        let bunyi = new AudioContext();
        let pembuat = bunyi.createOscillator();
        let isipadu = bunyi.createGain();
        pembuat.connect(isipadu); isipadu.connect(bunyi.destination);
        if(jenis === "tembak"){ pembuat.type="sawtooth"; pembuat.frequency.value=1200; isipadu.gain.setValueAtTime(0.1,bunyi.currentTime); isipadu.gain.exponentialRampToValueAtTime(0.01,bunyi.currentTime+0.1); pembuat.start(); pembuat.stop(bunyi.currentTime+0.1); }
        else if(jenis === "betul"){ pembuat.type="sine"; pembuat.frequency.value=523; isipadu.gain.setValueAtTime(0.15,bunyi.currentTime); pembuat.start(); pembuat.frequency.setValueAtTime(784,bunyi.currentTime+0.2); isipadu.gain.exponentialRampToValueAtTime(0.01,bunyi.currentTime+0.3); pembuat.stop(bunyi.currentTime+0.3); }
        else if(jenis === "salah"){ pembuat.type="square"; pembuat.frequency.value=200; isipadu.gain.setValueAtTime(0.12,bunyi.currentTime); isipadu.gain.exponentialRampToValueAtTime(0.01,bunyi.currentTime+0.3); pembuat.start(); pembuat.stop(bunyi.currentTime+0.3); }
    } catch(e){}
}

// Senarai Soalan Matematik Bab 3 Tingkatan 1
const senaraiSoalan = [
    {soalan:"2, 4, 6, 8, __ ?", betul:"10", salah:["9","12"]},
    {soalan:"3, 6, 9, 12, __ ?", betul:"15", salah:["14","18"]},
    {soalan:"5, 10, 15, 20, __ ?", betul:"25", salah:["22","30"]},
    {soalan:"1, 3, 5, 7, __ ?", betul:"9", salah:["8","11"]},
    {soalan:"2, 4, 8, 16, __ ?", betul:"32", salah:["20","24"]},
    {soalan:"1, 4, 9, 16, __ ?", betul:"25", salah:["20","23"]},
    {soalan:"1, 2, 4, 7, 11, __ ?", betul:"16", salah:["13","15"]},
    {soalan:"20, 18, 16, 14, __ ?", betul:"12", salah:["10","13"]},
    {soalan:"1, 3, 6, 10, __ ?", betul:"15", salah:["12","14"]},
    {soalan:"3, 5, __, 9, 11 ?", betul:"7", salah:["6","8"]},
    {soalan:"100, 90, 80, __ ?", betul:"70", salah:["60","75"]},
    {soalan:"2, 6, 18, 54, __ ?", betul:"162", salah:["108","72"]}
];

// Tambah Bintang Latar
function tambahBintang(){
    for(let i=0; i<30; i++){
        let bintang = document.createElement("div");
        bintang.className = "bintang";
        bintang.style.left = Math.random()*100 + "%";
        bintang.style.top = Math.random()*70 + "%";
        bintang.style.width = (1+Math.random()*2) + "px";
        bintang.style.height = bintang.style.width;
        kawasan.appendChild(bintang);
    }
}

// Kawalan Butang Skrin Sentuh
const btnKiri = document.getElementById("btnKiri");
const btnKanan = document.getElementById("btnKanan");
const btnTembak = document.getElementById("btnTembak");

btnKiri.addEventListener("touchstart", e=>{ e.preventDefault(); sedangGerakKiri = true; });
btnKiri.addEventListener("touchend", e=>{ e.preventDefault(); sedangGerakKiri = false; });
btnKanan.addEventListener("touchstart", e=>{ e.preventDefault(); sedangGerakKanan = true; });
btnKanan.addEventListener("touchend", e=>{ e.preventDefault(); sedangGerakKanan = false; });
btnTembak.addEventListener("touchstart", e=>{ e.preventDefault(); tembakPeluru(); });

// Kawalan Papan Kekunci
let kekunciDitekan = {};
document.addEventListener("keydown", e=>{ kekunciDitekan[e.code] = true; });
document.addEventListener("keyup", e=>{ kekunciDitekan[e.code] = false; });

// Fungsi Tembak
function tembakPeluru(){
    mainBunyi("tembak");
    let peluru = document.createElement("div");
    peluru.className = "peluru";
    let posisiKapal = kapal.offsetLeft + kapal.offsetWidth/2 - 4;
    peluru.style.left = posisiKapal + "px";
    peluru.style.bottom = "140px";
    kawasan.appendChild(peluru);
    peluruAktif.push(peluru);
}

// ✅ DIBAAKI: Bersihkan kawasan sepenuhnya sebelum buat pusingan baharu
function soalanBaharu(){
    // Simpan elemen yang perlu kekal
    const kapalSimpan = document.getElementById("kapal");
    const sinarSimpan = document.getElementById("sinarHijau");
    const mesejSimpan = document.getElementById("mesejTamat");
    
    // Kosongkan kawasan permainan
    kawasan.innerHTML = "";
    
    // Masukkan semula elemen penting
    kawasan.appendChild(kapalSimpan);
    kawasan.appendChild(sinarSimpan);
    kawasan.appendChild(mesejSimpan);
    
    sasaranWatak = [];
    peluruAktif = [];
    
    // Tambah semula bintang
    tambahBintang();

    // Pilih soalan baharu
    soalanSemasa = senaraiSoalan[Math.floor(Math.random()*senaraiSoalan.length)];
    document.getElementById("skrinSoalan").textContent = soalanSemasa.soalan;

    // Cipta sasaran baharu
    let senaraiJawapan = [soalanSemasa.betul, ...soalanSemasa.salah];
    senaraiJawapan.sort(()=> Math.random()-0.5);

    senaraiJawapan.forEach((jawapan, indeks)=>{
        let watak = document.createElement("div");
        watak.className = "watak";
        let lebarKawasan = kawasan.clientWidth;
        let jarak = lebarKawasan / 4;
        watak.style.left = (jarak * (indeks+1) - 35) + "px";
        watak.style.top = "40px";
        watak.innerHTML = `<div class='kotak-jawapan'>${jawapan}</div>👨‍🚀`;
        kawasan.appendChild(watak);
        sasaranWatak.push({elemen:watak, jawapan:jawapan});
    });
}

// Semak Pertembungan
function semakLindas(){
    peluruAktif = peluruAktif.filter(peluru=>{
        let posPeluru = peluru.getBoundingClientRect();
        let kena = false;

        sasaranWatak.forEach(sasaran=>{
            if(!sasaran.elemen) return;
            
            let posSasaran = sasaran.elemen.getBoundingClientRect();
            if(posPeluru.left < posSasaran.right && posPeluru.right > posSasaran.left &&
               posPeluru.top < posSasaran.bottom && posPeluru.bottom > posSasaran.top){
                kena = true; 
                peluru.remove();

                // Kesan letupan
                let letupan = document.createElement("div");
                letupan.className = "kesan-letupan";
                letupan.style.left = sasaran.elemen.offsetLeft + "px";
                letupan.style.top = sasaran.elemen.offsetTop + "px";
                kawasan.appendChild(letupan); 
                setTimeout(()=> letupan.remove(), 400);

                // Semak jawapan
                if(sasaran.jawapan === soalanSemasa.betul){ 
                    mata += 10; 
                    mainBunyi("betul"); 
                    if(mata>=100) return tamatPermainan(true);
                } else { 
                    nyawa--; 
                    mainBunyi("salah"); 
                    if(nyawa<=0) return tamatPermainan(false);
                }

                kemasKiniStatus();
                soalanBaharu(); // Pusingan baharu terus dimulakan
            }
        });

        if(!kena){
            let btm = parseInt(peluru.style.bottom || 140);
            peluru.style.bottom = (btm + 10) + "px";
            if(btm > kawasan.clientHeight) peluru.remove();
        } 
        return !kena;
    });
}

// Gelung Utama
function larianUtama(){
    if(sedangGerakKiri || kekunciDitekan["ArrowLeft"]) if(kapal.offsetLeft > 5) kapal.style.left = (kapal.offsetLeft - kelajuanKapal) + "px";
    if(sedangGerakKanan || kekunciDitekan["ArrowRight"]) if(kapal.offsetLeft < kawasan.clientWidth - 65) kapal.style.left = (kapal.offsetLeft + kelajuanKapal) + "px";
    if(kekunciDitekan["Space"]) tembakPeluru();
    semakLindas();
    requestAnimationFrame(larianUtama);
}

// Tamat Permainan
function tamatPermainan(menang){
    if(!menang){ 
        sinarHijau.style.opacity = "0.9"; 
        mesejTamat.style.display = "block"; 
        mesejTamat.innerHTML = "💥 Ditembak Sinar Hijau!<br>Kalah..."; 
    } else { 
        mesejTamat.style.display = "block"; 
        mesejTamat.innerHTML = "🎉 MISI BERJAYA!<br>Anda Menang!"; 
    }
}

function kemasKiniStatus(){
    document.getElementById("nilaiMata").textContent = mata;
    document.getElementById("nilaiNyawa").textContent = nyawa;
}

// Mula Permainan
soalanBaharu();
larianUtama();
</script>
</body>
</html>

Game Source: Galaksi Penyamaran

Creator: DriftGlider72

Libraries: none

Complexity: complex (328 lines, 12.8 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: galaksi-penyamaran-driftglider72-mr4htm3z" to link back to the original. Then publish at arcadelab.ai/publish.