コンテンツにスキップ

enchant.jsの利用

enchant.jsとは?

  • 株式会社UEIによって開発された国産のJavaScriptのライブラリ. Wikipediaの解説

    • 2016年以降,残念ながらアップデートやサポートは行われていません(事業移管)
    • 主としてゲーム開発を(効率良くできるように)支援することを目的として制作されたもの
    • 古いフレームワークだけど,情報やサンプルが豊富.
    • Windows, Mac, iPhone/iPad, Androidのすべてで動作するアプリケーションを作ることも可能(マルチプラットフォーム)
    • ユーザ(や他のプログラム)が起こした操作(イベント)に対する処理を記述していく,という,いわゆるイベント駆動型のプログラミングが必要になります.

演習でのenchant.jsの使い方

次のようなHTMLファイルを作成してブラウザで読み込むと,白いクマが右へ左へ移動する様子が見れます. これは,昔の本家のサイトで表示されていたサンプルプログラムを元に作成したものです.

<!DOCTYPE html>
<html>
    <head>
      <title>enchant.jsサンプル</title>
      <meta charset="utf-8" />
      <script src="http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/enchant.js" type="text/javascript"></script>
      <!-- プラグインも使う場合は必要なscriptタグを下記に追加 -->
      <script src="http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/plugins/tl.enchant.js" type="text/javascript"></script>
    </head>
    <body>
      <script type="text/javascript">
        enchant();  // おまじない

        var IMG = "http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/images/chara1.png"
        var game = new Game(320, 320);
        game.preload(IMG);

        game.onload = function () {
          var bear = new Sprite(32, 32);
          bear.image = game.assets[IMG];
          game.rootScene.addChild(bear);

          bear.frame = [6, 6, 7, 7];   // select sprite frame           
          bear.tl.moveBy(288, 0, 90)   // move right
              .scaleTo(-1, 1, 10)      // turn left
              .moveBy(-288, 0, 90)     // move left
              .scaleTo(1, 1, 10)       // turn right
              .loop();                 // loop it
        };
        game.start();
      </script>
    </body>
</html>

上記のプログラムで,

<script src="http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/plugins/tl.enchant.js" type="text/javascript"></script>

の部分は,プラグインや画像の読み込みを行っています. enchant.js本体,及びそのプラグインはそれぞれ,

http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/enchant.js
http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/plugins/XXX.js

に置いてあります.また,enchant.jsの開発元が提供している画像や音声素材も下記のディレクトリ配下に置いてあります.

http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/images/
(実態は: /home/wikiwiki/wiki/public_html/csd/js/images/ にあります.)
http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/sounds/
(実態の場所は同様です.)

自分たちのプログラムでは,HTMLの<script>タグ部やJavaScript内の必要箇所で,適宜これらを読み込んでください.

  • 12〜30行目を別ファイル(sample.jsとか)にして,<script type="text/javascript" src="sample.js"></script>などと書き換えてもOKです.

事前に理解しておいた方が良いこと

enchant.jsを利用する場合,いくつかのオブジェクトを組み合わせて使用します.基本的なものは以下の三つです.

Core(Game)オブジェクト

  • ゲーム全体を管理して,動かすシステム
  • ゲームの基本的な機能を提供するもの,つまり,このCoreオブジェクトを中心にゲームは動く
  • デフォルトでrootSceneという名前のSceneオブジェクトを一つ持つ

Sceneオブジェクト

  • 視覚要素(Nodeオブジェクト)をまとめたもの
  • 例えば,スタート画面のSceneオブジェクト,プレイ画面のSceneオブジェクト,とか
  • 階層的に重ねることができる(スタック管理)
    • プレイ画面のSceneオブジェクトに,スコア表示のSceneオブジェクトを重ねる,とか

Nodeオブジェクト

  • ゲームを構成する視覚要素
  • 実際にはNodeオブジェクトを継承したオブジェクトを使う
Node系オブジェクト 目的
Sprite 図や画像を表示
Label 文字を表示
Map ゲームマップを表示

enchant.js を用いて作るゲームのひな型は次のような形です.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
enchant();  // 1

window.onload = function() {

    var game = new Game(320, 320);  // 2

    game.preload('preload1.gif', 'preload2.wav');  // 3
    game.onload = function () {
        // ここに処理を書く
    };

    game.start();  // 4
}
  1. 1行目でenchant.jsを初期化.必須.
  2. 5行目でGameオブジェクトを作成(Coreオブジェクトでも可).この場合,横320px,縦320pxのゲーム画面を作成する,ということ
  3. 7〜10行目がGameオブジェクトの初期設定にあたる.
    • 7行目は素材のプリロード(使いたい画像や音楽ファイルを読み込んで,使えるようにしておく)
    • 8〜10行目が,ゲームが動作開始したときに実行されるコード.ここがメイン.gameオブジェクトのonloadメソッドに,ゲームを開始したときに実行したいプログラムを書く形で記述する.シーンを作ったり,メニューを作ったり,・・・
  4. 12行目でゲーム開始.(イベント待ちの無限ループ開始)

なお,7〜10行目には本当に必要なコードだけ(例えばメニューだけとか)書いておいて,ゲーム本体のコードは別のところに書いて呼び出したり呼び出せるようにしたりするのが普通です.


さらに,enchant.js を用いて作るゲームではいくつかの状態が存在し,それぞれの状態に応じたイベントに対してどういう処理をするか,をJavaScriptで記述する形になります.(非同期型イベント処理プログラミング

主要なイベントの例については,このページの下の方を参照してください.

自学用の参考サイト

以上を踏まえて,次のサイトで学んでみましょう.

enchant.jsのオブジェクト

enchant.jsのオブジェクトの種類は以下の通りです.

  • Label・・・文字列表示
  • Sprite・・・画像表示
  • Map・・・タイルを並べて作った画を1つの大きな画像にする
  • Entity・・・Sprite/Label/Mapの継承元
  • Scene・・・描画オブジェクトを貼り付けることが可能な画面オブジェクト
  • Group・・・複数の描画オブジェクトを1つにまとめられる
  • Surface・・・画像や図形のデータを保持
  • Node・・・表示オブジェクトの継承元
  • Core・・・ゲーム画面やメインループ,シーンを管理
  • EventTarget・・・イベントリスナを管理
  • Sound・・・サウンドを管理

継承ツリー

オブジェクト間の継承ツリーは以下のようになります.基本的に,子オブジェクトは,親オブジェクトのメソッドやプロパティを利用できます.

graph TB A[EventTarget] --- B[Core] B --- C[Node] C --- D[Entity] C --- E[Group] C --- F[Surface] D --- G[Sprite] D --- H[Label] D --- I[Map] E --- J[Scene]

描画オブジェクトツリーは以下のようになります.

graph TB A[RootScene] --- B[Group] A --- C[Label] B --- D[Sprite] B --- E[Map] F[Scene] --- G[Sprite] F --- H[Label]

基本的なプログラミング法

以下に書いてあることは, @IT(アットマークIT)の連載記事でも学べますので,説明不足に感じた場合はそちらを参照してください.

画像(スプライト)の表示

Spriteオブジェクトを使います.イメージとしては,画像表示用のオブジェクトを new で作って,それに表示したいキャラクターを登録するようなことを行います.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
enchant();

var IMG = 'http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/images/chara1.png';

window.onload = function() {
    var core = new Core(320, 320);  // var game = new Game(320, 320); でも同じ
    core.preload(IMG);
    core.onload = function() {
        var kuma = new Sprite(32, 32); // <-- 画像サイズに合わせる
        kuma.image = core.assets[IMG];
        kuma.frame = 3;  // 表示したいフレーム番号
        kuma.x = 120;
        kuma.y = 50;
        core.rootScene.addChild(kuma);
    }
    core.start();
}
  • 7行目: スクリプト実行中に使いたい画像ファイル(png,jpg,gifなら可)は,事前にプリロードしておく必要があります.複数の場合は「,」(カンマ)で区切って列挙すればOKです.
  • 14行目: スプライトを実際に表示するためには,表示オブジェクト(ここではrootScene)に追加する必要があります.
  • スプライトの主なプロパティは以下です.(他にもあります)
プロパティ 意味
frame 表示するフレーム番号
image 表示する画像.あらかじめプリロードしておく必要がある
rotation 回転角度
x x座標
y y座標
scaleX x方向の倍率
scaleY y方向の倍率

キー入力検知

Coreオブジェクトのinputプロパティを使います.

12
13
14
15
16
17
18
19
20
21
22
23
24
// 省略
 ...
        core.rootScene.addChild(kuma);
        kuma.addEventListener('enterframe', function(ev) {
            if( core.input.left )  this.x -= 4;  // 左ボタン
            if( core.input.right ) this.x += 4;  // 右ボタン
            if( core.input.up )    this.y -= 4;  // 上ボタン
            if( core.input.down )  this.y += 4;  // 下ボタン
        });

    }
    core.start();
}
  • 表示スプライトのコールバックでキーを検知するようにプログラミングします.スプライトのaddEventListenerメソッドの引数に,イベントタイプであるenterframeと,リスナ(イベントが発生した際に実行されるコールバック関数)を指定します.
  • enterframeイベントは,大雑把に言うと「1秒間にたーくさん発生しているイベント」のことです.ちゃんと言うと,新しいフレームが描画される際に発生するイベント.enterframeイベントは,1秒間に「Coreオブジェクトのfpsプロパティで指定された回数」だけ発生しています.
    • もしcore.fpsが30なら,1秒に30回,enterframeイベントが発生し,その都度,リスナとして登録したコールバック関数が実行されます
    • つまり,1秒に30回,キー入力を検知する,ということです
  • enchant.jsでは,デフォルトで「↑」「←」「→」「↓」「a」「b」の6つのボタンをサポートしていますが,任意のキーを割り当てたければCoreオブジェクトのkeybindメソッドを使えばOKです.引数には,キーコード割り当てるボタン名を指定します.
core.keybind(32, SPC);
  ...

if( core.input.SPC ) { ... }

イベント検知

イベントを検知して処理を実行するには,イベントリスナ(そのイベントが発生したときに実行されるコールバック関数)を使います.

例えば,タッチイベントを検出してスプライトをタッチ移動(ドラッグ移動)させるためには以下のように書きます.

19
20
21
22
23
24
25
26
27
28
29
30
// 省略
 ...
            if( core.input.down )  this.y -= 4;  // 下ボタン
        });

        kuma.on('touchmove', function(ev) { // addEventListenerはonとも書ける
            this.x = ev.x - this.width / 2;
            this.y = ev.y - this.height / 2;            
        });
    }
    core.start();
}
  • イベントリスナを登録するためには,EventTargetオブジェクトのaddEventListenerメソッドを使います.このメソッドは,省略してonとも書けます.
  • onの引数には,イベントタイプリスナを指定します.
  • イベントタイプには多くの種類がありますが,主なものは以下です.
イベントタイプ 発生のタイミング 発行元のオブジェクト
abuttondown [a]ボタンが押されたとき Core,Scene
abuttonup [a]ボタンが離されたとき Core,Scene
bbuttondown [b]ボタンが押されたとき Core,Scene
bbuttonup [b]ボタンが離されたとき Core,Scene
enterframe 新しい描画フレームが開始されるとき Core,Node
touchend タッチが終了したとき Node
touchmove タッチが移動したとき Node
touchstart タッチが開始されたとき Node

アニメーション表示

スプライトをアニメーション表示させるためには,描画フレームごとに画像を切り替えて表示します.要は,パラパラ漫画です.


文字(ラベル)表示

Labelオブジェクトを使います.

  var infolabel = new Label('サンプル');
  infolabel.x = 20;  // 表示位置x座標
  infolabel.y = 0;   // 表示位置y座標
  infolabel.color = '#0000FF';         // 表示色
  infolabel.font = '14px sans-serif';  // 表示フォント  

  core.rootScene.addChild(infolabel);
  • Labelオブジェクトを作る際の引数は「表示するテキスト」ですが,これを省略して,後からtextプロパティで設定することも可能です.
  • 文字の色はcolorプロパティで,フォントはfontプロパティでそれぞれ設定します.色については,以下の指定が可能です.
    • #RGB(各値は16進数,#00fとか)
    • #RRGGBB(各値は16進数,#0000ffとか)
    • rgb(R,G,B)(各値は10進数,rgb(0,0,255)とか)
    • rgb(R%,G%,B%)(各値はパーセンテージ,rgb(0%,0%,100%)とか)
    • rgb(R,G,B,A)(Aは透過率0.0〜1.0,rgb(0,0,255,1.0)とか)
    • 色の名前(blueとか)
  • あたりまえですが,フォントは,その端末(やブラウザ)で表示できるものでなければ正しく表示されません

音を鳴らす

Soundオブジェクトを使うと簡単に鳴らせます.

// 略

var BGM = 'http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/sounds/bgm06.wav';
var SNDEFCT = 'http://wiki.cis.iwate-u.ac.jp/~wiki/csd/js/sounds/se1.wav';

// 略

    core.preload(BGM, SNDEFCT);

    core.bgm = Sound.load(BGM);
    core.se  = Sound.load(SNDEFCT);

    core.onload = function() {
        core.bgm.volume = 0.5;
        core.bgm.play();

        core.se.play();

    // 略    
    }
// 略
  • サウンドファイルも要プリロードです.つまり,core.preloadメソッドで,あらかじめ読み込んでおく必要があります.
  • Firefoxでmp3を再生するためには,enchant.jsの本家で配布されている「sound.as」と「sound.swf」が必要らしいです.(未確認)
  • ブラウザによっては,音がならないときがあるので注意です.上記のbgm06.wavは,Mac上で,Chromeを用いた場合は再生されませんでした(20210527).
  • Soundオブジェクトの主なプロパティとメソッドは以下です.
メソッド 機能
pause() 再生中断
play() 再生開始
stop() 再生停止
プロパティ 設定値
currentTime 現在の再生位置(秒)
duration 再生時間(秒).mp3の場合は取得不可
volume 音量.0〜1の範囲
  • BGMをリピートしたい場合はcurrentTimedurationを比較し,等しくなったタイミングでcurrentTimeをゼロにすることで実現できそうです.(必要な班は詳細を自分達で調べてください)

画面切り替え

複数のSceneオブジェクトを使えば実現できます.

  • シーンは,rootSceneをベースとしたスタック構造になっています.
  • CoreオブジェクトのpushSceneメソッドで新しいシーンを追加でき,
  • CoreオブジェクトのpopSceneメソッドで(push前の)元のシーンに戻せます.
  • 指定したシーンを削除するremoveSceneメソッド,現在のシーンを別のシーンに置き換えるreplaceSceneメソッドなどもあります.