🎮

ポケモンの能力アップみたいなアニメーションを CSS で作った

2022/09/28に公開約5,200字2件のコメント

やったこと

ポケモンの能力アップしたときのようなエフェクトを CSS で作りました。
DS 作品(ダイヤモンド・パールとか)までのアニメーションを意識しています。

注意

以下のブラウザで動作することを確認しています。いずれも 2022/9/26 時点での最新版です。
その他のブラウザでは動かない可能性があります。

  • Google Chrome Version 105.0.5195.127
  • Mozilla Firefox Version 105.0.1

作り方

素材を入手する

PokeAPI を使って素材を入手しました。

https://pokeapi.co/

画像を手に入れたい欲しいポケモンの図鑑番号(今回はリザードンの6)を使って検索すると、特性や種族値などの情報を取得できます。
今回は、 sprites.front_default の画像データを使います。

次のように div 要素に background プロパティを使って画像を指定します。

<div class="pokemon no6"></div>
.pokemon {
  height: 96px;
  width: 96px;
}

.no6 {
  background: no-repeat url(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png);
}

素材に合わせたエフェクトを表示できるようにする

css の mask-image を使います。

https://developer.mozilla.org/ja/docs/Web/CSS/mask-image

div 要素を追加し、mask-image プロパティを使ってエフェクトのマスクに使う画像を指定します。

<div class="pokemon no6">
  <div class="effect"></div>
</div>
.effect {
  height: 100%;
  width: 100%;
}

.no6 .effect {
  -webkit-mask-image: url(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png);
  mask-image: url(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png);
}

試しに次のような指定を追加すると、画像にぴったり合うように表示範囲がマスクされていることが確認できます。

.effect {
  background-color: blue;
}

mask-imageの動作確認

エフェクトを表示する

静止した状態で作る

能力アップの時に出るギザギザ模様を表現します。

effect クラスの子要素として、模様を表示する effect-image クラスを持つ要素を追加します。
effect-image クラスに repeating-linear-gradient を使って次のように指定すると、斜めの縞模様が表示されます。
色やサイズは雰囲気で指定しています。

https://developer.mozilla.org/ja/docs/Web/CSS/gradient/repeating-linear-gradient

<div class="pokemon no6">
  <div class="effect">
    <div class="effect-image"></div>
  </div>
</div>
.effect-image {
  background-image: repeating-linear-gradient(
    60deg,
    red 0,
    orange 2px,
    white 4px,
    orange 6px,
    red 8px
  );
}

斜め模様を追加した

この縞模様を、一部を反転して表示するとギザギザ模様を作ることができます。

反転する部分を作るために、横方向に div 要素をいくつか並べます(とりあえず8こ)。 background-imageeffect-imageクラスの子要素で指定し、かつ偶数番目を反転させるとギザギザ模様になります。
反転には、 transoform プロパティを使います。

<div class="pokemon no6">
  <div class="effect">
    <div class="effect-image">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
</div>
.effect-image {
  display: flex;
}

.effect-image div {
  width: 12.5%; 
  height: 100%;
  background-image: repeating-linear-gradient(
    60deg,
    red 0,
    orange 2px,
    white 4px,
    orange 6px,
    red 8px
  );
}

.effect-image div:nth-child(even) {
  transform: scale(-1, 1);
}

ギザギザ模様を追加

アニメーションで上昇させる

animationkeyframes を使って上昇するアニメーションを作ります。
また、画像の上昇分に合わせて、 effect-image の高さを大きくしておきます。

@keyframes up {
  from {
    transform: translate(0, 0);
  }
  to {
    transform: translate(0, -100px);
  }
}

.effect-image {
  height: calc(100% + 100px);
  animation: up 1.3s ease-out 0s infinite;
}

アニメーションを追加

ボタンを追加

好きなタイミングでアニメーションを動かすためにボタンを追加します。
ボタンをクリックしてアニメーションが動くように、次のように実装しました。

  • ボタンがクリックされたタイミングで、 effect-up クラスを追加
  • effect-up クラスが追加された時、アニメーションを一度だけ表示
  • アニメーションが終了したら effect-up クラスを削除

また、次のような調整も行いました。

  • アニメーションが動いていないときはエフェクトが見えないようにする
  • アニメーションの最中で「透明→半透明→透明」とエフェクトの見え方を変化させる
<div id="pokemon-no6" class="pokemon no6"> <!-- id を追加 -->
  <div class="effect">
    <div class="effect-image">
(略)

<button id="button-up">up</button>
@keyframes up {
  0% {
    transform: translate(0, 0);
    opacity: 0;
  }
  20% {
    opacity: 0.5;
  }
  70% {
    opacity: 0.5;
  }
  100% {
    transform: translate(0, -100px);
    opacity: 0;
  }
}

.effect-image {
  opacity: 0;
}

.effect-up .effect-image {
  animation: up 1.3s ease-out;
}
const effect = document.getElementById("pokemon-no6").children[0];

effect.addEventListener("animationend", function () {
  effect.classList = ["effect"];
});
document.getElementById("button-up").onclick = function () {
  effect.classList.add("effect-up");
};

クリックでアニメーションを開始

バリエーションを増やす

能力ダウンした場合も同様に実装したら完成です。

能力アップとの違いは色とアニメーションの向きだけです。
CSS のカスタムプロパティを使うと簡単に色を変更させられます。

.effect-up {
  --color-1: red;
  --color-2: orange;
  --color-3: white;
}

.effect-down {
  --color-1: navy;
  --color-2: aqua;
  --color-3: white;
}

.effect-image {
  background-image: repeating-linear-gradient(
    60deg,
    var(--color-1) 0,
    var(--color-2) 2px,
    var(--color-3) 4px,
    var(--color-2) 6px,
    var(--color-1) 8px
  );
}

能力ダウンも追加

あとは気が済むまで色やサイズを微調整したら完成です。

まとめ

使った主要な技術は以下のとおりです。

  • mask-image を使った画像のマスク処理
  • repeating-linear-gradient を使ったパターン画像
  • animationkeyframes を使ったアニメーション

Discussion

アイデアが最高で、おもしろい記事でした!
構成要素はシンプルなのにかなりそれっぽくてすごいです 🤩

反転する部分を作るところでdivを並べて作られていますが、
mask-imageを使えば ::before, ::afterだけで作れそうだと思い、フォークして作ってみました。
CSSで作っておくと、列の数をCSS変数 (--effect-lines) で制御できてイイ感じです。
ご参考まで!

コメントありがとうございます。
ギザギザ模様がちょうど beforeafter で表現できるんですね。
mask-image / linear-gradienttransform/scaleX の使い方がうまくて勉強になりました!

ログインするとコメントできます