【phina.js】牛を避けるだけのゲームを作りました(?)


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

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

プレイ動画(Twitter)

スクリーンショットを見ればすぐわかると思いますが、クソゲーです
今回はこんな感じのクソゲーの作り方をちょっと紹介します

ゲームライブラリ

当たり判定など大変そうな事はやりたくないので素直にゲームライブラリを使います
webゲームには有名どころでPhaserなどがありますが、
あまり時間をかけずにサクッとゲームを作りたいのであれば「phina.js」がオススメです

phina.jsは日本製のjavascriptのwebゲームライブラリで使った感想はこんな感じ

  • セットアップが楽
  • 仕組みがシンプル
  • runstantというサイトに沢山サンプルがあるので参考にできる
    とにかくすぐにゲームとして形にできます

雛形

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

セットアップ

$ yarn 

$ yarn dev

ざっくり仕組みを説明

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

parcel-phinajs-example/src/assets/index.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

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に接触するとゲームオーバーとなります
コード内にコメントを記載しているので参考にしてみてください
基礎としてはこんな感じでガンガンコーディングしてクオリティをあげていく感じです

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