【HTMLとCSSとJavaScript】東京フレンドパークのストッパーキューブリッジのようなゲームを作る【作成編】

children playing a video game プログラミング

こんにちは、コンスキです。

前回はゲームを作るためにどのようなコードを書く必要があるのかを考えました。今回はその考えをもとに実際にゲームのコードを書いていきます。

前回は動かす棒みたいなやつを「キューブ」と呼んでいましたが、スライダーとよんだほうがしっくりくるので、今回は「キューブ」と呼んでいきます。

完成したゲームを実行する

ゲームのコードは3つのファイルに分けて保存します。HTMLのコードは「index.html」、CSSは「style.css」、JavaScriptは「main.js」という名前で保存します。

「index.html」をブラウザに表示させると次のように動作します。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ストッパーキューブリッジ</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="game">
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
    </div>
    <button id="place-btn">置く</button>
    <script src="main.js"></script>
</body>
</html>

上のコードになる過程を説明していきます。

まず下のように<body>要素の中にスライダーが動く範囲を決めるための<div>要素を作っています。この要素には「game」というclass名を付けます。この部分を「ゲームエリア」呼ばせてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ストッパーキューブリッジ</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="game">   //この部分の説明です↑
    </div>            //この部分の説明です↑
    <script src="main.js"></script> 
</body>
</html>

次にスライダーを止めるためのボタンを作ります。ボタンにはわかりやすいように「ストップ」という文字を書いておきます。また、このボタンのidを「stop-btn」にします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ストッパーキューブリッジ</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="game">   
    </div>
    <button id="place-btn">置く</button>  //この部分の説明です↑
    <script src="main.js"></script>            
</body>
</html>

最後に「slider」と「animate」というclass名を付けた20個の<div>要素を「ゲームエリア」の中に作ります。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ストッパーキューブリッジ</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="game">
      //ここから
      <div class="slider animate"></div>  
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      <div class="slider animate"></div>
      //ここまでの説明です↑
    </div>
    <button id="place-btn">置く</button>
    <script src="main.js"></script>
</body>
</html>

CSS

* {
  margin: 0;
  padding: 0;
}
#game {
  overflow: hidden;
  box-sizing: border-box;
  border: 1px solid black;
  width: 500px;
  height: 400px;
  margin: 20px auto;
}
#place-btn {
  height: 200px;
  width: 200px;
  margin: 20px auto;
  display: block;
}
.slider {
  box-sizing: border-box;
  border: 1px solid black;
  visibility: hidden;
  background-color: #7DC8C1;
  height: 20px;
  width: 100px;
  position: relative;
  top: 0;
  left: -100px;
}
}
.visible {
  visibility: visible;
}
.animate {
  animation: slide 3s infinite linear;
}
.stop {
  animation-play-state: paused;
}
@keyframes slide {
  0% { left: -100px; }
  100% { left: 100% }
}

上のCSSの大切だと思う部分だけを説明します。

デフォルトのCSSを変更

* {
  margin: 0;
  padding: 0;
}

この部分は、CSSで何も設定しなくてもデフォルトで効いているCSSを打ち消しています。この設定をしないと、idが「game」になっているdivとブラザの外枠との間に、すこし隙間ができてしまいます。セレクタ「*」を使ってmarginやpaddingを設定しています。

<div id=”game”>の設定

#game {
  overflow: hidden;
  box-sizing: border-box;
  border: 1px solid black;
  width: 500px;
  height: 400px;
  margin: 20px auto;
}

この部分は、スライダーを囲むdivの部分の設定をしています。

「overflow: hidden」を設定することで、スライダーが<div>要素からはみ出たときに、はみ出た部分のスライダーが非表示になります。

<div id=”slider”>の設定

.slider {
  box-sizing: border-box;
  border: 1px solid black;
  visibility: hidden;
  background-color: #7DC8C1;
  height: 20px;
  width: 100px;
  position: relative;
  top: 0;
  left: -100px;
}

この部分は動くスライダーの設定をしています。「position: relative」を設定することで、要素がもともとあった場所からの距離を指定して、スライダーの位置を決めることができます。スライダーをゲームエリアの外に配置するために「left: -100px」を設定します。

アニメーションの設定

.animate {
  animation: slide 3s infinite linear;
}
.stop {
  animation-play-state: paused;
}
@keyframes slide {
  0% { left: -100px; }
  100% { left: 100% }
}

3つのセレクタを使って設定してるこの部分は、アニメーションの設定です。

@keyframes

プロパティをどういうふうに変化させていくかを定義できる「@keyframes」というもの使っています。0%を「lef: -100px」にして100%を「left: 100%」にします。こうすることで、ゲームエリアの左外側からスライダーを登場させて、ゲームエリアの右外側へ消えるアニメーションを定義します。

.animate {…}

このスタイルはスライダーにアニメーションを付けるために設定しています。animationプロパティの値には、先程「@keyframes」で定義した「slide」というアニメーションをつけるために「slide」が書かれています。

動きを止めない限りは何度も繰り返すように「infinite」も書かれています。「linear」は、アニメーションのスピード一定にするものです。

JavaScriptスライダーになる20個の<div>要素にanimateというclass名を外したりします。そうすることでアニメーションを効かせるスタイルを無効にして、スライダーの動きを止めます。

.stop{…}

このスタイルはアニメーションの動きを止めるためだけにあります。「animation-play-state」というプロパティは、値を「paused」にすることでアニメーションを停止させることができます。animateクラスは外すことで、アニメーションを止めますが、pauseクラスは反対に要素につけることでアニメーションを止めます。

animateクラスを外すこととstopクラスを付けることの違い

2つの違いは、アニメーションを止めたときにその場に留まるか、留まらないかというところです。

一番最初に置くスライダーは、「animate」というクラスを外すことでアニメーションを止めると、少し不都合が生じてしまいます。animateというクラスを外すと、スライダーは「left: -100」という最初に設定した位置に戻ってしまいます。

一方で、「animation-play state」プロパティを使うと、アニメーションの途中で止めた場合、止めた位置に要素を留めることができます。

JavaScript

長くなりすぎてしまうため、JavaScriptのほとんどの説明をコメントとして書いてみました。反対に読みづらかったらすみません(汗)

//即時関数というものの中にすべてのコードを書いてグローバル変数を定義しないようにする
(function(){  
  var counter = 0
  var game = document.getElementById("game")
  var placeBtn = document.getElementById("place-btn")
  var slider = document.getElementsByClassName("slider")
  var sliderCount = game.childElementCount  //gameの子要素の数
  var clientRect
  var placedSlider
  var movingSlider
  slider[sliderCount - 1].classList.add("visible")   //一番はじめに置くスライダーを表示しておく
  
  var place = function () {
    counter++     //置かれたスライダーの個数を数える
    //動いているスライダーをおいたら次のスライダーを表示する
    slider[sliderCount - (counter + 1)].classList.add("visible") 

    if(counter === 1) {
      placedSlider = slider[sliderCount - counter]
      placedSlider.classList.add("stop")
      return
    } else {
       //動いているスライダーのDOM要素を取得する
      movingSlider= slider[sliderCount - counter]  
      //placedSliderに有効になっているスタイルを取得する
      var placedCss = getComputedStyle(placedSlider, null)  
      //最後に置かれたスライダーの長さを定義する(この後短い変数名で使えるようにするため)
      var placedWidth = parseInt(placedCss.getPropertyValue("width"))  
      //最後に置かれたスライダーの🔴左端の位置を定義する(この後短い変数名で使えるようにするため)
      var placedLeft = parseInt(placedCss.getPropertyValue("left"))   
      //最後に置かれたスライダーの🔵右端の位置を定義する(この後短い変数名で使えるようにするため) 
      var placedRight = parseInt(placedCss.getPropertyValue("left")) + placedWidth    
      //placedSliderに有効になっているスタイルを取得する
      var movingCss = getComputedStyle(movingSlider, null)
       //最後に置かれたスライダーの長さを定義する(この後短い変数名で使えるようにするため)    
      var movingWidth = parseInt(movingCss.getPropertyValue("width"))
      //動いているスライダーの🔴左端の位置を定義する(この後短い変数名で使えるようにするため)
      var movingLeft = parseInt(movingCss.getPropertyValue("left"))  
      //動いているスライダーの🔵右端の位置を定義する(この後短い変数名で使えるようにするため)
      var movingRight = parseInt(movingCss.getPropertyValue("left")) + movingWidth 
      //もし動いているスライダーの右端が置かれているスライダーの左端よりも左に置かれたら
      if(movingRight < placedLeft || movingLeft > placedRight) { 
        //ゲーム終了と一緒に点数を表示して、リセットするか尋ねる
        var result = confirm("点数" + (counter - 1) + "点です。\nリセットしますか?")  
        if(result) {       //もしリセットするという選択がされれば
          location.reload()   // ページをリロードする
        }                                    
        //もし動いているスライダーの左端が置かれているスライダーの左端よりも左に置かれたら
      } else if(movingLeft < placedLeft) {      
        //はみ出た分だけ短くした長さのスタイル
        var newWidthStyle = "width: " + (placedWidth - (placedLeft - movingLeft)) + "px;"
        //動いているスライダーの左端を置かれたスライダーの左端に合わせるスタイル
        var newLeftStyle = "left: " + placedLeft + "px;" 
        //動いているスライダーのアニメーションを停止させて最初の位置に戻す
        movingSlider.classList.remove("animate") 
         //はみ出た分だけ短くした長さのスタイル
        movingSlider.style.cssText = newWidthStyle + newLeftStyle 
        //動いているスライダーの左端を置かれたスライダーの左端に合わせるスタイル
        slider[sliderCount - counter -1].style.cssText = newWidthStyle  
      } else {
        var newWidthStyle = "width: " + (movingWidth - (movingRight - placedRight)) + "px;" 
        var newLeftStyle = "left: " + (placedLeft + (movingRight - placedRight)) + "px;"   
        movingSlider.classList.remove("animate")
        //長さを縮めるスタイルと位置をずらすスタイルを動いているスライダーに適用する
        movingSlider.style.cssText = newWidthStyle + newLeftStyle  
        slider[sliderCount - counter -1].style.cssText = newWidthStyle
      }
      placedSlider = movingSlider  //「動いている」スライダーを、次の「置かれた」スライダーにする
    } 
  } 
  placeBtn.addEventListener("click", place)  //「ストップボタン」が押されたらplace関数を呼び出す
})()  

おわりに

今回は東京フレンドパークの「ストッパーキューブリッジ」というゲームに似ているゲームを作ってみました。

私はHTML、CSS、JavaScriptの初心者です。人に教えられるような立場ではありませんが、私が説明することが少しでもお役に立てれば幸いです。また、もっとこうしたほうがいいという部分がありましたらコメントで教えていただけたら嬉しいです。

このゲームのコードはこちらの動画で紹介されているものを参考にさせていただきました。

コメント

  1. […] ゲームのコードだけを知りたい方はこちら […]

タイトルとURLをコピーしました