この記事は CSS Advent Calendar 2019 16日目の記事です。
概要
CSSで昔懐かしのベルトスクロールゲームを作りました。
PC、画面サイズ大きめで遊んでください><
https://codepen.io/Rin_T_T/pen/MWYjJKv?editors=1100
本記事はあくまで作った物の簡単な説明のため、コード,制作過程を一部省略しています。
設計書
必須機能をまとめます。
衝突判定: hoverで判定
ゲーム画面のスクロール: transitionで実装
スタート: hoverで判定
スコア用のアイテムを設置: checkboxで実装
キャラクターの移動: カーソルを画像に置き換える。
早速作っていきます。
最初にスクロールエリアと衝突オブジェクトを作成します。
.gameArea_inner
.playArea.-test2
- for(var i = 1; i <= 50; i++)
.item.-object(class='-o' + i)
衝突判定を実装します。
.item.-objectをhoverすると兄弟要素のFailが最前面に表示するようにします。
※faile要素を最前面に維持するため、.faile要素自体にもhover状態を指定しておきます。
ひとまず判定が通ることが確認できれば良いでしょう。
.gameArea_inner
.playArea.-test2
- for(var i = 1; i <= 50; i++)
.item.-object(class='-o' + i)
+ .faile
.faile_inner
.faile_contents
.faile {
position: absolute;
width: 100%;
height: 100%;
z-index: -100;//初期状態では非表示
display: none;//初期状態では非表示
&:hover{
opacity: 1;
z-index: 100;
display: block;
}
&_inner{
display: flex;
}
&_contents{
text-align: center;
background-image: url('https://portfolio.littledemon.pw/cssadvent/failed.png');
background-size: 386px 160px;
width: 100%;
height: 100vh;
& > *{
margin-top: 15px;
}
}
}
.item{
width: 30px;
height: 30px;
background-color: #9c290d;
position: absolute;
z-index: 100;
opacity: 1;
&.-object{//衝突オブジェクトクラス
position: absolute;
&:hover{
& ~ .faile{
z-index: 100;
opacity: 1;
display: block;
}
}
}
}
ゲーム画面のスクロールを実装します。
.gameArea_innerのサイズをプレイエリアとし最大値を560vwに設定します。
animationを指定し、スクロールスピードを設定します。
ついでにスタート/リスタート用のanimationも作っておきます。
.gameArea{
&_inner{
width: 560vw;
display: flex;
position: relative;
z-index: 0;
left: 0;
animation: areaScroll 70s linear forwards;
}
}
@keyframes areaScroll {
0% {
position: relative;
left: 0vw;
}
100% {
position: relative;
left: -560vw;
}
}
@keyframes areaScrollBack {
0% {
position: relative;
}
100% {
position: relative;
left: 0vw;
}
}
スクロールを制御できるスタート/リスタートを作成します。
CSSは常に親から子へもしくは兄弟要素のみ指定できます。
スタートはスクロールしている要素と同じレイヤーに配置します。
hoverで先ほど作成したareaScrollBackを発火できるよう設定します。
+ .wrap
+ .gameArea
+ .startArea
+ .startChecker
+ .startLine
+ .startLine_text START
.gameArea_inner
.playArea
.item.-object.-ribbon.-top
.item.-object.-ribbon.-bottom
- for(var i = 1; i <= 50; i++)
.item.-object(class='-o' + i)
.startArea{
display: flex;
z-index: 10;
&:hover + .gameArea_inner{// 兄弟要素を指定し、animationを発火する。
animation: areaScrollBack 150s ease forwards;
}
}
.startChecker{
width: 160px;
background: linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%),
linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%);
background-color: white;
background-size: 40px 40px;
background-position: 0 0, 20px 20px;
}
.startLine{
background-color: white;
height: 100%;
padding: 0 15px;
&_text{
writing-mode: vertical-rl;
height: 100%;
text-align: center;
}
}
.gameArea{
width: 100%;
height: 100vh;
background-color: white;
overflow: hidden;
display: flex;
&_inner{
~~~
}
}
スコア用のアイテムを作成します。
.wrap
.gameArea
.startArea
.startChecker
.startLine
.startLine_text START
.gameArea_inner
.playArea
.item.-object.-ribbon.-top
.item.-object.-ribbon.-bottom
- for(var i = 1; i <= 50; i++)
.item.-object(class='-o' + i)
+ - for(var i = 1; i <= 24; i++)
+ label.present
+ input(type="checkbox")
+ .present_item(class='-p' + i)
.present{
&_item{
position: absolute;
width: 40px;
height: 40px;
display: block;
background-size: 30px 30px;
transition: left 7s;
&.-p1{//ゲームエリア上の位置(checkboxがfalseの時)
top: 45vh;
left: 20.5vw;
}
}
& input{
display: none;
&:checked {
& + .present_item {
pointer-events: none;
transition: left 4s;
&.-p1{//アイテムを取得した後の位置(checkboxがtrueの時)
top:60vh;
left: 585vw;
}
}
}
}
}
scssが少し複雑ですね、メインのデザインは.present_itemに担当してもらいます。
input要素は非表示にしておき、checkBoxがtureの時、後述するゴールエリアに遷移するように設定します。
キャラクターの移動
Cursolを画像に変更します。
利用できるサイズは最大128128のようですが、
ブラウザの互換性から考えると3232が推奨のようです。
※今回は少し小さかったため、64pxにしました。
以上で完成です。
反省点。
遊んでいただけると気づくかもしれませんが、hover要素はカーソルの移動時に現在位置を再取得します。強制スクロールというゲーム上、衝突オブジェクトの手前で停止するとhoverの判定されず貫通します。
とりあえずゴールを見たいという人はカーソル放置でゴールまでたどり着きます(笑)
スコア用のカーソル衝突オブジェクトはもっとCSS芸的なもので、頑張りたかった...時間が足りませんでした...
chrome PCのみの対応です。