TECH.C 体験授業

講師:大森田不可止



シューティングゲーム・プログラム

シューティングゲームの歴史

  • 1978年: スペースインベーダー(タイトー) 社会現象になるほどの大ブーム
  • 1979年: ギャラクシアン(ナムコ)
  • 1981年: ギャラガ(ナムコ)
  • 1983年: ゼビウス(ナムコ)
  • 1985年: グラディウス(コナミ)
  • 1993年: DOOM(id Software) FPS(First Person Shooter)
  • 1997年: 怒首領蜂(ケイブ) 弾幕系
  • 現在は長い衰退期だが同人ソフトなどでは創られている。

詳しくは シューティングゲーム - Wikipedia

スペースインベーダー

※動画はファミコン版。

  • 日銀が100円玉を大増産したほどの熱狂的ブーム。
  • それまではブロック崩し程度のゲームしか無かった。
  • タイトーはこのブームで一等地にゲームセンターを大量出店。

ギャラクシアン

  • カラフルな画面と曲線的な動きでスマッシュヒット。
  • 背景の星はハードウェアで実装されてる。

ギャラガ

※動画はファミコン版。

  • ピンボールからヒントを得たフューチャーが満載。
  • チャレンジングステージが新設。
  • デュアルファイターというパワーアップシステムを搭載。

ゼビウス


  • サブカル層を中心に大ヒット。ゲームの背景に物語性を持たせた。
  • ただし、高得点者が続出してゲームセンターのインカムは悪化。
  • 地上と空中というその後のシューティングゲームの手本になった。

ゼビウスのグラフィック

  • 当時のハードでもスプライトは8色程度。グレイのグラデーションに、明滅する赤パレットとアニメーションを使って敵の生命感を演出。
  • 回避行動を取るなど、戦略を持った敵であることを暗示。
  • バキュラという敵の素材運送という、主役をスポイルする事による世界観の深みを演出。等々

グラディウス

※動画はファミコン版。

  • パワーアップの仕組みが絶品。
  • 弾幕系の先駆者。

DOOM

  • FPS(First Person Shooter)の最初の大ヒット
  • 欧米で大ヒット。日本では現実感が乏しくほとんど受けなかった。国民性の違いは、ゲームでは重要な考慮事項。

怒首領蜂


  • ハードの進歩に依って可能になった大量弾幕。
  • 弾幕系として2000年前後にシリーズがスマッシュヒット

業務用シューティングゲームの特徴

  • 操作性 ―― (上下)左右移動のジョイスティックとシュートボタン(マイクロスイッチに大きなボタン)。直感的な操作で分かりやすい。
  • リアルタイム性 ―― TV画面が1/60秒毎に更新されるので、その間に次の画面を用意する必要がある。
  • スプライト ―― 画面の任意の位置に表示できるグラフィック。
  • 衰退の原因 ―― ゲームセンターでは数分間で百円を使って貰う必要がある。後期には難易度が上がり、一般ユーザを遠ざけてしまった。

シューティングゲームのデザイン

  • 画面内で動くものが多いので、視認性を高める必要がある。敵の弾は赤など。
  • 納得の行くミス。敵・敵の弾と自機の当たり判定は小さめに設定。敵の弾の速度は抑え気味。
  • 難易度の波を造り、先に行くに従って難易度アップ。
  • 先へ進むことへの動機付け。得点アップでのエクステンド、パワーアップ、見たことのない敵、新しい地形などなど。
  • 操作系によるアレンジ。ジョイスティック、ボタンがない環境でどうするか?自動連射は当然。攻撃ユニットを配置するタワーディフェンス系も、シューティングの進化形といえる。

ウェブの仕組み

Webサーバ

  • サーバソフト … Apche, IIS, Node.js, ...
  • データベース … MySQL, PostgreSQL, ...
  • サーバ言語 … PHP, Java, Ruby, Python, Perl, ...


ブラウザ

IE, Edge, FireFox, Chrome, Safari, ...

  • HTML … コンテンツの骨組みと内容
  • CSS … 見た目を決める
  • JavaScript … 動作を制御するプログラム言語

JavaScript

enchant.js

  • 今回はJavaScript のゲーム向けライブラリ enchant.js を使って作成します。ゲームを作るのに適した様々な機能を提供してくれます。
  • また、プログラムはサーバを意識しなくても作れる jsbin.com というサイト上で作成します。
  • このサイト http://jsbin.com/jukotebabu/edit?html,js,output を開いて、プログラムを始めてみましょう。

jsbin.com の使い方

  • 灰色のライン部分がメニューエリアになります。
    [HTML|CSS|JavaScript|Console|Output]
    から、下に表示するペインの ON/OFF を制御できます。
  • [Output] は、プログラムを書くと直ちに反映してくれるので面白いのですが、落ち着かないので 右上の をクリックして、別画面で実行するようにします。プログラムを書き換えてたら、別画面でリロードすれば、書き換えたプログラムを実行させることができます。
  • GitHub という、プログラム共有サイトの無料アカウントを持っていると、ログインでき 行番号表示などの追加機能が使えるようになります。全機能を使うためには有料登録が必要です。

index.html

  • index.html は、ウェブページを表示する骨格にあたります。enchant.js を、ここで読み込むように指示しています。背景を濃紺( #000066) に指定して、何も表示しない状態です。

JavaScript プログラムのひな形

enchant();  // enchant.js を使えるようにする

window.onload = function() {  // ブラウザにデータが全て読み込まれたら
  var width = 480, height = 640;  // ゲーム画面のサイズを変数に
  var core = new Core( width, height );  // ゲーム画面を作る
  core.rootScene.backgroundColor = "#000000"; // 背景は真っ黒
  core.fps = 30;  // 1秒間に30回更新
  // 事前に画像ファイルは読み込んでおく。別のサーバに置かれている。
  core.preload( 'http://techc.omorita.com/img/ship.png' );
  core.keybind(0x20, 'a');  // space キーに名前を与える

  // メイン処理.
  core.onload = function() {  // 準備が完了したら開始
    // ここに初期化処理を書いていく.

    core.addEventListener('enterframe', function() {
      // ループ処理

    });
  };

  // ゲームをスタート.
  core.start();
}; 

グラフィック素材

  • 60x60 のサイズの、噴射のアニメーション2パターンがある、宇宙船4タイプ、計8パターン。
  • 60x60 の爆発アニメ4パターン。
  • 15x15 の MyShipが撃つ弾と、Enemyが撃つ弾。

MyShipの表示

core.onload = function() { の行の直後に以下を追加。

  // メイン処理.
  core.onload = function() {
    // ここに初期化処理を書いていく.

    // MyShip
    var myship = new Sprite(60, 60);  // 60x60 のスプライト作る
    myship.image = core.assets['http://techc.omorita.com/img/ship.png'];
    myship.y = height - 30;
    myship.x = width/2 - 30;
    myship.frame = [6, 7];   // 6番目と7番目のパターンを交互に表示
    myship.status = 0;
    core.rootScene.addChild( myship );
        

jsbin: ここまでのプログラム

敵の表示

myship表示プログラムの直後に以下を追加。

    // Enemy
    var enemy = new Sprite(60, 60);
    enemy.image = core.assets['http://techc.omorita.com/img/ship.png'];
    enemy.y = 0;
    enemy.x = width/2 - 30;
    enemy.vx = 0;
    enemy.vy = 0;
    enemy.frame = [0, 1];
    enemy.status = 0;
    enemy.rotation = 180;  // 180度回転してこっち向きに
    core.rootScene.addChild( enemy );
        

jsbin: ここまでのプログラム

MyShipを矢印キーで左右に動かす

core.addEventListener('enterframe', function() { の行の直後に以下を追加。ここに書いたプログラムは毎秒30回呼び出される。

    core.addEventListener('enterframe', function() {
      // ループ処理

      // MyShip
      var myshipSpd = 4;
      if( myship.status === 0){
        if (core.input.right) {
          myship.x += myshipSpd;
          if( myship.x > width - 60 ) {
            myship.x = width - 60;
          }
        }
        if (core.input.left) {
          myship.x -= myshipSpd;
          if(myship.x < 0) {
            myship.x = 0;
          }
        }
      }
        

jsbin: ここまでのプログラム

敵を動かす

myshipを動かすプログラムの直後に以下を追加。

    // move Enemy
    enemy.y += 8;
    if( enemy.y >= 640 ){
      enemy.y = -60;
      enemy.x = Math.floor(Math.random() * 420);
    }
          

jsbin: ここまでのプログラム

Bulletの表示

enemy表示プログラムの直後に以下を追加。

    // bullet
    var bullet = new Sprite(15,15);
    bullet.image = core.assets['http://techc.omorita.com/img/ship.png'];
    bullet.frame = 12*16;
    bullet.y = -15;  // out of range
    core.rootScene.addChild( bullet );
        

Bulletの発射

enemyの動きプログラムの直後に以下を追加。

      // move bullet & fire
      if( bullet.y <= -15 ){
        if (core.input.a) {  // Fire
          bullet.y = myship.y;
          bullet.x = myship.x+22;
        }
      } else {
        bullet.y -= 12;
      }
        

jsbin: ここまでのプログラム

衝突判定

bulletの動きプログラムの直後に以下を追加。

      // 衝突判定 enemy & bullet
      if( bullet.y > -15 && enemy.status == 0 ){
        if( bullet.within( enemy, 37 )){
          enemy.frame = [8,9,10,11,13,null];
          enemy.status = 6;
          bullet.y = -15;
        }
      }
        

Enemy の動きプログラムの修正

enemy のstatusを見て動作を変える。

      // move Enemy
      if(enemy.status > 0){
        if(--enemy.count == 0){
          enemy.frame = [0,1];
          enemy.y = 640;
        }
      } else {
        enemy.y += 8;
        if( enemy.y >= 640 ){
          enemy.y = -60;
          enemy.x = Math.floor(Math.random() * 420);
        }
      }
        

jsbin: ここまでのプログラム





第二段階

Spriteクラスの拡張

enchant.Class を使って、Sprite クラスに機能を追加した ExSprite クラスを作る。

var ExSprite = Class.create(Sprite, { // Spriteを継承したクラスを作成する
  initialize: function(size, frame, px, py, rotation, visible) { // コンストラクタを上書きする
      Sprite.call(this, size, size); // 継承元のコンストラクタを適用する
      this.image = core.assets['http://techc.omorita.com/img/ship.png'];
      this.frame = frame;
      this.x = px;
      this.y = py;
      this.rotation = rotation;
      this.wait = 0;
      this.visible = visible;
      return this;
    },
  setpos: function(px, py, velocity, rotation){
      this.x = px;
      this.y = py;
      this.velocity = velocity;
      this.rotation = rotation;
      this.visible = true;
    },
  move(){
      this.y = -Math.cos(this.rotation/180*Math.PI) * this.velocity;
      this.x = Math.sin(this.rotation/180*Math.PI) * this.velocity;
      if(this.checkOut()){
        this.visible = false;
      }
    },
  checkOut(){
    if(this.x < -this.width || this.x >= 480 + this.width){
      return true;
    }
    if(this.y < -this.height || this.y >= 640 + this.height){
      return true;
    }
    return false;
  }
});

少し手を加えたサンプル

シューティングゲームの骨組みだけ

  • スコアを付ける
  • グラフィックを加える
  • 連射出来るようにする
  • 効果音を付ける
  • 敵機のパターンを増やす
  • 背景をスクロールさせる
  • 自機を複数繋げる
  • 難易度の波を付ける

参考リンク