Skip to content

Создаем Street Fighter на CSS анимациях и JavaScript

Привет, друзья. В данной статье я бы хотел поделиться с вами одной интересной техникой с сайта Simurai, об оживлении PNG-спрайтов с помощью CSS3 анимаций. Основная идея этого метода заключается в том, чтобы «воссоздать» какой-то анимированный GIF, но через спрайт в формате PNG.

В детстве я, как и все, кого я знаю, играл в Street Fighter. И когда я наткнулся в сети на спрайт персонажа Кена из данной игры. Что появилось в моей голове, Вы можете увидеть в демонстрации.

Демонстрация

Создадим спрайт

Сначала мы должны открыть Photoshop для создания спрайта. Сделайте все изображения одинакового размера (у меня это 70px по ширине и 80px по высоте). В создании спрайта для игры нам поможет сервис Switches. В итоге должно получиться что-то вроде этого:

css-спрайт

HTML и CSS

Теперь нам нужно создать блок DIV для Кена, который будет драться, ходить и другие наши действия:

<div class="ken"></div>
.ken {
width:70px; height:80px; /* размеры кадра в спрайте */
background-image:url('../images/sprite.png'); /* путь до спрайта */
}

Теперь создадим анимацию для хука (удара рукой):

.punch {
animation: punch steps(4) 0.15s infinite;
}
@keyframes punch {
from { background-position:0px -160px; }
to { background-position:-280px -160px; }
}

Мы только что применили анимацию (punch) на класс .punch, при которой произойдет смена background-position с 0px до 280 пикселей (по оси х). Эта анимация будет разбита на 4 части (steps(4), т.к. нам надо пройтись по спрайту до конца и назад), и это займет 0,15 секунду на выполнения.

Наконец, нам надо добавлять или удалять класс .punch для блока DIV.ken, по нажатию на клавишу.

$(document).on('keydown', function(e) {
if (e.keyCode === 68) { // 68 это буква D на клавиатуре
$('.ken').addClass('punch');
setTimeout(function() { $ken.removeClass('punch'); }, 150);
}
});

Мы используем jQuery, чтобы добавить класс .punch, по нажатию на букву «D», а затем убираем его по прошествии 150 мс. Это в значительной степени все, что вам необходимо знать для того, чтобы создать другие действия.

Выйдем на следующий уровень с SASS

Вы могли заметить, что у нас есть некоторые не изменные константы, например, ширина и высота кадра в спрайте. После того как вы создадите другие действия, вы обнаружите много дублирования кода в CSS, который будет трудно поддерживать в будущем. SASS может поможет нам предотвратить все это безобразие!

Сначала мы используем @mixins для animation() и keyframes():

@mixin animation($params) { 
    -webkit-animation:$params;
    -moz-animation:$params;
    -ms-animation:$params;
    animation:$params;
}
@mixin keyframes($name) { 
    @-webkit-keyframes $name { @content }
    @-moz-keyframes    $name { @content }
    @-ms-keyframes     $name { @content }
    @keyframes         $name { @content }
}

Сохраним ширину и высоту кадра спрайта в переменные:

$spriteWidth:70px;
$spriteHeight:80px;

И, наконец, мы можем соединить их вместе, чтобы создать новый сложный миксин, который задает анимацию и делает правильный расчет background-position для спрайта:

@mixin anim($animName, $steps, $animNbr, $animParams){
    .#{$animName} { 
        @content;
        @include animation($animName steps($steps) $animParams); 
    }
    @include keyframes($animName) {
        from { background-position:0px (-$spriteHeight * ($animNbr - 1)); }
        to { background-position:-($spriteWidth * $steps) (-$spriteHeight * ($animNbr - 1)); }
    }
}

Теперь вы можете создать новое действие одной строчкой кода:

$spriteWidth: 70px;
$spriteHeight: 80px;

/* punch */
@include anim($animName:punch, $steps:3, $animNbr:3, $animParams:.15s infinite);
/* kick */
@include anim($animName:kick, $steps:5, $animNbr:7, $animParams:.5s infinite);
/* hadoken */
@include anim($animName:hadoken, $steps:4, $animNbr:1, $animParams:.5s infinite);
...

Переменная $animNbr очень важна! Это номер строки в нашем спрайте. Так кадры для хука (удара рукой) находится на третьей строке в нашем спрайте, а для кика (удар ногой) — на 7-й строке, и т.д.

Добавим обнаружение столкновений для файрбола

Нам нужен очень быстрый цикл для проверки, что файрбол дошел до границы экрана. Если левое положение файрбола больше, чем ширина окна, то это означает, что огненный шар дошел до конца экрана, поэтому мы должны его сразу же «взрывать». Вот решение, оно не идеально, но работает:

var $fireball = $('<div/>', { class:'fireball' });
$fireball.appendTo($ken);

var isFireballColision = function(){ 
    return $fireballPos.left + 75 > $(window).width();
};

var explodeIfColision = setInterval(function(){
    $fireballPos = $fireball.offset();
    if (isFireballColision()) {
        $fireball.addClass('explode'); 
        clearInterval(explodeIfColision);
        setTimeout(function() { $fireball.remove(); }, 500); 
    }
}, 50);

Что дальше?

Мы могли бы легко добавить звуковые эффекты, фоновую музыку, другого персонажа… Вот что я люблю в веб-разработке: это практически полная безграничность.

Оргинал статьи: davidwalsh.name