2019/06/05
Atomic DesignでAtomが走りジャンプするゲームを作りました。
原子が障害物を越えて走るだけのシンプルなゲームです。
github: https://github.com/daitasu/atomsDash
ここから遊べます: https://atomsdash.firebaseapp.com/
注: 現在PCでのみ遊べます。スマホ対応はしておりません。
タッチでもジャンプはできますが、レスポンシブじゃないので急にゲームオーバーになります。
最近こんなの作ってました。やっと盛り込みたかったことが一通りできたので記事に起こしていきます! #nuxt #atomsdash pic.twitter.com/C7ZLVLAr3Y
— daitasu (@daitasu) May 29, 2019
特にサーバから取得するデータもないので、Nuxtで静的ファイルをgenerateしたものをおいてるだけの構成になります。
なぜこのゲームを作ったか
「Atomic Designをしっかり0から設計してみたい」
これが一番大きな理由です。
また、普段は業務システムの作成に従事しているため、全く別分野の物が作りたいと思い、ゲームを作ることにしました。
この記事に惹かれ、CSSアニメーションをバンバンやってみよう!画像は極力使わないぞ!という思いを持って挑み始めました。なぜAtomを走らせた?
...これを走らせればいいのでは?
安易ですが、Atomic Designの学習がメインなので。
UIコンポーネント設計のためのデザインフレームワーク。
UIをコンポーネント単位に区切って考えていくことで、コンポーネント単位でテストすることをできるようにしたり、再利用による実装量の減少、不具合時や手戻り時に解決すべき部分を最小に抑えることができます。
Atomic Designはこのコンポーネント設計を原子に見立てて大きく5つの枠組みに区切ったものです(上記に挙げた図です)。
Atomic Designはこの5つの機構に分けることで責務を切り分け、それぞれの役割に集中できるようにしています。
粒度 | 関心事 |
---|---|
Atom 原子 | デザインの統一性 |
Molecules 分子 | 行動を阻害しない統一性 |
Organisms 有機体 | ユーザの行動を促すコンテンツ |
Templates テンプレート | 画面全体のレイアウト |
Page ページ | コンテンツやルーティングとコンポーネントをつなぐ(再利用しない) |
大きなコンポーネントから小さなコンポーネントに依存関係を持たせていく事でデザインの仕様変更時はAtomsやMoleculesのみを修正、fetch周りの修正はPagesのみといったように切り分けや作業の容易さが変わってきます。
※ この辺りは他の方の記事や書籍を参考にした方が良いかと思うので、深くは割愛致します。書籍のオススメは「こちら」です(表はこの本から引用してます)。
ではAtomsDashではどのようにしたかを見ていきます。
Character.vue
、 Obstacle.vue
などを置いています。ロジックはAtomsに持たせず、極力Moleculesで賄うようにしています。作成過程で色々考えた部分、肝となった部分を書いていきます。
こちらには、Vueでトランジションを使う際に用いる、Enter/Leaveを利用しています。
Enter/Leaveを使うと、v-ifやv-showなどでの描画時、または消滅時にjsフックができ、カスタムイベントを作ることができます。
transition(
appear
v-on:before-appear="customBeforeAppearHookK"
v-on:appear="customAppearHook"
)
div.electron-shell(:style="`width: ${size * 2 / 3 }px; height: ${size * 2 / 3 }px;`")
div.electron-1(v-if="selectedAtomNo > 0" :class="isOutermostK")
div.electron-2(v-if="selectedAtomNo > 1" :class="isOutermostK")
div.neutron(:style="`width: ${size / 3}px; height: ${size / 3}px;`")
上記は電子殻部分の一例です。pugというjadeのような記法で書いています。
methods: {
customBeforeAppearHookK: function(el) {
Velocity(el, { rotateZ: "360deg" }, { duration: 5000, loop: true, easing: "linear" });
}
}
Enter/Leaveでのjsフックで要素を取得することができ、Velocity.jsというアニメーションライブラリを組み合わせることで回転を実現させています。
こちらもご参照ください。 VueでのCSSアニメーションの話
キャラクターと障害物の衝突判定部分。色々悩んだが下のやり方が一番しっくりきました。
横軸と縦軸に対して、
衝突 = (2物体の中心点間の距離 < 2つの物体の半径の和)
として計算を行いました。
X1: 2つの物体の中心点のX方向距離
Y1: 2つの物体の中心点のY方向距離
X2: 2つの物体のX方向半径の和
Y2: 2つの物体のY方向半径の和
if (x1 < x2 && y1 < y2)
jsだとこんな感じになります。
以下を2段組み合わせて空中ジャンプを実現しています。
onJump(event) {
// ジャンプ中は許可しない
if (this.jumping) {
return;
}
this.jumping = true;
const radius = 200;
let t = 0;
const timer = setInterval(() => {
const jumpHeight = Math.sin((Math.PI * t++) / 80) * radius;
// position:absolute に対し、ベースとなるbottomにsin関数の高さを足したものをjump中の高さにする
this.bottom = this.center + jumpHeight;
// 地面以下となったら元の位置に戻す
if (jumpHeight < 0) {
clearInterval(timer);
this.bottom = this.center;
this.jumping = false;
}
}, 20);
Atomic Designを用いているため、極力propsでの依存関係を意識し、グローバルな値で汚染したくありませんでした。
そのため、storeを用いて作成しているのは現在選択している原子番号のみとしています。
export const state = () => ({
atomNo: 10
});
export const mutations = {
SET_ATOM_NO: function(state, data) {
state.atomNo = data;
}
};
そのうちログイン等を取り入れる時は、ログイン情報などを持たせようかなと思っています。
いつやるかとかは未定ですが、スマホ対応したいなと思ってます。PWAにしたいです。スマホで遊べたほうがいいと思うので。
あとは、Googleの某恐竜くんみたいにNightモードを入れたり、電子を打つシューティングモードを入れたりとかしたいですね。
この規模感でAtomic Designを取り入れる必要はない
正直この規模感ではここまで設計をこだわる必要はないかなと思います。
あと、設計について悩んでると「設計とは?」という迷走に入り鬱になるため、分けやすい部分だけ分けて、あとは気になりだすまでは、templatesなどに書いてていいかと思います。
position: fixedと absoluteの使いすぎは発狂しそうになる
ゲームの作り方がよくわからず多用しましたが、あんまり使わないほうがいいです。
レスポンシブとかやろうと思った時が大変です。
設計に関して結構こだわりを持ってやれた
0から作ったことで試行錯誤しながら開発でき、Atomic Designってなんぞ?みたいなところは語れるようになったかと思います。
普段はフォームが多い業務システムを作っているが、ゲーム作りはイベント発火のタイミングとか異なる部分での学びが多かった
普段と全く違うシステムを作ると学びが多いのでオススメです。
とりあえず楽しい
「Atomic DesignでAtomを作る」という半分ネタですが、作ってるとやりたいことが色々出てきて楽しかったです。
正直迷走した部分が多く、ツッコミ等色々ご教授頂けると嬉しいです。
よかったらぜひ遊んで下さい。
Github: https://github.com/daitasu/atomsDash
AtomsDash: https://atomsdash.firebaseapp.com/