【phina.js】牛を避けるだけのゲームを作りました（？）

# webゲーム「牛を避けるだけのゲーム」を作りました

空から降り注ぐ牛を避け続けるゲームです
github pagesにアップしてあるので気軽に遊んでみてください
https://git-gen.github.io/cow_runner
**※ 音が出るので音量注意です！！**

![スクリーンショット 2021-03-04 22.33.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/31bf7b2d-47c8-9b3c-0dc4-e4db3213f743.png)

![スクリーンショット 2021-03-04 22.38.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/0608862f-f42e-4641-abca-df7f7884c7ef.png)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">頭がおかしくなって作ったゲーム<a href="https://t.co/FTnBsgXJzm">https://t.co/FTnBsgXJzm</a><a href="https://twitter.com/hashtag/%E7%89%9B%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%E3%81%A0%E3%81%91%E3%81%AE%E3%82%B2%E3%83%BC%E3%83%A0?src=hash&amp;ref_src=twsrc%5Etfw">#牛を避けるだけのゲーム</a> <a href="https://t.co/yZ2rNfNrQ3">pic.twitter.com/yZ2rNfNrQ3</a></p>&mdash; Gen (@devgeeeen) <a href="https://twitter.com/devgeeeen/status/1365990899193311234?ref_src=twsrc%5Etfw">February 28, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こんな感じのクソゲーの作り方を紹介します

# ゲームライブラリ

phina.jsというゲームライブラリを使用します

https://phinajs.com

使用例はこちらのサイトに沢山用意されているので、
作りたいゲームの参考にしてもらえると良いと思います

http://runstant.com/projects?tag=phina.js

# 雛形

https://github.com/git-gen/parcel-phinajs-example

parcelにphina.jsを入れただけのリポジトリです
phina.jsはパッケージではなくCDNで読み込んでます、
パッケージを使わない理由はnpm・yarnのphina.jsは更新されていないのかバグがある為

**セットアップ**

```bash
$ yarn 

$ yarn dev
```

http://localhost:1234

# ざっくり仕組みを説明

雛形の中のindex.jsが本体になります
まずこれがindex.jsの中身で最低限の設定しかされていない状態です

**parcel-phinajs-example/src/assets/index.js**

```js
// phina.js をグローバル領域に展開
phina.globalize();

// MainScene クラスを定義
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() {
    this.superInit();
    this.backgroundColor = '#fff';
  },
});

// メイン処理
phina.main(function() {
  // アプリケーション生成
  var app = GameApp({
    startLabel: 'title',
    title: 'ゲーム',
  });
  // アプリケーション実行
  app.run();
});
```

`phina.globalize();`はphina.jsで用意されているオブジェクトを呼び出しやすくする宣言です
といっても、これを書かなかった場合は原因不明のエラーが発生してゲームが止まる事が多々あったので、ほぼ必須な気がします

後は`app.run`してあげれば自動でDOMにcanvas要素を作成してくれてゲーム画面が作られます

MainSceneというクラスを定義しています
これはゲーム画面はシーンごとに分かれており
phina.jsではデフォルトで用意されているシーン（タイトル、メイン、リザルトなどがある）を上書きしているものです

# アセットを用意する

フリー素材を使っても良し・自分で作っても良しです
自機や障害物にアニメーションを付けたければ
スプライトシートを作れば簡単にアニメーションをつけることもできます
ちなみにスプライトシートの作成はPiskelでできます（オススメ）

こんな感じで使います

**parcel-phinajs-example/src/assets/index.js**

```js
import bgm from './bgm.mp3'
import player from './player.png'

const ASSETS = {
  sound: {
    'bgm': bgm,
  },
  image: {
    'player': player,
  },
}

...省略

phina.main(function () {
  // アプリケーションを生成
  const app = GameApp({
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    assets: ASSETS,
  app.run()
})
```

# ゲームを作ってみる

例として敵にぶつかるとゲームオーバーになるだけのゲームを作ってみました
MailSceneで定義しているplayerはクリックした位置に移動して動かないenemyに接触するとゲームオーバーとなります
コード内にコメントを記載しているので参考にしてみてください
基礎としてはこんな感じでガンガンコーディングしてクオリティをあげていく感じです

```js
import bgm from './bgm.mp3'
import effect from './effect.mp3'
import player from './player.png'

// phina.js をグローバル領域に展開
phina.globalize();

const SCREEN_WIDTH = 640
const SCREEN_HEIGHT = 960
const OBJECT_POSITION = 800
const ASSETS = {
  sound: {
    'bgm': bgm,
    'effect': effect,
  },
  image: {
    'player': player,
  },
}

// MainScene クラスを定義
phina.define('MainScene', {
  superClass: 'DisplayScene',
  init: function() {
    this.superInit();
    this.backgroundColor = '#fff';
    SoundManager.playMusic('bgm');

    // labelを表示する
    Label('敵ぶつかるとゲームオーバー').addChildTo(this).setPosition(this.gridX.center(), this.gridY.center());

    // 背景の設定方法（backgroundという背景用の画像をassetsに読み込む）
    // Sprite('background').addChildTo(this).setPosition(this.gridX.center(), this.gridY.center());

    // 自機
    this.player = Sprite('player', 64, 64).addChildTo(this)
    this.player.setPosition(200, OBJECT_POSITION)

    // 敵
    this.enemy = Sprite('player', 64, 64).addChildTo(this)
    this.enemy.setPosition(440, OBJECT_POSITION)
  },

  // 毎フレーム更新処理
  // 1フレームごとにこの処理が実行されます
  // デフォルトは30fpsなので1秒間に30回実行されるという事です
  update(app) {
    const p = app.pointer
    // クリックがあったところにplayerを移動させる
    if (p.getPointing()) {
      this.player.setPosition(p.x, p.y)
    }

    // playerがenemyに接触していたらgemeover()を呼び出す
    if (this.player.hitTestElement(this.enemy)) {
      this.gameover()
    }
  },

  // ゲームオーバー
  gameover() {
    // 効果音を再生する
    SoundManager.play('effect');

    // 次のシーンに遷移する
    this.exit()
  },
});

// メイン処理
phina.main(function() {
  // アプリケーション生成
  var app = GameApp({
    startLabel: 'title',
    title: 'ゲーム',
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    assets: ASSETS,
  });
  // アプリケーション実行
  app.run();
});
```

# github

牛を避けるだけのゲームのgithub pagesのリポジトリはこちらになります！
https://github.com/git-gen/git-gen.github.io