Pong на javascript

    Решил поддержать серию постов «Делаем XXX на JS в 30 строк». Взял для примера Pong в приближенному к классическому оформлении:

    Вышло не совсем в 30 строк, а целых 38, т.к. логики вышло прилично, а совсем убивать читаемость или сжимать минимизаторами/обфускаторами не хотелось.

    В демке:
    • Управление по Up/Down;
    • ИИ противника;
    • Ускорение мяча с каждым отскоком;
    • Обработка клавиатуры, не зависящая от перемещения мяча;
    • Ожидание нажатия клавиш для запуска мяча;
    • Поддержка практически любого размера поля и высоты «игроков»;
    • Ведение статистики.


    Поиграться на fiddle (вроде туда повсеместно все демки заливают).

    Вариант, где можно выиграть.

    Вариант с управлением мышкой.

    Код
    (function(cell, width, height, plr_height) {
        var min_speed=5, max_speed=20, speed, tick, ball, pl, pr, py = parseInt((height-plr_height)/2), pmy = plr_height-1, score = [0, 0];
        function $(id) {return document.getElementById(id)};
        function $$(o, attrs) {for (var k in attrs) {o.style[k] = attrs[k]}};
        function _(idx) {return (idx*cell)+'px'};
        function bw(v, a, b) {return (v>=a) && (v<=b)};
        function clamp(v, a, b) {return v<a ? a : (v>b ? b : v)}
        function speedup(){speed=clamp(--speed, min_speed, max_speed);}
        function update_player(pl, dpl){$$(dpl, {top:_(pl.y=clamp(pl.y+pl.dy, 0, height-plr_height))}); pl.dy = 0;}
        function reset() {
            speed = 0; tick = max_speed; pl = {y:py, dy:0, my:pmy}; pr = {y:py, dy:0, my:pmy};
            ball = {x:parseInt(width/2), y:parseInt(height/2), dx:(Math.random()>0.5?1:-1), dy:(Math.random()>0.5?1:-1)};
            $('score').innerHTML = score[0]+':'+score[1];
        }
        document.body.onkeydown = function(e) {
            pr.dy = (e.keyCode == 40) ? 1 : ((e.keyCode == 38) ? -1 : 0);
            if (pr.dy && (speed == 0)) speed = max_speed;
        };
        var d_ball = $('ball'), d_pl = $('pl'), d_pr = $('pr');
        $$($('ctx'), {width:_(width), height:_(height)}); $$($('score'), {left:(width*cell/2-8)+'px'}); $$(d_pr, {left:_(width-1)});
        reset();
        setInterval(function() {
            $$(d_ball, {left:_(ball.x), top:_(ball.y)});
            update_player(pl, d_pl); update_player(pr, d_pr);
            if (!speed || --tick) return;
            tick = speed;
            ball.x += ball.dx; ball.y += ball.dy;
            if (ball.dx < 0) {
                var x=ball.x, dx=ball.dx, y = ball.y, dy = ball.dy;
                while (x>1) { x+=dx; if (!bw(y+=dy, 1, height-2)) break;/*до первого отскока, а можно {dy = -dy}; */ }
                pl.dy = bw(y, pl.y, pl.y+pl.my) ? 0 : (pl.y > y ? -1 : 1);
            }
            if (!bw(ball.y, 1, height-2)) {ball.dy = -ball.dy; speedup();}
            if ((ball.x == 1 && bw(ball.y, pl.y, pl.y+pl.my)) || (ball.x == (width-2) && bw(ball.y, pr.y, pr.y+pr.my))) {ball.dx = -ball.dx; speedup();}
            else if ((ball.x == 0) || (ball.x == width-1)) {++score[ball.x ? 0 : 1]; reset();}
        }, 10);
    })(16/*css*/, 20, 15, 5/*css*/);
    

    <div id="ctx" class="ctx">
        <div id="score" class="score">0:0</div>
        <div id="ball" class="cell ball" />
        <div id="pl" class="cell plr" />
        <div id="pr" class="cell plr" />
    </div>
    

    .ctx {
        background-color: black;
        position: fixed;
        left: 0;
        top: 0;
    }
    
    .ctx .cell {
        width: 16px;
        height: 16px;
        background-color: white;
        position: fixed;
        left: 0;
        top: 0;
    }
    
    .ctx .plr {
        height: 80px;
    }
    
    .ctx .score {
        color: white;
        position: absolute;
        top: 0;
        font-family: "Lucida Console", Monaco, monospace;
    }
    

    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 18
    • +6
      А в нем можно выиграть? О_о
      • 0
        Когда ИИ обсчитывал все отскоки — вряд ли. Сейчас он обсчитывает только до первого отскока, так что возможно. Да и судя по логам, есть те, кто набирает 8x11, к примеру (может через консольку?).

        В любом случае, сейчас сделаю, чтобы он ошибался.
        • +2
          Выложил (по новой ссылке) вариант, где ИИ иногда ошибается на 1-2 клетки.
        • +13
          Никогда не понимал, по какому принципу считаются «строки» в подобных демках. Можно же вообще всё в одну строку склеить…

          Но, безотносительно моего занудства, очень круто!
          • +4
            Вообще-то принято соревноваться в количестве символов на программу… js1k.com/
          • +2
            Строки это понятие относительное.
            Думаю при помощи обфускатора этот код можно написать в одну строку :)
            Вот если бы все те кто пишут что-то в 30 строк придерживались Coed Conventions…
            • +2
              *Code Conventions
              • +1
                Мне больше нравятся сравнения «размер бинарника» или «количество непробельных символов». Но предыдущие посты были именно на число строк, несмотря на всю странность такого решения для js. Я сам не js программист, может можно покомпактнее реализовать.
              • НЛО прилетело и опубликовало эту надпись здесь
                • +2
                  Ещё немного и будет jquery в 30 стро кода.
                  • 0
                    Круто, всё выглядит достаточно просто и логично. Правда форматирование кода не лучшее, читать его немного трудно.
                    • –1
                      Первоначальный (рабочий) вариант был на ~48 вроде строк. Это уже некоторое ужатие. Хотелось вместить хотя бы в 3x строчек :)

                    • 0
                      Выложил вариант с управлением мышкой. Самый халявный :)
                      • 0
                        Извините, но это читерство…
                        function update_player(pl, dpl){$$(dpl, {top:_(pl.y=clamp(pl.y+pl.dy, 0, height-plr_height))}); pl.dy = 0;}
                        • 0
                          Отсечение по интервалу или два действия в функции?
                          • 0
                            Блин ну по честному это не одна строка,
                            а целых шесть!
                            function update_player(pl, dpl) {
                                $$(dpl, {
                                    top: _(pl.y = clamp(pl.y + pl.dy, 0, height - plr_height))
                                });
                                pl.dy = 0;
                            }


                            Ну пускай не шесть, если скобки закрывать в конце строк,
                            но четыре то как минимум ))
                            function update_player(pl, dpl) {
                                $$(dpl, {
                                    top: _(pl.y = clamp(pl.y + pl.dy, 0, height - plr_height)) });
                                pl.dy = 0; }


                            PS: А совсем совсем по честно в коде 117 строк.
                          • 0
                            У меня не совсем 30 строк, мой вариант не подходит :)

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.