<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>HTML5 릴게임</title>
<style>
:root {
--bg:#0e0f13; --panel:#1b1e25; --accent:#ffcc00; --text:#e9edf1; --muted:#9aa3ad;
}
body {
margin:0; min-height:100vh; display:flex; align-items:center; justify-content:center;
background:radial-gradient(1200px 600px at 50% 30%, #151822 0%, #0d0f14 60%, #07080b 100%);
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
color:var(--text);
}
.game {
width:min(520px, 92vw); background:linear-gradient(#21242c, #191c23);
border:1px solid #2b2f39; border-radius:18px; box-shadow:0 18px 40px rgba(0,0,0,.5);
overflow:hidden;
}
.header {
padding:16px 20px; display:flex; justify-content:space-between; align-items:center;
background:#14171d;
border-bottom:1px solid #232733;
}
.title { font-weight:700; letter-spacing:.4px; }
.balance { font-size:14px; color:var(--muted); }
.reels {
display:grid; grid-template-columns:repeat(3, 1fr); gap:14px; padding:20px;
}
.reel {
height:160px; background:linear-gradient(#111318, #0c0e12); border:1px solid #2a2e39;
border-radius:12px; position:relative; overflow:hidden;
box-shadow: inset 0 0 0 1px #1f2330, inset 0 8px 18px rgba(0,0,0,.35);
}
.strip {
position:absolute; left:0; right:0; top:0;
display:flex; flex-direction:column; align-items:center; gap:10px; padding:10px 0;
transition: transform cubic-bezier(.2,.8,.2,1);
}
.symbol {
width:100%; height:70px; display:flex; align-items:center; justify-content:center;
font-size:42px; filter: drop-shadow(0 2px 1px rgba(0,0,0,.35));
user-select:none;
}
.controls {
padding:14px 20px; display:flex; gap:10px; align-items:center; border-top:1px solid #232733;
background:#14171d;
}
button {
flex:1; padding:12px 14px; border:none; border-radius:10px; font-weight:700;
background:linear-gradient(180deg, #ffd54d, #ffb300); color:#241a00;
box-shadow:0 8px 16px rgba(255, 179, 0, .25); cursor:pointer;
}
button:disabled {
background:#3c3f49; color:#9aa3ad; box-shadow:none; cursor:not-allowed;
}
.bet {
display:flex; align-items:center; gap:8px;
padding:10px 12px; border-radius:10px; background:#1b1f2a; color:var(--muted);
}
.msg {
padding:10px 20px; font-weight:600; min-height:28px; color:#9dd7ff;
}
.win {
animation: flash 900ms ease-in-out 2;
}
@keyframes flash {
0% { color:#9dd7ff; }
50% { color:#79ff9d; text-shadow:0 0 12px rgba(121,255,157,.65); }
100% { color:#9dd7ff; }
}
</style>
</head>
<body>
<div class="game">
<div class="header">
<div class="title">릴 게임 · Lucky Reels</div>
<div class="balance">잔액: <span id="balance">1000</span> 코인</div>
</div>
<div class="reels" id="reels">
<div class="reel"><div class="strip"></div></div>
<div class="reel"><div class="strip"></div></div>
<div class="reel"><div class="strip"></div></div>
</div>
<div class="msg" id="msg"></div>
<div class="controls">
<div class="bet">베팅: <strong id="bet">50</strong> 코인</div>
<button id="spinBtn">SPIN</button>
</div>
</div>
<script>
(() => {
// 심볼 목록 (이모지라서 별도 이미지 없이 바로 사용)
const SYMBOLS = ['🍒','🍋','🍀','⭐','🔔','7️⃣','💎'];
const reels = [...document.querySelectorAll('.strip')];
const spinBtn = document.getElementById('spinBtn');
const msg = document.getElementById('msg');
const balanceEl = document.getElementById('balance');
const betEl = document.getElementById('bet');
let balance = 1000;
let bet = 50;
let spinning = false;
// 초기 스트립 구성
function buildStrip(strip) {
strip.innerHTML = '';
// 가시성 확보를 위해 20칸 정도 구성
const pool = [];
for (let i = 0; i < 20; i++) {
const sym = SYMBOLS[Math.floor(Math.random() * SYMBOLS.length)];
pool.push(sym);
}
pool.forEach(s => {
const el = document.createElement('div');
el.className = 'symbol';
el.textContent = s;
strip.appendChild(el);
});
// 시작 위치 랜덤
const start = -(Math.floor(Math.random() * (pool.length - 3)) * 80);
strip.style.transform = `translateY(${start}px)`;
}
reels.forEach(buildStrip);
function setMessage(text, winning=false) {
msg.textContent = text;
msg.classList.toggle('win', winning);
}
function updateBalance(diff) {
balance += diff;
balanceEl.textContent = balance;
if (balance <= 0) {
spinBtn.disabled = true;
setMessage('잔액이 없습니다. 새로고침으로 초기화하세요.');
}
}
// 스핀 로직
async function spin() {
if (spinning) return;
if (balance < bet) { setMessage('잔액이 부족합니다. 베팅을 줄이거나 초기화하세요.'); return; }
spinning = true;
spinBtn.disabled = true;
setMessage('회전 중...');
updateBalance(-bet);
// 각 릴에 서로 다른 지속시간과 감속 적용
const durations = [900, 1100, 1300];
const results = [];
await Promise.all(reels.map((strip, i) => new Promise(resolve => {
const total = strip.children.length;
// 목표 인덱스(중앙에 멈출 심볼)
const targetIndex = Math.floor(Math.random() * (total - 2)) + 1; // 1~(total-2)
const targetY = -(targetIndex * 80 - 40); // 중앙 보정
strip.style.transitionDuration = durations[i] + 'ms';
strip.style.transform = `translateY(${targetY}px)`;
strip.addEventListener('transitionend', function handler() {
strip.removeEventListener('transitionend', handler);
// 중앙, 윗, 아래 심볼 추출 (중앙 기준)
const center = strip.children[targetIndex].textContent;
results[i] = center;
resolve();
}, { once:true });
})));
// 결과 판정
const [a,b,c] = results;
let payout = 0;
let text = `결과: ${a} | ${b} | ${c}`;
const allSame = (a === b && b === c);
const twoSame = (a === b || b === c || a === c);
if (allSame) {
// 심볼 별 배당
const multiplier = ({
'🍒': 4, '🍋': 4, '🍀': 6, '⭐': 8, '🔔': 10, '7️⃣': 20, '💎': 25
})[a] || 4;
payout = bet * multiplier;
updateBalance(payout);
setMessage(`${text} · 대박! 배당 x${payout / bet} → +${payout} 코인`, true);
} else if (twoSame) {
payout = Math.floor(bet * 1.5);
updateBalance(payout);
setMessage(`${text} · 2개 일치! +${payout} 코인`, true);
} else {
setMessage(`${text} · 꽝! -${bet} 코인`);
}
spinning = false;
spinBtn.disabled = balance <= 0;
}
spinBtn.addEventListener('click', spin);
// 모바일 더블탭 방지, 터치도 클릭과 동일 처리
spinBtn.addEventListener('touchend', (e) => { e.preventDefault(); spin(); }, { passive:false });
// 간단한 베팅 조절: 버튼 길게 누르면 베팅 증가/감소 아이디어 (옵션)
// 키보드 지원
window.addEventListener('keydown', (e) => {
if (e.key === ' ' || e.key.toLowerCase() === 's') spin();
if (e.key === 'ArrowUp') { bet = Math.min(bet + 10, 200); betEl.textContent = bet; }
if (e.key === 'ArrowDown') { bet = Math.max(bet - 10, 10); betEl.textContent = bet; }
});
// 처음 안내
setMessage('SPIN 버튼 또는 스페이스바로 시작하세요. 화살표로 베팅 조절.');
})();
</script>
</body>
</html>

'PHP Tip' 카테고리의 다른 글
| 외부사이트 가져오기 curl 기본 설명 파싱(parsing) (0) | 2025.12.20 |
|---|---|
| DB 없이 chatbot 간단하게 만들기 (0) | 2025.12.20 |
| /* 페이징 스타일 복원 + 반응형 */ (0) | 2025.12.18 |
| 오버레이가 있는 반응형 이미지 갤러리(그누보드) (0) | 2025.12.17 |
| 쿠키 값으로 방문자 횟수 표시 (1) | 2025.12.16 |