体験授業

講師:大森田不可止



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





spaceshift + space での操作が快適です。

スライドの操作

キー操作
or lスライドを右方向に進む
or h前のスライドに移動
or j下のスライドに移動
or k上のスライドに移動
Space or n次のスライドへ垂直→水平の順に移動
Shift + spaceSpace の順序を逆にたどる。
Home最初のスライドへ
End最後のスライドへ
Esc or o概要表示
f全画面表示。Escで戻す。

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

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

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

ギャラガ

※動画はファミコン版。

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

ウェブの仕組み

Webサーバ

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


ブラウザ

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

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

JavaScript

jsbin.com の使い方

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

オンラインの開発環境

同じIPから多数のアクセスがあると、DDOS攻撃と誤認されて遮断される場合があるため、人数の多い授業では使えない場合がある。しかし、手軽に試せるのでどれかに馴染んておくことをおすすめします。それぞれに違いがあります。ユーザー登録が必要だったり。

Xampp の利用

  • Xampp コントローラを起動して、Apache を起動
  • c:\xampp\htdocs\ (ドキュメントルート) に、フォルダ(例: shooting)を作成する。
  • enchant.min.js をそのフォルダにコピーする。
  • ship.png をそのフォルダにコピーする。
  • エディタを起動して、c:\xampp\htdocs\shooting\index.html を開く。エンコードはUTF-8
  • c:\xampp\htdocs\shooting\index.html のURLは、http://localhost/shooting/index.html でアクセスできる。

html ファイルを直接開く

  • あまりお勧めできない方法だが、作業フォルダに全てのファイルやリソースを置き、そこで完結した形で、htmlファイルを右クリック→プログラムから開く→Google Chrome を選択して、ブラウザから直接開くこともできる。
  • ウェブサーバーが介在しないので、動作がサーバを介した場合と異なるので注意。F5で完全リロードしてくれるメリットは有る。

enchant.js

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

index.html

  • index.html は、ウェブページを表示する骨格にあたります。enchant.js を、ここで読み込むように指示しています。背景を濃紺( #000066) に指定して、何も表示しない状態です。
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="utf-8" />
<title>Shooting</title>
<script src="(https://techc.omorita.com/js/)enchant.min.js"></script>
<style>
body {
  background: #000066;
  padding: 0;
  margin: 0;
}
</style>
</head>
<body>

</body>
</html> 

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( '(https://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['https://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['https://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['httpd://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: ここまでのプログラム






プログラムの改善

プログラムの今後の方針

  • プログラムの全体的な動きや、段取りが見えてきた段階です。重複してる部分や、敵の数、弾の数を増やす方法などを考慮しつつ、構成を見直します。
  • 例えば、スプライトの発生で共通してるのは、frame x y 等の指定。移動させる場合には、x y の更新、画面外に出たかどうかのチェックなど。
  • これらをコーディングする上で、関数を使う方法、Spriteクラスを拡張する方法などがあるので、調べて対処方法を選ぶ。

JavaScript の クラス

  • Sprite のように、ある機能を使いやすいようにパッケージしたものが「クラス」です。
  • var myship = new Sprite(60,60); で、スプライトというクラスから、具体的なスプライトが作られます。
  • myship のクラスの属性を呼び出すのが、"." (ドット) です。myship.image, myship.frame, myship.rotation などに、具体的な値をセットしていきます。

class

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  speak() {
    console.log(this.name + ' barks.');
  }
} 

Spriteクラスの拡張

Sprite クラスに機能を追加した ExSprite クラスを作る。ただし、enchant.Sprite は昔のスタイルのクラスなので、コンストラクタが initialize という名前になっており、super では呼び出せないので、そこだけ修正。
参考: Tips: クラスを継承する | enchant.js

var ExSprite = enchant.Class.create( enchant.Sprite, { // Spriteを継承したクラスを作成する
  initialize: function(size, frame, px, py, rotation, status) { // コンストラクタ
    Sprite.call(this, size, size); // super(size, size);
    this.image = core.assets['https://techc.omorita.com/img/ship.png'];
    this.frame = frame;
    this.x = px;
    this.y = py;
    this.rotation = rotation;
    this.wait = 0;
    this.stat = staus;
    return this;
  },
  setpos: function(px, py, velocity, rotation){
    this.x = px;
    this.y = py;
    this.velocity = velocity;
    this.rotation = rotation;
    this.visible = true;
  }
}); 

ExSprite

ExSprite を使うと、各スプライトの表示は以下のように簡単になる。

    // MyShip
    var myship = new ExSprite(60, 210, 560, [6,7], 0, 1);

    // Enemy
    var enemy = new ExSprite(60, 420*Math.random(), -60, [0,1], 180, 0);

    // bullet
    var bullet = new ExSprite(15, 0, -15, 12*16, 0, 0); 

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

敵の数、弾の数を増やしてみよう

    var enemy = new Array(20);
    for( var i = 0; i < 20; i++){
      enemy[i] = new ExSprite(60, 420*Math.random(), -60, [0,1], 180, 0);
    }
    var bullet = new Array(10);
    for(i = 0; i<10; i++){
      bullet[i] = new ExSprite(15, 0, -15, 12*16, 0, 0);
    } 

少し手を加えたサンプル

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

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

参考リンク