phina.jsでゲームをつくったので制作過程を公開（バラ）します

どうも。utyoと申します。
今年も[phina.js](http://phinajs.com)アドベンドカレンダーに参加させていただきました。


さて、先日phina.jsを使って「寺井、キミってやつは…」というゲームを作りました。
![TitleBack.png](https://qiita-image-store.s3.amazonaws.com/0/62035/665d1b23-82e4-29b2-1fad-d308fb39e4e9.png)

こちらから遊べます。
http://cachacacha.com/GAME/Teraikimi/


この記事ではゲームの紹介がてらどんな感じで制作したか書いていこうと思います。
趣味で作ってる程度のものですが、これからゲームを作りたいという人向けに参考ぐらいになれば幸いです。

というわけでこのゲームの制作過程ですが、だいたい３つに分けられます

* 企画
* 絵
* プログラミング

です。

#企画

通勤中電車を待ってる時に「会社行きたくない。誰か電車止めてくれ」と思って、誰かが電車を止めるゲームを作ることにしました。
テリーマンみたいに走ってくる電車から子犬を守る設定にすれば分かりやすくなる気がしたので主人公の名前を「寺井」にして、せっかくなんで電車だけじゃなくて色々襲い掛かってきたほうがおもしろいなと思ったので陸上部とか怪獣も出すことにしました。
ついでに止めるだけじゃなくてぶん殴ってぶっ飛ばしたほうが気持ちいいので、ぶんなぐってぶっ飛ばすことにしました。
そんな感じで固まったので、作ります。

#絵

絵についてはドット絵でやることにしました。
ドット絵は根気があればなんとかなる気がするので絵心がない人におすすめです。

使ったツールは次の３つです。全部無料です。

* [EDGE](http://takabosoft.com/edge)
* [TexturePacker](https://www.codeandweb.com/texturepacker)
* [PhotoScape](http://www.vector.co.jp/soft/winnt/art/se492136.html)


**EDGE**
EDGEはドット絵を描くためのエディタです。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/51df8ee5-44ab-b62f-c538-591d197bd2c2.png)
こんな感じでドット絵を描いて出力できます。

ちなみにドット絵の描き方とEDGEの使い方についてマジで死ぬほどタメになるサイトがあるので紹介します。
[ドット絵描こうZ](http://blog.livedoor.jp/dotez/)
アニメーションの講座とか超ありがたいです。

**TexturePacker**
TexturePackerはスプライトシートを作成するためのツールです。
スプライトシートというのは画像が繋がってる画像で、こんなやつです。
![rikuzyo.png](https://qiita-image-store.s3.amazonaws.com/0/62035/22c4ffb9-749c-0d5c-4ae9-cb81e78e3a5b.png)
phina.jsはこのスプライトシートを読み込むことでアニメーションを作ることが出来ます。

EDGEで描いた画像をつなげてスプライトシートを作るわけですが、Gimpなどの画像編集ソフトでいちいち自分で画像をつなげるのは非常に面倒です。
それがTexturePackerを使うと超ラクになります。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/d910a946-a543-5021-8656-fdbfd4724439.png)

使い方は簡単で、画像をドラッグアンドドロップするだけです。
有料版と無料版があるのですが、自分は無料版で事足りてるので無料版を使ってます。が、注意点があります。
まず無料版では大きいサイズの画像は作れないというのと、無料版では使えない機能があるので、それを全部オフにするのがやや面倒です。
具体的には

* AlgorithmをBasicにする
* Png Opt Levelを0にする
* Detect identical spritesのチェックを外す（Layoutのshow advancedを押すと出てくる）
* Trim mode をnoneにする

こんな感じで設定します。面倒ですが自分で画像くっつけるよりマシです。

**PhotoScape**
画像サイズを一括で拡大するときに使います。
EDGEで出力した画像はちっちゃいので、これで良い感じの大きさにします。
あってもなくてもいいですが。あると便利です。

#プログラミング
最低限の絵が用意できたら、だいたいのゲームの流れを網羅したプロトタイプを作って、後から絵を描いて追加したり、プログラムを追加したりしてゲームを作っていきます。

プログラミングについて全部解説するとクソ長くなるし他の記事読んだ方がいいと思うので、ポイントだけ書いていこうと思います。

##タッチ処理

まず画面をタッチした時の処理がこちら。

```javascript:MainScene.js
  onpointstart: function(e){
    switch (this.Player.MoveMode) {
      case "Normal":
        this.Player.CatchAction();

        break;

      case "Kamae":
        this.Player.RendaStart();

        this.bg.tweener
        .clear()
        .to({y:this.gridY.center()}, 50)
        .to({y:this.gridY.center(0.2)}, 50)
        .to({y:this.gridY.center(-0.2)}, 50)
        .to({y:this.gridY.center()}, 50)
        var bokoboko = BokoBokoEffect().addChildTo(EffectGroup);
        var toucheffect = TouchEffect(e.pointer.x,e.pointer.y,2).addChildTo(EffectGroup);

        break;


      case "Renda":

        this.bg.tweener
        .clear()
        .to({y:this.gridY.center()}, 50)
        .to({y:this.gridY.center(0.2)}, 50)
        .to({y:this.gridY.center(-0.2)}, 50)
        .to({y:this.gridY.center()}, 50)
        var bokoboko = BokoBokoEffect().addChildTo(EffectGroup);
        var toucheffect = TouchEffect(e.pointer.x,e.pointer.y,2).addChildTo(EffectGroup);

        this.Player.RendaAdd();

        break;


      case "GameOver":

        break;

      default:

    }

```

onpointstartに書いた処理は画面をタッチしたときに動きます。

主人公の状態によって処理を分けています。

普通に立ってるときにタッチすると、主人公は敵をキャッチするアクションをします。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/c0b5df41-7060-6a72-2c12-9975b9f961cb.png)


構えてるときにタッチすると連打を開始、連打してるときにタッチすると、連打回数を加算したりヒットエフェクトを出す処理に飛びます。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/dbba0273-5c34-d6d8-8d25-065daad0c92c.png)

同時に、背景画像をtweenerを使って一瞬移動させることで画面が揺れるエフェクトをかけます。

更にタッチした場所にタッチエフェクトを生成します。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/208ff75b-1f65-8fde-4a68-cf5d5ae0d033.png)

あと画面全体にまんべんなく「ドカ」とか「バキ」とか文字を出すボコボコエフェクトというのを生成します。
ボコボコエフェクトは乱数を使うことで画面上のランダムな場所に文字を生成します。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/f18fd7cc-cbb9-ff04-c84b-e5baf54764d6.png)



##連打

主人公が敵をキャッチしたあとは、一定時間内に目標値まで連打します。
以下は連打の受付時間をカウントしている部分です。

```javascript:Player.js
              case "Renda":

                this.RendaTimer += app.deltaTime;

                if(this.RendaTimer > this.RendaTimeRemit){
                  this.RendaCount = 0;
                  this.Miss();
                  this.Enemy.Run();
                  this.RendaEffect.remove();
                  this.RendaEffectSS.remove();

                }

                break;

```

app.deltaTimeを使うと正確な時間を計れます。
処理が重くてカクカク動いてる時でも1フレームにかかった時間を加算するのでfpsに影響されず時間を計れる感じです。
これを使わないと、カクカク動くほど連打受け付け時間が長くなってゲームが楽になります。

連打時間を超えると、主人公は弾き飛ばされ、敵が走り抜け、連打エフェクトが消えます。


##必殺アクション


![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/24993673-88aa-53c5-0f5c-c772f49b8a8a.png)


連打に成功すると必殺アクションに移行します。
以下は必殺アクションに移行する時のコードです。

```javascript:MainScene.js
  HissatuMove: function(){
    this.BlackBG = RectangleShape().addChildTo(BackGroup);
    this.BlackBG.width = SCREEN_WIDTH * 2;
    this.BlackBG.height = SCREEN_HEIGHT * 2;
    this.BlackBG.fill = "black";

    var Flash;

    var self = this;


    this.tweener
      .clear()
      .call(function(){
        Flash = Sprite("Flash").addChildTo(BackGroup);
        Flash.setSize(SCREEN_WIDTH,SCREEN_HEIGHT)
        Flash.setPosition(self.gridX.center(),self.gridY.center(1));
        Flash.tweener
          .clear()
          .wait(300)
          .to({alpha:0}, 1000)
          .wait(300)


      })
      .wait(1400)
      .call(function(){

        self.TutorialText.text = "押せ！";
        self.TutorialText.scaleX = 1.2;
        self.TutorialText.scaleY = 1.2;
        self.TutorialText.tweener
          .clear()
          .to({scaleX:1,scaleY:1}, 50)
        self.TutorialText.rotation =-10;
        self.CreateHissatuButton();

      })
      .to({alpha:0}, 1000)
      .wait(300)
      .call(function(){
        Flash.remove();

      })
  },
```

だいたいtweenerを使ってやってます。手軽に動きをつけられるので楽です。
まず最初に背景を真っ黒にします。これは黒くて大きい四角を背景の前に置いているだけです。
そして、なんかそれっぽい雷を出しておきます。

雷が徐々に消えるので、消えたタイミングぐらいで必殺ボタンを生成します。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/5c859482-a57a-9a22-ca48-8852850c5d66.png)




必殺ボタンが押されたとき、必殺ボタンのonpointstartが動き、そこから以下の処理が呼ばれます。

```javascript:MainScene.js
  PushHissatuButton: function(){

    this.PushHissatuCount++;
    if(this.PushHissatuCount >= this.HissatuButtonMax){
      this.KnockOut();
    }

  },

```

ボタンを押した回数をカウントして、全部押したらノックアウトする処理を走らせます。
コードは省略します。K.O.って文字を出して、主人公が昇竜拳出して、敵をぶっ飛ばします。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/e6350c66-840d-4f93-4c9c-86270a6112c6.png)



##エフェクト
自分なりにエフェクトをつけてみました。
エフェクトがあるとプレイヤーがした操作が視覚的にわかりやすくなります。

###タッチエフェクト
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/208ff75b-1f65-8fde-4a68-cf5d5ae0d033.png)

タッチエフェクトについては、画像を使わずにphina.jsの図形描画機能で作っています。
中を透明にした白いボーダーラインの円の図形と
角を増やした星型の図形を一緒に出すことで、それっぽく見せています。

```javascript:MainScene.js

phina.define("TouchEffect", {
    superClass: "DisplayElement",
    init: function(X,Y,scale) {
      this.superInit({
        width: 550,
        height: 550,
        fill: "green",
        stroke: null,

      });

      var shape = CircleShape().addChildTo(this);
      // 位置を指定
      shape.setPosition(X, Y);
      shape.fill = 'rgba(0,0,0,0)';
      shape.stroke = 'white';
      shape.strokeWidth = 2 * scale;
      shape.radius  = 180;
      shape.tweener
      .clear()
      .to({alpha:0,scaleX:scale,scaleY:scale}, 500,"easeOutCubic")
      .to({alpha:0}, 200,"easeOutQuint")
      .call(function(){
        shape.remove();
      })

      // 図形をシーンに追加
      var star = StarShape().addChildTo(this);
      // 位置を指定
      star.stroke = 'red';
      star.fill = 'yellow';
      star.setPosition(X, Y);
      star.sides = 11;
      star.sideIndent = 0.6;
      star.strokeWidth = 11;
      star.radius  = 90;
      star.tweener
      .clear()
      .to({alpha:0,scaleX:scale,scaleY:scale}, 300)
      .call(function(){
        star.remove();
      })

    },

    update: function(app) {


    },

});

```

図形を生成したあとtweenerを使って、徐々に広がりつつ透明にしています。
scaleX,scaleYの値を変えてサイズを大きくしています。
radiusの値を変えて大きくすることもできますが、処理が重くなるので、scale使ったほうがいいです。
一回それで大量に生成して死にました。


###キャッチエフェクト
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/eb277e4b-b067-3c62-1e63-054c3c539120.png)

インパクトの瞬間に円を出しています。格ゲーでガードした時とかを参考にしました。

タッチエフェクトと同じ方法で出しています。
タッチした瞬間に主人公から出る円と、敵をキャッチした瞬間に出る円があり、重なると良い感じになります。

あとキャッチした瞬間に画面が一瞬白くなります。白い大きい四角を一瞬生成して消してるだけです。

###炎エフェクト

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/6ee21314-befe-5be2-e91c-fedeae7f4819.png)


phina.jsのパーティクルのサンプルをほぼそのまんま使っています。
http://phiary.me/phina-js-tips-fire-effect-particle/


###煙エフェクト

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/62035/89f6dc07-7e1b-82c9-47d5-bdb6530a1ecd.png)


敵を止めたときに足元から煙が出てます。
これは炎エフェクトをちょっと変えたら作れます。
パーティクルの図形を四角にして、色をクッキリさせて、サイズと速度の調整をするだけです。


##その他

###パンチボタン
![PunchButton2.png](https://qiita-image-store.s3.amazonaws.com/0/62035/1e84d24d-e47f-dde6-dcfe-72e71adbdbda.png)
拳のイラストはフリー素材を改変したものを使ってます。
http://free-illustrations.gatag.net/tag/拳

###動画
win10を使ってるひとはwindowsキー+Gでゲームの録画ができて便利です。
自分は撮った動画をAviUtilとかで編集してツイッターにあげたりしてます。






##おわり

こんな感じでゲームが完成したらサイトなりにあげてツイッターで宣伝とかして終わりです。

ちなみにトータルの作業時間でだいたい１～２週間ぐらいでした。
簡単なゲームなら１日で作れてしまうので、興味もった方はつくってみてください。

あとサイトの宣伝させてください。作ったゲームが置いてあります。

[かちゃコム](http://cachacacha.com)

それでは、これで失礼します
読んでくださった方ありがとうございました。

「ええ。勉強させていただきましたよ」

なっ・・・！お、おまえは・・・！

![nigaoe_taikoubou.png](https://qiita-image-store.s3.amazonaws.com/0/62035/406b99bc-11ad-0eb7-2b24-db2181fb9ca7.png)

太公望・・・！！！


おわり