Przejdź do treści
<code>pen.pl

BLOK — rozbijacz cegieł

Gry

Podgląd

Ładowanie podglądu…

Odbijaj piłkę, zbij 24 cegły i pilnuj trzech żyć. Paletka podąża za wskaźnikiem lub strzałkami.

0,0 / 5 Brak ocen

Kod źródłowy

Licencja MIT — także do użytku komercyjnego. Zachowaj informacje o autorze i licencji.

HTML
<main><header><span class="eyebrow">Rozbijanie cegieł</span><h1>BLOK / 24</h1><p>Rozbij układ. Utrzymaj piłkę w grze.</p></header><div class="desktop-split"><section aria-label="Plansza"><canvas id="screen" width="600" height="400" tabindex="0" aria-label="BLOK / 24. Przesuwaj paletkę myszą, palcem lub strzałkami. Masz trzy życia.">Gra wymaga obsługi canvas. Wynik i przyciski znajdują się pod planszą.</canvas><div class="controls" aria-label="Sterowanie"><button type="button" data-key="ArrowLeft" aria-label="Ruch: lewo">←</button><button type="button" data-key="ArrowRight" aria-label="Ruch: prawo">→</button></div></section><aside><div class="eyebrow">Punkty</div><div id="score" class="metric">0</div><p id="status" class="status" role="status">Naciśnij Graj.</p><div class="actions"><button id="play" type="button">Graj</button><button id="reset" type="button">Od nowa</button></div><p>Przesuwaj paletkę myszą, palcem lub strzałkami. Masz trzy życia.</p><small>Esc — pauza. Gra zatrzymuje się po opuszczeniu okna.</small></aside></div></main>
CSS
*{box-sizing:border-box}body{margin:0;font-family:system-ui,sans-serif;background:var(--bg);color:var(--ink)}main{width:min(100% - 32px,980px);margin:32px auto}h1{font-size:clamp(32px,7vw,64px);line-height:1;margin:12px 0 20px;letter-spacing:-.045em}p{line-height:1.55}button{font:inherit;min-height:44px;padding:10px 16px;border:1px solid currentColor;border-radius:0;background:transparent;color:inherit;cursor:pointer}button:hover{background:var(--ink);color:var(--bg)}button:disabled{cursor:default;opacity:.55}button:focus-visible,canvas:focus-visible{outline:3px solid var(--focus);outline-offset:3px}button[aria-pressed="true"]{background:var(--ink);color:var(--bg)}.eyebrow{font:12px ui-monospace,monospace;letter-spacing:.16em;text-transform:uppercase}.status{min-height:48px;font-weight:600}.actions{display:flex;flex-wrap:wrap;gap:8px}.metric{font:700 28px ui-monospace,monospace}small{line-height:1.5}canvas{display:block;width:100%;height:auto;border:1px solid currentColor;touch-action:none}.controls{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0}.controls button{min-width:54px;touch-action:none;user-select:none}.board{display:grid;gap:5px}.board button{padding:0;aspect-ratio:1;min-width:0;font-size:clamp(18px,5vw,30px)}@media(max-width:600px){main{width:calc(100% - 24px);margin:20px auto}h1{margin-bottom:16px}.desktop-split{display:block!important}}@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
:root{--bg:#f5eee3;--ink:#172153;--focus:#d62e28}h1{font-weight:900;font-size:clamp(44px,10vw,96px);color:#d62e28}header{display:block}.desktop-split{display:grid;grid-template-columns:minmax(0,680px) 1fr;gap:20px}aside{background:#f7c940;padding:20px}canvas{border:3px solid #172153}.metric{font-size:60px}.actions button{font-weight:800}
@media(max-width:600px){aside .metric{font-size:36px}aside .status{min-height:0;margin:8px 0}aside .actions{margin:12px 0}}
JavaScript
function brickHit(ball, brick) { return ball.x + ball.r >= brick.x && ball.x - ball.r <= brick.x + brick.w && ball.y + ball.r >= brick.y && ball.y - ball.r <= brick.y + brick.h; }
$(function () {
    const canvas = document.getElementById('screen'), ctx = canvas.getContext('2d');
    let ball, paddle, bricks, lives, score;
    function serve() { ball = {x:300,y:280,r:7,vx:145,vy:-195}; }
    function init() { paddle=250; lives=3; score=0; bricks=Array.from({length:24},(_,i)=>({x:28+(i%6)*92,y:35+Math.floor(i/6)*30,w:84,h:22,live:true}));serve();$('#score').text('0 / 24'); }
    function direction(key) { if(key==='ArrowLeft')paddle=Math.max(0,paddle-16); if(key==='ArrowRight')paddle=Math.min(500,paddle+16); }
    $(canvas).on('pointermove pointerdown', function(event){if(!playing)return;const box=canvas.getBoundingClientRect();paddle=Math.max(0,Math.min(500,(event.originalEvent.clientX-box.left)*600/box.width-50));});
    function update(dt) {
        if(held.has('ArrowLeft'))paddle=Math.max(0,paddle-dt*360);if(held.has('ArrowRight'))paddle=Math.min(500,paddle+dt*360);
        const oldY=ball.y;ball.x+=ball.vx*dt;ball.y+=ball.vy*dt;
        if(ball.x<7||ball.x>593){ball.x=Math.max(7,Math.min(593,ball.x));ball.vx*=-1;}if(ball.y<7){ball.y=7;ball.vy=Math.abs(ball.vy);}
        if(ball.vy>0 && oldY+7<=365 && ball.y+7>=365 && ball.x>=paddle-7 && ball.x<=paddle+107){ball.y=358;ball.vy=-Math.abs(ball.vy);ball.vx=(ball.x-paddle-50)*4;}
        for(const brick of bricks){if(brick.live&&brickHit(ball,brick)){brick.live=false;ball.vy*=-1;score++;$('#score').text(score+' / 24');break;}}
        if(score===24){finish('Wszystkie cegły rozbite!');return;}
        if(ball.y>410){lives--;if(!lives){finish('Koniec gry. Zbite cegły: '+score+'.');return;}serve();$('#status').text('Pozostałe życia: '+lives+'.');}
    }
    function draw() {
        ctx.fillStyle='#f5eee3';ctx.fillRect(0,0,600,400);
        bricks.forEach((b,i)=>{if(b.live){ctx.fillStyle=['#d62e28','#172153','#eebc24','#287f64'][Math.floor(i/6)];ctx.fillRect(b.x,b.y,b.w,b.h);}});
        ctx.fillStyle='#172153';ctx.fillRect(paddle,365,100,12);ctx.beginPath();ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2);ctx.fill();
        ctx.font='14px monospace';ctx.fillText('ŻYCIA '+lives,28,330);
    }

    let playing = false, ended = false, frameId = null, previous = 0;
    const held = new Set();
    function pause() {
        if (!playing) return;
        playing = false; held.clear(); cancelAnimationFrame(frameId);
        $('#play').text('Wznów'); $('#status').text('Pauza.');
    }
    function finish(message) {
        playing = false; ended = true; held.clear(); cancelAnimationFrame(frameId);
        $('#play').text('Zagraj ponownie'); $('#status').text(message);
    }
    function reset() {
        playing = false; ended = false; held.clear(); cancelAnimationFrame(frameId);
        init(); draw(); $('#play').text('Graj'); $('#status').text('Naciśnij Graj.');
    }
    function frame(now) {
        if (!playing) return;
        const dt = Math.min((now - previous) / 1000, .035); previous = now;
        update(dt); draw();
        if (playing) frameId = requestAnimationFrame(frame);
    }
    $('#play').on('click', function () {
        if (playing) { pause(); return; }
        if (ended) reset();
        playing = true; previous = performance.now();
        $(this).text('Pauza'); $('#status').text('Gra trwa.'); canvas.focus();
        frameId = requestAnimationFrame(frame);
    });
    $('#reset').on('click', reset);
    $(document).on('keydown', function (event) {
        if (event.key === 'Escape') { pause(); return; }
        if (playing && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
            event.preventDefault(); held.add(event.key); direction(event.key);
        }
    }).on('keyup', event => held.delete(event.key));
    $('[data-key]').on('pointerdown', function (event) {
        if (!playing) return;
        event.preventDefault(); this.setPointerCapture(event.originalEvent.pointerId);
        const key = $(this).attr('data-key'); held.add(key); direction(key);
    }).on('pointerup pointercancel lostpointercapture', function () { held.delete($(this).attr('data-key')); })
      .on('click', function (event) { if (playing && event.originalEvent.detail === 0) direction($(this).attr('data-key')); });
    $(window).on('blur', pause);
    $(document).on('visibilitychange', function () { if (document.hidden) pause(); });
    reset();
});
Biblioteki

JavaScript

Edytuj swój pen

Podaj adres e-mail użyty przy zapisie. Wyślemy link do edycji.

Link jest ważny przez 30 minut.