GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

css snake game 9가지 — 키보드 없이 길을 찾아 먹이를 먹는 뱀 게임

css snake game 을 열면 키보드를 누르기도 전에 뱀이 먹이 쪽으로 돌아 나간다 — 01번 최단 경로와 02번 해밀턴 순환이 그 한 수를 계산으로 정한다.

아홉 가지 뱀 게임을 화면에서 바로 돌려 본다

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

css snake game 9가지 — 길찾기·순환·보간으로 뱀이 스스로 움직인다

판은 캔버스에 그리고 화면 틀은 CSS 가 잡는다. 칸과 뱀과 먹이를 칠하고 다음 한 수를 정하는 일은 index.html 의 자바스크립트가 하고, CSS 는 무대 크기와 그 위에 얹힌 상태 알약·캡션·버튼, 키보드 포커스 외곽선을 맡는다. 무대 폭은 min(92vw, calc(160vh - 12.8vw)), 비율은 480:300, 모서리는 16px 이다.

캔버스 안쪽 해상도는 480×300 에 devicePixelRatio(최대 2)를 곱한 값이라 창 크기가 바뀌어도 판의 칸 수는 그대로다. 칸은 makeBoard(GRID_N) 이 정한다. 줄 수가 16 이면 칸이 18.75px, 가로 25칸 × 세로 16칸으로 400칸이 되고, 12 이면 25px 칸 228칸, 8 이면 37.5px 칸 96칸이다.

시간은 16ms 고정 스텝으로 흐른다. 장면마다 스텝을 모았다가 TICK_MS 가 찰 때 논리 틱을 한 번 돌리고 그림은 프레임당 한 번만 그린다. 난수는 시드를 고정한 lcg 뿐이라 먹이 자리가 매번 같고, 01·02·03·05·06·07·08 일곱 장면은 숨은 워밍 틱을 먼저 돌려 중반 상태에서 열린다. 01 은 길이 54, 02 는 91/96칸, 08 은 점수 0070·길이 10, 07 은 길이 11 이고 04 와 09 는 처음부터 보인다.

아홉 장면은 뱀이 무엇을 계산하느냐로 나눠 놓았다. 01·02 는 다음 한 칸을 고르는 판단이고, 03·04 는 같은 이동을 몸통으로 그리는 두 방식이다. 05·07·09 는 칸이나 몸에 값을 칠하는 장면이고, 06 은 판의 모양을 바꾸고 08 은 먹는 순간의 반응을 붙인다.

어디에 붙일지는 쓰임으로 고르면 빠르다. 자동 플레이 데모나 AI 대전 미리보기라면 01, 엔딩 없는 대기 화면이라면 02, 부드러운 모션이 중요한 모바일 화면이라면 03, 자유 이동 벌레 캐릭터라면 04 에서 시작한다. 플레이 기록 시각화는 05, 벽 없는 맵은 06, 스킨 상점 미리보기는 07, 점수 보상 HUD 는 08, 길찾기 설명 화면은 09 가 맞다.

사람이 방향키로 조작하는 쪽이 먼저 필요하다면 웹 미니게임 만들기 9종 — 계산기·타이머·퍼즐 복붙 코드나 CSS 게임 만들기 — 미니게임 9종 복붙 코드가 맞다. 이 편은 사람이 손대지 않아도 뱀이 스스로 길을 찾는 쪽이다.

snake game using html css and javascript 를 기법별 코드로 본다

각 항목의 코드는 index.html 의 <script> 에서 연속된 줄을 그대로 잘라 붙였고, 한 조각은 25줄을 넘지 않는다. snake game using html css and javascript 는 방향키 입력과 충돌 검사부터 찾게 되는 주제인데, 이 아홉 장면은 입력 대신 판단과 그림 쪽 계산을 코드로 보여 준다.

01너비 우선 탐색으로 먹이까지 최단 경로를 잡고 막다른 길이면 꼬리를 쫓는 뱀

매 틱 먹이에서 너비 우선으로 거리를 채워 머리가 갈 최단 길을 뽑고, simulate 가 그 길을 끝까지 걸은 가상의 몸을 만든다. tailReachable 이 가상 머리에서 가상 꼬리까지 닿는지 보고, 막히면 그 길을 버려(분홍 선) 꼬리를 쫓는다. 캡처 24장에서 잰 값은 누적면적 49.8%, 평균 강도 114.0, 움직인 프레임 23/23 이다.

너비 우선 탐색으로 먹이까지 최단 경로를 잡고 막다른 길이면 꼬리를 쫓는 뱀
새 창에서 열기

01 · 너비 우선 탐색으로 먹이까지 최단 경로를 잡고 막다른 길이면 꼬리를 쫓는 뱀 — 측정 누적면적 49.751% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

TICK_MSGRID_NSAFE_CHECKREJECT_LIFE
        if (g.food >= 0) {
            const dist = distField(b, g.food, blocked, g.wrap);
            const path = pathFrom(b, dist, head, g.wrap);
            plan.path = path;
            if (path.length > 0) {
                if (!safeOn) {
                    plan.next = path[0];
                    return plan;
                }
                const v = simulate(g.body, path);
                if (tailReachable(b, v, g.wrap, plan.trap)) {
                    plan.next = path[0];
                    return plan;
                }
                plan.rejected = path;
            }
        }

02판 전체를 한 바퀴 도는 해밀턴 순환으로 판을 끝까지 채우는 뱀

판의 모든 칸을 한 번씩 지나는 고정 순환에 ord 로 번호를 매기고, 이웃 중 먹이에 가까우면서 꼬리를 앞지르지 않는 칸이 있으면 순환 순서를 건너뛴다. 시작은 숨은 틱으로 91/96칸을 채운 상태라 약 10틱 뒤 판이 가득 차고, 14틱 멈춘 다음 새 판이 열린다. 누적면적 61.4%, 평균 강도 90.0 이고 움직인 프레임이 17/23 인 것은 가득 찬 판이 멈춰 있는 동안 화면이 같기 때문이다.

판 전체를 한 바퀴 도는 해밀턴 순환으로 판을 끝까지 채우는 뱀
새 창에서 열기

02 · 판 전체를 한 바퀴 도는 해밀턴 순환으로 판을 끝까지 채우는 뱀 — 측정 누적면적 61.428% · 움직인 프레임 17/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

GRID_NSHORTCUT_MARGINTICK_MSWARM_FILL
            let best = cyc[(ord[head] + 1) % N];
            let bestD = 1;
            for (let d = 0; d < 4; d += 1) {
                const nb = neighborCell(b, head, d, false);
                if (nb < 0 || occupied[nb] === 1 || nb === tail) {
                    continue;
                }
                const dc = cd(head, nb);
                if (dc > bestD && dc <= foodD && dc < tailD - SHORTCUT_MARGIN) {
                    best = nb;
                    bestD = dc;
                }
            }
            if (bestD > 1) {
                cuts += 1;
                jump = 6;
            }
            moveSnake(g, best);

03틱 사이를 보간해 칸이 아니라 픽셀 단위로 미끄러지는 뱀 몸통

논리는 100ms 틱으로 칸을 한 칸씩 옮기고, 그리는 자리 px·py 는 16ms 스텝마다 논리 칸 중심으로 BODY_LERP 0.35 만큼 다가간다. 탭을 누르면 보간이 꺼져 몸이 칸 중심에 바로 붙으므로 크림색 윤곽 사각형(논리 칸)과 굵은 몸통을 번갈아 비교할 수 있다. 이 장면의 값은 누적면적 18.5%, 평균 강도 78.6, 움직인 프레임 23/23 이다.

틱 사이를 보간해 칸이 아니라 픽셀 단위로 미끄러지는 뱀 몸통
새 창에서 열기

03 · 틱 사이를 보간해 칸이 아니라 픽셀 단위로 미끄러지는 뱀 몸통 — 측정 누적면적 18.462% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

BODY_LERPTICK_MSTUBE_FRACTRAIL_LEN
                // 그리는 자리가 논리 칸 자리를 BODY_LERP 만큼씩 따라간다
                for (let i = 0; i < g.body.length; i += 1) {
                    const tx = cellX(b, g.body[i]);
                    const ty = cellY(b, g.body[i]);
                    if (smoothOn) {
                        px[i] = lerp(px[i], tx, BODY_LERP);
                        py[i] = lerp(py[i], ty, BODY_LERP);
                    }
                    else {
                        px[i] = tx;
                        py[i] = ty;
                    }
                }

04칸 없이 머리를 따라 거리 제약으로 끌려오는 사슬 몸통의 뱀

칸이 없고 머리만 ang 방향으로 직접 움직인다. 머리 뒤로 이어지는 마디(처음 26마디 중 머리를 뺀 25개, 먹이를 먹으면 늘어난다)는 이전 위치와의 차이(관성)에 DAMP 0.97 을 곱해 나아간 뒤 이웃 마디 간격을 9px 로 되돌리는 제약을 4번 푼다. 누적면적은 7.7% 로 아홉 중 가장 작고 평균 강도 50.4, 움직인 프레임 23/23 이다.

칸 없이 머리를 따라 거리 제약으로 끌려오는 사슬 몸통의 뱀
새 창에서 열기

04 · 칸 없이 머리를 따라 거리 제약으로 끌려오는 사슬 몸통의 뱀 — 측정 누적면적 7.728% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

SEG_GAPSTEER_RATESEG_COUNTFOLLOW_ITER
                // 거리 제약: 이웃 마디와의 간격을 SEG_GAP 으로 되돌린다
                for (let it = 0; it < FOLLOW_ITER; it += 1) {
                    for (let i = 1; i < count; i += 1) {
                        const dx = px[i] - px[i - 1];
                        const dy = py[i] - py[i - 1];
                        const d = Math.sqrt(dx * dx + dy * dy) || 0.0001;
                        const k = ((d - SEG_GAP) / d) * FOLLOW_STIFF;
                        if (i === 1) {
                            px[i] -= dx * k;
                            py[i] -= dy * k;
                        }
                        else {
                            px[i] -= dx * k * 0.5;
                            py[i] -= dy * k * 0.5;
                            px[i - 1] += dx * k * 0.5;
                            py[i - 1] += dy * k * 0.5;
                        }
                    }
                }

05지나간 칸에 열이 남았다가 식으며 이동 경로를 그리는 뱀

머리가 새 칸에 닿을 때 그 칸의 heat 에 1 을 더하고(최대 1.4), 매 16ms 스텝 모든 칸에 0.988 을 곱해 식힌다. 곱셈 하나라 반감기가 약 57스텝(0.92초)이고, heatColor 가 값을 7단계로 끊어 보라에서 크림까지 칠한다. 누적면적 22.8%, 평균 강도 62.6, 움직인 프레임 23/23 으로 잡혔다.

지나간 칸에 열이 남았다가 식으며 이동 경로를 그리는 뱀
새 창에서 열기

05 · 지나간 칸에 열이 남았다가 식으며 이동 경로를 그리는 뱀 — 측정 누적면적 22.775% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

HEAT_DECAYHEAT_GAINGRID_NPALETTE_STEPS
    function heatColor(h, steps) {
        let v = clamp(h, 0, 1);
        if (steps > 0) {
            v = Math.floor(v * steps) / steps;
        }
        const f = v * (RAMP.length - 1);
        const i = Math.min(RAMP.length - 2, Math.floor(f));
        return mix(RAMP[i], RAMP[i + 1], f - i);
    }

06벽을 지나면 반대편에서 나오고 경계에서 몸이 두 조각으로 그려지는 뱀

이웃 칸과 거리는 나머지 연산으로 계산해 판에 벽이 없어지고, 마디 사이 이동은 wrapDelta 가 짧은 쪽을 골라 판 끝에서 반대편으로 튀지 않는다. 그림은 마디를 3×3 곳에 복제해 판 사각형으로 잘라 이음매를 잇고, 탭을 누르면 복제가 꺼져 몸이 반쪽만 보인다. 렌더 값은 누적면적 20.9%, 평균 강도 95.3, 움직인 프레임 23/23 이다.

벽을 지나면 반대편에서 나오고 경계에서 몸이 두 조각으로 그려지는 뱀
새 창에서 열기

06 · 벽을 지나면 반대편에서 나오고 경계에서 몸이 두 조각으로 그려지는 뱀 — 측정 누적면적 20.9% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

WRAP_MODEGRID_NSEAM_GHOSTSTICK_MS
    function wrapDelta(a, c, n, wrap) {
        let d = c - a;
        if (wrap) {
            if (d > n / 2) {
                d -= n;
            }
            if (d < -n / 2) {
                d += n;
            }
        }
        return d;
    }

07몸통을 따라 비늘 무늬와 밝기 물결이 흐르는 뱀 가죽

마디 번호 k 에 sin(k·SCALE_FREQ − phase) 파형을 걸고 hash2 노이즈를 NOISE_AMP 0.28 만큼 섞어 비늘 밝기를 정하며, phase 가 스텝마다 0.07 씩 늘어 물결이 몸을 따라 흐른다. 마디 하나는 비늘 4개이고, 배경의 원 360개도 같은 파형을 사선으로 받아 판 전체가 비늘 벽지가 된다. 누적면적 41.1%, 평균 강도 59.9, 움직인 프레임 23/23 이다.

몸통을 따라 비늘 무늬와 밝기 물결이 흐르는 뱀 가죽
새 창에서 열기

07 · 몸통을 따라 비늘 무늬와 밝기 물결이 흐르는 뱀 가죽 — 측정 누적면적 41.128% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

SCALE_FREQWAVE_SPEEDNOISE_AMPSKIN_MIX
        // 비늘 하나의 밝기: 인덱스에 걸린 사인파 + 칸별 해시 노이즈
        function scaleLight(k, seedA, seedB) {
            const wave = 0.5 + 0.5 * Math.sin(k * SCALE_FREQ - phase);
            const noise = (hash2(seedA, seedB, 455) - 0.5) * 2 * NOISE_AMP;
            return clamp(wave * (1 - NOISE_AMP * 0.5) + noise * 0.5 + 0.25, 0, 1);
        }

08먹이를 먹는 순간 중력을 받는 입자가 터지고 점수 숫자가 튀어 오르는 뱀

먹는 순간 먹이 칸에서 입자 28개가 방사형으로 터져 GRAVITY 0.075 로 떨어지고, 수명이 0.017 씩 줄어 약 0.56~0.94초 만에 사라진다. 점수는 네 자리이고 바뀐 자릿수마다 위로 -4.2 의 속도를 받아 스프링으로 제자리에 돌아온다. 이 장면의 측정은 누적면적 20.1%, 평균 강도 100.2, 움직인 프레임 23/23 이다.

먹이를 먹는 순간 중력을 받는 입자가 터지고 점수 숫자가 튀어 오르는 뱀
새 창에서 열기

08 · 먹이를 먹는 순간 중력을 받는 입자가 터지고 점수 숫자가 튀어 오르는 뱀 — 측정 누적면적 20.14% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

BURST_COUNTGRAVITYLIFE_DECAYDIGIT_STIFF
        function burst(x, y) {
            for (let i = 0; i < BURST_COUNT; i += 1) {
                const a = rnd() * PI2;
                const sp = 0.9 + rnd() * 2.7;
                sparks.push({ x: x, y: y, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp - 1.2, life: 0.6 + rnd() * 0.4, c: BURST_COLORS[i % BURST_COLORS.length] });
            }
            rings.push({ x: x, y: y, r: 4, life: 1 });
        }

09먹이에서 퍼지는 거리장 물결과 그 비탈을 타고 내려가는 뱀

먹이에서 너비 우선으로 모든 칸의 거리를 채워 그 값으로 파동 색을 칠하고, 뱀은 머리 이웃 중 가장 낮은 값(lowestNeighbor)으로 내려간다. 방향키는 먹이를 한 칸 옮기고 탭은 물결을 멈춰 같은 값의 칸이 띠로 남는다. 판 전체를 거리 색으로 덮어 누적면적 73.6% 로 아홉 중 가장 크고, 평균 강도 67.0, 움직인 프레임 23/23 이다.

먹이에서 퍼지는 거리장 물결과 그 비탈을 타고 내려가는 뱀
새 창에서 열기

09 · 먹이에서 퍼지는 거리장 물결과 그 비탈을 타고 내려가는 뱀 — 측정 누적면적 73.622% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

WAVE_SPEEDGRID_NDIST_COLOR_STEPSTICK_MS
        function refreshField() {
            const blocked = new Uint8Array(b.n);
            for (let i = 0; i < g.body.length - 1; i += 1) {
                blocked[g.body[i]] = 1;
            }
            if (g.food >= 0) {
                dist = distField(b, g.food, blocked, false);
            }
            stepTo = lowestNeighbor(b, dist, g.body[0], false);
        }

값이 뱀의 인상을 바꾸는 곳 — 틱 간격·판 크기·몸통 보간

값 하나로 뱀이 달리 보이는 곳은 셋이다. 이 절의 숫자는 브라우저 캡처가 아니라 소스의 함수를 노드에서 직접 호출해 센 값이라, 맨 아래 표의 렌더 측정과는 따로 읽는다.

틱 간격을 90ms 에서 50ms 로 줄이면 같은 10초에 먹이를 세 배 먹는다

01 의 TICK_MS 만 90 에서 50 으로 바꾸고 같은 상태에서 10초를 돌리면 길이가 54에서 57로 느는 대신 54에서 63으로 는다. 먹이가 3개에서 9개로 세 배가 된 셈이다. 버린 길은 두 설정 모두 2건이라 판단은 그대로이고 속도만 달라진다.

판을 8줄에서 12줄로 키우면 가득 채우는 데 5.9배가 걸린다

02 의 GRID_N 을 8 에서 12 로 올리면 96칸이 228칸이 된다. 처음부터 가득 채우는 데 1,818틱이 아니라 10,665틱이 들고, 60ms 틱으로 따지면 109초가 640초가 된다. 지름길은 171번에서 811번으로 늘지만 순환 한 바퀴가 길어진 효과가 더 크다.

시드 여섯 개를 돌려도 모두 처음부터 가득 채웠고 걸린 틱은 1,818~2,113 이었다. 지름길을 끄면(마진 999) 2,311틱으로 27% 늘고, SHORTCUT_MARGIN 을 0·2·6 으로 두면 1,948·1,818·1,885틱이라 기본값 2 가 가장 짧았다.

보간 비율을 0.35 에서 0.12 로 낮추면 몸이 한 칸 늦게 끌려온다

03 의 BODY_LERP 가 0.35 일 때 그린 마디가 논리 칸 중심에서 뒤처지는 평균 거리는 8.5px, 칸 폭(25px)의 0.34칸이다. 0.12 로 낮추면 26.8px, 1.07칸이 되어 몸이 머리보다 한 칸쯤 늦게 따라온다. 1 로 두면 px[i] = tx 와 같아져 보간이 없는 것과 같은 그림이 나온다.

아홉 장면을 렌더해 잰 값은 다음 표다.

항목 누적면적 평균 강도 움직인 프레임
01 안전 검사 자동 조종 49.8% 114.0 23/23
02 해밀턴 순환 61.4% 90.0 17/23
03 보간 몸통 18.5% 78.6 23/23
04 사슬 줄 7.7% 50.4 23/23
05 열 궤적 22.8% 62.6 23/23
06 원환 20.9% 95.3 23/23
07 비늘 가죽 41.1% 59.9 23/23
08 먹이 폭발 20.1% 100.2 23/23
09 거리장 물결 73.6% 67.0 23/23

어디서 깨지는가 — 판이 가득 찰 때·벽 통과·움직임 줄이기 설정

검사를 끄면 같은 시드에서 600초에 6번 갇힌다

01 의 SAFE_CHECK 를 켠 채 600초(길이 209, 버린 길 44건)를 돌리면 갇힘이 0회이고 끄면 같은 시드에서 6회다. 다만 검사는 첫 먹이를 먹은 뒤 꼬리에 닿는지까지만 보고 그다음 먹이는 내다보지 않으므로, 0회는 이 시드와 600초에서 나온 실측일 뿐 갇히지 않는다는 증명이 아니다. 검사 없이 거리장만 따르는 09 도 600초에 6번 갇혔고 03·08 은 0회였다.

순환은 줄 수가 짝수일 때만 닫힌다

02 의 순환은 맨 윗줄을 가로지르고 나머지 줄을 지그재그로 돌아 왼쪽 열을 올라오게 만든다. 7줄 판(11×7=77칸)으로 바꿔 순환을 만들어 보니 한 곳이 이웃하지 않는 칸으로 이어져, 게임은 돌아가도 머리가 그 자리에서 건너뛴다. 줄 수가 짝수인 판을 써야 하는 이유다.

제약 반복이 모자라면 사슬이 늘어난다

04 의 FOLLOW_ITER 가 4 이면 이웃 마디 간격이 평균 9.04px, 최대 10.46px 이고, 1 로 줄이면 평균 9.18px, 최대 12.67px 라 목표 간격 9px 의 1.4배까지 늘어진다. 사슬끼리 부딪히는 검사는 없어서 몸이 자기 몸을 지나가도 막지 않는다.

점수 칸은 네 자리라 10000 에서 0000 으로 돈다

08 의 digits() 는 마지막 네 글자만 자르므로 점수가 10000 이 되면 칸에는 0000 이 보이고 상태 줄에는 10000 이 적힌다. 점수 상한을 정하거나 자릿수를 늘리는 쪽은 쓰는 사람의 몫이다.

움직임 줄이기에서는 입력이 있어야 화면이 바뀐다

prefers-reduced-motion 이 켜져 있으면 아홉 장면 모두 requestAnimationFrame 루프를 시작하지 않고 1,400ms 앞으로 보낸 한 장만 그린다. 02 는 판이 가득 찬 상태를 그대로 두며 탭으로만 새 판을 연다.

여기까지 읽고 값을 직접 바꿔 보고 싶다면 아래 카드에서 압축 파일을 받고, 열 때 쓰는 비밀번호는 9tzpwtwu 이다. 장면마다 HTML·SCSS 한 쌍과 리액트 판이 함께 담겨 있다.

변형 세 가지와 접근성

이름 값 느낌
틱 간격 바꾸기 01 TICK_MS 90 → 50 같은 상태에서 10초를 돌리면 90ms 는 길이 54→57, 50ms 는 54→63 으로 먹이를 세 배 먹는다. 버린 길은 둘 다 2건이라 판단은 같고 속도만 달라진다.
판 크기 바꾸기 02 GRID_N 8 → 12 판이 96칸에서 228칸으로 늘면 처음부터 가득 채우는 데 1,818틱이 아니라 10,665틱(약 5.9배)이 걸린다. 60ms 틱이면 109초가 640초가 된다.
몸통 보간 세기 바꾸기 03 BODY_LERP 0.35 → 0.12 그린 몸통이 논리 칸 중심에서 뒤처지는 평균 거리가 8.5px(0.34칸)에서 26.8px(1.07칸)로 벌어져, 몸이 머리보다 한 칸 가까이 늦게 끌려온다.

세 변형의 숫자도 위 값 절과 같은 방식으로 소스 함수를 노드에서 직접 호출해 센 것이다.

입력 처리는 아홉 파일이 같은 뼈대를 나눠 쓴다. 장면마다 <button> 이 하나 있고 캔버스는 tabindex="0" 과 aria-label 을 갖는다. Enter·Space·포인터 누름은 장면의 탭 동작으로 이어지고 preventDefault 로 Space 가 페이지를 내리지 못하게 막는다. 방향키를 쓰는 장면은 04 와 09 뿐이라 이 둘에서만 방향키의 기본 동작을 막고, 나머지 일곱 장면에서는 키를 가로채지 않으니 Tab 으로 캔버스에서 버튼으로 넘어간다. 상태 줄은 aria-live="polite" 로 길이·버린 길·점수가 바뀔 때만 갱신된다.

prefers-reduced-motion 이 켜져 있으면 버튼이 다음 장면 으로 바뀌어 누를 때마다 900ms 씩, 포인터 이동이나 키 입력은 128ms 씩 앞으로 보낸 뒤 바로 다시 그린다. Enter 와 Space 는 아홉 장면 모두 그 장면의 탭 동작을 한 번 실행하고, 그 직후 128ms 를 앞으로 보내 다시 그린다.

snake game code html css js 는 라이브러리 없이 충분한가?

snake game code html css js 를 찾는 사람이 보는 소스로는 드물게, 이 편의 아홉 파일에는 라이브러리·CDN·WebGL 이 없고 Math.random·Date·fetch·localStorage 도 없다. 길찾기와 순환과 보간과 입자는 모두 requestAnimationFrame 과 캔버스 2D 만으로 돌아가므로, 뱀이 스스로 움직이는 장면까지는 순수 자바스크립트로 충분하다.

부족한 것은 게임을 서비스로 만들 때의 부분이다. 최고 기록 저장이나 효과음은 없고 사람이 방향키로 조작하는 입력도 04 와 09 의 약한 형태뿐이다. 벽돌이 부서지는 반사각까지 가려면 벽돌깨기 게임 만들기 9가지 — 반사각은 맞은 위치가 정한다가, 블록 쌓기 규칙까지 가려면 HTML 테트리스 코드 — 캔버스로 조립하는 9단계가 그다음 걸음이다. 중력과 충돌 물리가 더 궁금하면 바운싱 볼 애니메이션 9가지 — 충돌·중력 물리 계산을 보면 된다.

snake game html css js github 코드를 가져다 쓰기 전에 자주 묻는 질문

snake game html css js github 저장소에 이 소스를 그대로 올려도 되나?

외부 코드를 끌어 쓰지 않아 올릴 때 따라붙는 의존성 목록이 없다. 파일마다 index.html 하나에 스타일과 스크립트가 들어 있어 붙여 넣으면 돌아가고, 난수가 시드로 고정이라 같은 화면이 재현된다. 라이선스 문구나 저장소 규칙은 올리는 쪽에서 따로 정해야 한다.

먹이 자리를 매번 다르게 하려면 어디를 바꾸나?

01 은 newGame(b, false, 455101) 의 마지막 숫자가 lcg 의 시드이고, 02·03·05·06 도 같은 꼴이라 숫자를 바꾸면 다른 판이 나온다. 매번 무작위로 하고 싶으면 그 자리에 쓸 값을 직접 만들어 넣어야 하고, 그러면 같은 화면이 재현되지 않는다.

판을 더 크게 잡으면 느려지나?

02 는 판이 커지면 가득 채우는 틱 수가 5.9배로 늘고, 한 틱에는 순환 위치 비교와 이웃 네 칸 검사만 돈다. 01 은 매 틱 칸 수만큼 너비 우선 탐색을 다시 돌리므로 칸이 많아질수록 틱당 일이 늘어날 것이다. 키운 판에서 프레임 시간은 재 보지 않았다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.