phina.jsでゲーム作り入門編①

#1.	ゲーム作成用のフォルダを作りましょう
名前も場所も自由です。
今回は「studyPhina」という名前でフォルダを作りました。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/35c893e7-f2ad-118e-d115-4c93f3b01322.png)



 

#2.	次にHTMLページをつくります。
phina.jsはブラウザ上で動くゲームです。ブラウザで動くということはHTMLがないと動きません。
以下のソースコードをコピペすればOKです。一応１つ１つ何をしているのか読んでみましょうね。

「HTMLって何？？( ﾟдﾟ)ﾎﾟｶｰﾝ」
「HTMLでJavascriptを読み込む？？( ﾟдﾟ)ﾎﾟｶｰﾝ」

って人は、CODEPREPの「WEBの基礎を学ぶ」コースをまずクリアしておきましょう。
https://codeprep.jp/tracks/%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91%20Web%E3%81%AE%E5%9F%BA%E7%A4%8E%E3%82%92%E5%AD%A6%E3%81%B6

```main.html
<!doctype html>

<html>
  <head>
    <meta charset='utf-8' />
    <!-- 画面の横幅にあわせた窓をつくる。ユーザがズームできないように設定している-->
    <meta name="viewport" content="width=device-width, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />

    <!-- ブラウザのタブのところに表示される文字です　-->
    <title>　ゲームつくるぞー | phina.js</title>
    <!-- phina.js をダウンロードして読み込む -->
    <script src='http://cdn.rawgit.com/phi-jp/phina.js/v0.2.0/build/phina.js'></script>

    <!-- ここで自分で作ったJavascriptファイルを読み込んでいる-->
    <script src='main.js'></script>
  </head>
  <body>
    <!-- 肝心のHTMLの中身は実はからっぽなんです・・・！　-->
    <!-- Javascript作るだけでゲームはうごきます -->
  </body>
</html>
```

「色がつかないんだけど・・・？」

ってときには、VSCodeの右下にある「プレーンテキスト」ってところをクリックして、「HTML」へ切り替えましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/53463408-ea7b-7897-78b8-f87b2bc78ae0.png)

 



#3.	終わったらさきほどのフォルダに保存
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/6861dd63-bad7-94a3-1b2a-d083116ec1ae.png)


これで下準備完了です。
基本的に、いま作ったHTMLファイルは、今後さわる必要はありません。
みなさんが作るプログラミングは、次に作るJavascriptファイルの中にだけ書いていきます。

#4. 空っぽのJavascriptファイルをつくりましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/de3a7bcc-0853-4b18-8fb6-324c54beb562.png)

 

#5. main.jsを作っていきましょう。
まずは、もっとも最小の、もっとも基本的なJavascriptコードを書きます。

```main.js
phina.globalize(); // phina.jsがこれで使えるようになります。

// phinaではこうやってClassを定義します
// Classよくわからんって人は、「ここで画面（Scene）を作ってる」とおぼえましょう
// ゲーム業界では画面のことをSceneと呼びます。スタート画面、ゲームプレイの画面、メニュー画面など
// DisplaySceneという「画面全体のボス」から、子供のMainSceneという「ゲームプレイ画面」を作りました
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() { // ここはコンストラクタです。一番最初に一回だけやる処理のこと。
    this.superInit(); // 親クラス（DisplayScene）のコンストラクタを呼んでます。
                      // ←←他にもやりたいことがあるときは、ここに追記していきます。
  }
});

// ここがゲームスタートの入り口です
// 今はGameSceneという画面が１つあるだけなので、ただ画面が表示されるだけです。
phina.main(function() {
  var app = GameApp({
    startLabel: 'main'  // 色んな画面を増やしたいときはここに追加していきます。そのうちやりましょう。
  });
  app.run();
});
```

**※functionの定義の仕方について**

ふつうは、
`function init() {}`
のように定義しますが、オブジェクトの中で定義する場合に限っては、
`init : function() {}`
のようになります。

#6.	Sceneとオブジェクトの関係について
ゲームをつくる上で、まずSceneが必要です。
各Sceneの中に、そのSceneで必要なオブジェクトを置く、というイメージです。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/74fadde7-6871-d224-880f-4d36d5fb9d4e.png)




#7.	上記をふまえてMainSceneに文字オブジェクトを追加してみる
```main.js
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() { // ここはコンストラクタです。要は一番最初に一回だけやる処理のこと。
    this.superInit(); // 親クラス（DisplayScene）のコンストラクタを呼んでます。

　　　// 以下追記です
    // newをする必要はありません
    // 直接、必要なオブジェクトの種類を書くと、そのオブジェクトが作成されます。
    // 文字：Label()、キャラ：Sprite()、円形：CircleShape()とかとか
    // 最後の.addChildTo(this)は、作成されたLabelオブジェクトをMainSceneの子供にするよってことです。
    // まず画面があって、そこに必要なオブジェクトを置く、という流れです。
    var label = Label('オッス、, おらphina.js!').addChildTo(this)
    // これ以降でlabelに対して様々な操作をする
    // 「.（ドット）」でつなげていくことで、オブジェクトに対し色々できます。
    // .addChildToで画面に置いたり、setPositionで置く座標を決めたり
    // Javascriptは最後に「；（セミコロン）」を置くことで、行の終わりの意味になります。
    // つまり上の「var label =」から始まって、下の「gridY.center());」までが１行なんです。
      .setPosition(this.gridX.center(), this.gridY.center()); // 位置を指定
  }
});
```

#8.	次は２つの飛行機を出してみましょう。
 画像は適当にネットから拾ってきて、studyPhinaフォルダに置きましょう。
フォルダの中がごちゃごちゃしないようにimgフォルダを作って、そのなかに置いておくとよいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/34da15b4-6622-72eb-f089-2a69ac6810c1.png)

 
 

#9.	main.js にコードを追記します。

```main.js
phina.globalize(); // phina.jsがこれで使えるようになります。

// こんな感じで画像や音のファイルを指定します
let ASSETS = {
    image:{
        white:"img/planeship/white.png",
        black:"img/planeship/black.png"
    }
};
```
```main.js
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() { // ここはコンストラクタです。要は一番最初に一回だけやる処理のこと。
    this.superInit(); // 親クラス（DisplayScene）のコンストラクタを呼んでます。

    // こんな感じで、飛行機オブジェクトを作って、画面に配置します。
    // WHITE
    let white = Sprite("white", 48, 48).addChildTo(this);
    white.x = this.gridX.center();
    white.y = this.gridY.center();

    // BLACK
    let black = Sprite("black", 146, 96).addChildTo(this);
    black.x = this.gridX.center();
    black.y = this.gridY.span(4);
    black.scaleY *= -1; // Y方向の"大きさ"を逆にすると見た目が逆になります。
  }
});
```
「gridXとかgridYって何だろ？」
以下をご覧ください。実は画面がこのように分割されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/a071c8a7-1bc1-dfc2-d6a1-0c7dd3e4d6fb.png)

 ```main.js
phina.main(function() {
  var app = GameApp({
    startLabel: 'main',  // 色んな画面を増やしたいときはここに追加していきます。
    assets: ASSETS,       // 一番上で指定した画像とかを読み込み
  });
  app.run();
});
```
全部できたら、保存して、main.htmlをブラウザで開いてみると、こんな感じに表示されるはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206887/f803a2f1-30f5-b5aa-f47e-c483038b73f2.png)

 

#10.	白い飛行機を動かしてみましょう
```main.js
    black.scaleY *= -1; // Y方向の"大きさ"を逆にすると見た目が逆になります。
  },　　// ここのカンマ忘れずに。MainSceneの中のinitとupdateです。
  // Scratchでいうと、「ずっと」です
  update:function(app) {
      const key = app.keyboard; // キーボードの状況が入った箱を持ってきます
      if (key.getKey("right")) { // rightボタンが押されたらTrueになります
        white.x += 1;
      }
      if (key.getKey("left")) { // leftボタンが押されたらTrueになります
        white.x += -1;
      }
  }
```
これでいけそうな気がしますが、実はだめなのです。
**「変数のスコープ」** というやつを思い出しましょう。

**『functionの中で定義した変数は、そのfunctionの外では使えない』**

つまり、whiteという変数は上のほうのinit : function()の中で定義されたものなので、
下のupdate : function()の中では使えません。

ではどうすればいいのかというと、initでもupdateでも両方で使えるような共通の変数を作って、そこを経由すればいいんです。

つまり、こういうことです。

```main.js
    // WHITE
    let white = Sprite("white", 48, 48).addChildTo(this);
    white.x = this.gridX.center();
    white.y = this.gridY.center();
    this.white = white;  // MainSceneが持つwhiteという変数に、initが持つwhiteを入れた
```

```main.js
  // Scratchでいうと、「ずっと」です
  update:function(app) {
      let white = this.white; // updateが持つwhiteに、MainSceneが持つwhiteを入れた
      const key = app.keyboard; // キーボードの状況が入った箱を持ってきます
      if (key.getKey("right")) { // rightボタンが押されたらTrueになります
        white.x += 1;
      }
      if (key.getKey("left")) { // leftボタンが押されたらTrueになります
        white.x += -1;
      }
  }
```

修正がおわったら、保存して、白い飛行機が動くことを確認しましょう。

#11.	チャレンジ課題
黒い飛行機を、左右に自動で動くようにしてみましょう

**【ヒント①】**:phinaの座標は、左上が0, 0で、右に行くほどXは大きくなり、下にいくほどYは大きくなります。Scratchとは違うので気をつけましょう。
**【ヒント②】**:blackのX座標を変えればいいだけなので、black.xの値を更新するようにしましょう。