Untitled
1 hour ago in Plain Text
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Bee Collector — Mini Game</title>
<style>
:root{
--bg:#e8f7ff;
--panel:#ffffffcc;
--accent:#ffcc00;
--muted:#666;
}
html,body{height:100%;margin:0;font-family:Inter,system-ui,Segoe UI,Roboto,Arial;}
body{display:flex;align-items:center;justify-content:center;background:linear-gradient(180deg,var(--bg),#bfefff);}
#game-wrap{width:min(920px,96vw);height:min(680px,86vh);box-shadow:0 18px 40px rgba(10,30,60,0.12);border-radius:14px;overflow:hidden;background:var(--panel);display:grid;grid-template-rows:64px 1fr;}
header{display:flex;align-items:center;gap:12px;padding:12px 18px;border-bottom:1px solid #00000008;}
.title{font-weight:700;font-size:18px;color:#0b3b5a}
.hud{margin-left:auto;display:flex;gap:12px;align-items:center;color:var(--muted)}
.btn{background:#0b84ff;color:white;padding:8px 12px;border-radius:8px;border:0;cursor:pointer;font-weight:600}
#canvas-wrap{position:relative;background:linear-gradient(180deg,#98d9ff, #cfeeff);display:flex;align-items:center;justify-content:center}
canvas{background:transparent;max-width:100%;height:auto;border-radius:0;display:block}
.panel-bottom{position:absolute;left:10px;bottom:10px;background:#ffffffdd;padding:8px 10px;border-radius:8px;backdrop-filter:blur(4px);box-shadow:0 6px 18px rgba(10,30,60,0.06)}
.small{font-size:13px;color:#234}
.bigscore{font-weight:800;font-size:20px;color:#0b3b5a}
.overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none}
.center-card{pointer-events:auto;background:rgba(255,255,255,0.95);padding:18px;border-radius:12px;box-shadow:0 12px 30px rgba(10,30,60,0.12);text-align:center}
.controls{display:flex;gap:8px;justify-content:center;margin-top:10px}
.muted-note{font-size:12px;color:#567}
</style>
</head>
<body>
<div id="game-wrap" role="application" aria-label="Bee Collector game">
<header>
<div class="title">Bee Collector</div>
<div class="hud">
<div id="level">Level: 1</div>
<div id="score">Score: 0</div>
<button id="restart" class="btn">Restart</button>
</div>
</header>
<div id="canvas-wrap">
<canvas id="game" width="900" height="560" aria-label="game canvas"></canvas>
<div class="panel-bottom small">
<div>Controls: A / D or ← → to move • Space to dash</div>
</div>
<div id="start-overlay" class="overlay">
<div class="center-card" id="menu">
<h2>Selamat datang!</h2>
<p class="muted-note">Kumpulkan lebah sebanyak-banyaknya. Setiap lebah memberi skor dan menambah tantangan.</p>
<div class="controls">
<button id="startBtn" class="btn">Mulai</button>
<button id="how" class="btn" style="background:#6c757d">Cara main</button>
</div>
</div>
</div>
<div id="game-over" class="overlay" style="display:none">
<div class="center-card">
<h3>Game Over</h3>
<p id="final-score">Skor: 0</p>
<div class="controls">
<button id="tryagain" class="btn">Main Lagi</button>
</div>
</div>
</div>
</div>
</div>
<script>
/* --- Bee Collector: simple canvas game --- */
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
let keys = {};
let score = 0;
let level = 1;
let bees = [];
let particles = [];
let running = false;
let spawnTimer = 0;
const player = {
x: W/2, y: H-100, r: 18, speed: 3.6, vx: 0, dashCooldown:0
};
function rand(min,max){return Math.random()*(max-min)+min}
function dist(a,b){return Math.hypot(a.x-b.x,a.y-b.y)}
function spawnBee(){
const side = Math.random() < 0.5 ? -40 : W+40;
const y = rand(60, H-160);
const vx = side < 0 ? rand(1,2)+level*0.2 : rand(-2,-1)-level*0.2;
const b = {
x: side, y, vx,
r: rand(10,18),
wobble: rand(0,Math.PI*2),
value: 1 + Math.floor(level/3)
};
bees.push(b);
}
function update(dt){
if(!running) return;
// player movement
let move = 0;
if(keys['ArrowLeft']||keys['a']) move -= 1;
if(keys['ArrowRight']||keys['d']) move += 1;
player.vx += (move*player.speed - player.vx) * 0.2;
player.x += player.vx;
player.x = Math.max(20, Math.min(W-20, player.x));
// dash (space)
if(keys[' '] && player.dashCooldown <= 0){
player.x += (player.vx >= 0 ? 120 : -120);
player.dashCooldown = 1.2;
spawnParticles(player.x, player.y, 12);
}
player.dashCooldown = Math.max(0, player.dashCooldown - dt);
// bees
for(let i=bees.length-1;i>=0;i--){
const b = bees[i];
b.x += b.vx;
b.wobble += dt*4;
b.y += Math.sin(b.wobble)*0.6;
// collect
const d = Math.hypot(player.x - b.x, player.y - b.y);
if(d < player.r + b.r){
score += b.value;
spawnParticles(b.x,b.y,8);
bees.splice(i,1);
} else if(b.x < -80 || b.x > W+80){
bees.splice(i,1);
}
}
// spawn logic: faster spawn with level
spawnTimer -= dt;
if(spawnTimer <= 0){
spawnTimer = Math.max(0.15, 0.8 - level*0.05);
spawnBee();
if(Math.random() < 0.3 && bees.length< 8 + level) spawnBee();
}
// particles
for(let i=particles.length-1;i>=0;i--){
const p = particles[i];
p.x += p.vx; p.y += p.vy; p.life -= dt;
p.vy += 70*dt;
if(p.life<=0) particles.splice(i,1);
}
// level up every 10 score
const newLevel = Math.floor(score/10) + 1;
if(newLevel > level){
level = newLevel;
// spawn bonus bees on level up
for(let i=0;i<Math.min(6, level);i++) spawnBee();
}
// lose condition (too many bees)
if(bees.length > 30) endGame();
}
function draw(){
// background sky (subtle gradient)
ctx.clearRect(0,0,W,H);
// ground
ctx.fillStyle = '#8ed0ff';
ctx.fillRect(0,H-60,W,60);
// draw flowers on ground
for(let x=30; x<W; x+=80){
const hx = (x + (Math.sin(x*0.03 + Date.now()*0.0005)*12));
ctx.fillStyle = '#2e8b57';
ctx.fillRect(hx, H-60, 6, 20);
// petals
ctx.beginPath();
ctx.fillStyle = '#ff6699';
ctx.ellipse(hx+6, H-68, 8,6,0,0,Math.PI*2);
ctx.fill();
}
// draw bees
for(const b of bees){
drawBee(b.x,b.y,b.r);
}
// draw player
ctx.save();
ctx.translate(player.x, player.y);
// body
ctx.beginPath();
ctx.fillStyle = '#0b3b5a';
ctx.ellipse(0,0,player.r,player.r*0.85,0,0,Math.PI*2);
ctx.fill();
// yellow belly
ctx.beginPath();
ctx.fillStyle = '#ffdd33';
ctx.ellipse(-4,0,player.r*0.6,player.r*0.5,0,0,Math.PI*2);
ctx.fill();
// eyes
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(6,-6,4,0,Math.PI*2); ctx.fill();
ctx.fillStyle = '#000'; ctx.beginPath(); ctx.arc(7,-6,2,0,Math.PI*2); ctx.fill();
ctx.restore();
// particles
for(const p of particles){
ctx.globalAlpha = Math.max(0, p.life / p.maxLife);
ctx.beginPath();
ctx.fillStyle = p.color;
ctx.arc(p.x,p.y,p.size,0,Math.PI*2);
ctx.fill();
ctx.globalAlpha = 1;
}
// UI (top-left small)
ctx.fillStyle = '#044a6d';
ctx.font = '18px Inter, Arial';
ctx.fillText(`Score: ${score}`, 14, 26);
ctx.fillText(`Level: ${level}`, 14, 48);
}
function drawBee(x,y,r){
// wings
ctx.beginPath();
ctx.fillStyle = 'rgba(255,255,255,0.9)';
ctx.ellipse(x - r*0.5, y - r*0.8, r*0.7, r*0.45, 0, 0, Math.PI*2);
ctx.ellipse(x + r*0.5, y - r*0.8, r*0.7, r*0.45, 0, 0, Math.PI*2);
ctx.fill();
// body
ctx.beginPath();
ctx.fillStyle = '#222';
ctx.ellipse(x,y,r,r*0.7,0,0,Math.PI*2);
ctx.fill();
// stripes
ctx.fillStyle = '#ffd23f';
ctx.fillRect(x-r*0.6, y-r*0.2, r*1.2, r*0.4);
// eye
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(x + r*0.4, y - r*0.1, r*0.2,0,Math.PI*2); ctx.fill();
ctx.fillStyle = '#000'; ctx.beginPath(); ctx.arc(x + r*0.45, y - r*0.1, r*0.09,0,Math.PI*2); ctx.fill();
}
function spawnParticles(x,y,count){
for(let i=0;i<count;i++){
particles.push({
x, y,
vx: rand(-120,120)/60,
vy: rand(-200, -30)/60,
size: rand(1,4),
color: ['#ffdd55','#ff9a9a','#fff'][Math.floor(Math.random()*3)],
life: rand(0.4,0.9),
maxLife: 1
});
}
}
let last = performance.now();
function loop(t){
const dt = Math.min(0.033, (t-last)/1000);
update(dt);
draw();
last = t;
requestAnimationFrame(loop);
}
function startGame(){
// reset state
score = 0; level = 1; bees = []; particles = [];
player.x = W/2; player.y = H-120; player.vx = 0; player.dashCooldown = 0;
spawnTimer = 0.15;
running = true;
document.getElementById('start-overlay').style.display = 'none';
document.getElementById('game-over').style.display = 'none';
document.getElementById('score').innerText = `Score: ${score}`;
document.getElementById('level').innerText = `Level: ${level}`;
}
function endGame(){
running = false;
document.getElementById('final-score').innerText = `Skor: ${score}`;
document.getElementById('game-over').style.display = 'flex';
}
document.addEventListener('keydown', e=>{
keys[e.key] = true;
if(e.key === 'p') {
running = !running;
document.getElementById('start-overlay').style.display = running ? 'none' : 'flex';
}
});
document.addEventListener('keyup', e=>{
keys[e.key] = false;
});
document.getElementById('startBtn').addEventListener('click', ()=> startGame());
document.getElementById('restart').addEventListener('click', ()=> startGame());
document.getElementById('tryagain').addEventListener('click', ()=> startGame());
document.getElementById('how').addEventListener('click', ()=> {
alert("Cara main:\n- A / ← : bergerak ke kiri\n- D / → : bergerak ke kanan\n- Space : dash (cooldown)\nTujuan: kumpulkan lebah sebanyak mungkin sebelum arena penuh.");
});
// update HUD regularly
setInterval(()=>{
document.getElementById('score').innerText = `Score: ${score}`;
document.getElementById('level').innerText = `Level: ${level}`;
}, 200);
// start animation
requestAnimationFrame(loop);
</script>
</body>
</html>