콤보 카운터

Combo Counter

연속으로 성공한 타격 수를 숫자로 키워가며 보여주다가, 일정 시간 안에 다음 타격이 없으면 끊기고 0으로 리셋되는 카운터.

다른 이름: 콤보 게이지Combo meter연속 타격 카운터
···
html
<div class="ccwrap"><div class="ccnum" id="ccnum">0</div><div class="cclabel">COMBO</div><div class="ccbar"><div class="ccfill" id="ccfill"></div></div></div>
css
.ccwrap{display:flex;flex-direction:column;align-items:center;gap:4px}
.ccnum{font:900 clamp(30px,13vmin,56px)/1 monospace;color:var(--fg);transition:transform .12s cubic-bezier(.3,1.6,.4,1),color .2s}
.ccnum.hit{transform:scale(1.25)}
.ccnum.hi{color:var(--accent-2)}
.cclabel{font:700 clamp(8px,2.4vmin,10px) monospace;color:var(--muted);letter-spacing:.15em}
.ccbar{width:min(60%,140px);height:4px;border-radius:2px;background:color-mix(in srgb,var(--fg) 14%,transparent);overflow:hidden;margin-top:2px}
.ccfill{height:100%;width:100%;background:var(--accent);transform-origin:left;transition:transform linear}
js
const num=document.getElementById('ccnum');
const fill=document.getElementById('ccfill');
const WINDOW_MS=850;
let combo=0;
function hit(){
  combo++;
  num.textContent=combo;
  num.classList.remove('hit'); void num.offsetWidth; num.classList.add('hit');
  num.classList.toggle('hi', combo>=8);
  fill.style.transition='none';
  fill.style.transform='scaleX(1)';
  requestAnimationFrame(function(){
    fill.style.transition='transform '+WINDOW_MS+'ms linear';
    fill.style.transform='scaleX(0)';
  });
}
function breakCombo(){
  num.style.transition='transform .3s ease-in, opacity .3s ease-in';
  num.style.transform='scale(0.6) rotate(-8deg)';
  num.style.opacity='0.3';
  setTimeout(function(){
    combo=0;
    num.textContent='0';
    num.classList.remove('hi');
    num.style.transform='scale(1) rotate(0deg)';
    num.style.opacity='1';
    fill.style.transition='none';
    fill.style.transform='scaleX(0)';
  }, 320);
}
const pattern=[260,240,260,230,240,WINDOW_MS+150,260,240,260,230,240,230,220,WINDOW_MS+400];
let pi=0;
function loop(){
  const gap=pattern[pi%pattern.length];
  if(gap>WINDOW_MS) breakCombo(); else hit();
  pi++;
  setTimeout(loop, gap);
}
setTimeout(loop, 500);

콤보 카운터는 숫자와 타이머 두 부분으로 이뤄진다. 숫자는 맞을 때마다 올라가며 그때마다 스케일이 펀치처럼 커졌다 줄어들어 "카운트가 오른다"는 것 자체가 보상처럼 느껴지게 한다. 타이머(보통 원형 게이지나 얇은 바)는 다음 타격이 그 시간 안에 들어와야 콤보가 이어진다는 압박을 시각적으로 보여준다.

콤보 수가 일정 구간을 넘으면(10, 20, 50 등) 색이 바뀌거나 글자가 커지는 식으로 등급을 매기는 경우가 많다 — 이는 목표 그라데이션 효과(목표에 가까워질수록 노력이 커진다)를 활용해 콤보를 이어가고 싶은 동기를 강화한다.

콤보가 끊기는 순간의 연출도 중요하다 — 숫자가 아무 반응 없이 사라지면 허무하고, 반대로 무너지듯 튕기거나 흔들리며 사라지면 "콤보가 끊겼다"는 것이 실패로서 명확히 체감된다. 다만 끊김 연출이 과하면 오히려 짜증을 유발하므로 가볍게 처리한다.

언제 쓰나

연속 입력·연속 타격에 보상이 있는 액션·리듬 게임. 단발성 판정만 있는 게임에는 불필요.