5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Y'sAdvent Calendar 2017

Day 2

enchant.jsで画面サイズより広いフィールドの作り方

Last updated at Posted at 2017-12-01

この記事は、株式会社Y's アドベントカレンダー 2日目の記事になります。

enchant.js

#enchant.jsとは

enchant.js」は、株式会社UEIが開発している、JavaScriptのゲームエンジンです。
ゲーム開発に必要な最低限の機能を備えており、ファイルサイズが小さいことが特徴です。
また、様々なプラグインが存在しており、アニメーションや3D機能を追加できます。

#enchant.jsで作ろう

ゲームを簡単に作れます!
あなたのアイデアをガンガン実現させていきましょう!
以下のリンクから「enchant.js」をダウンロードしてみてください。

enchant.jsのダウンロード

#さっそく作ってみる

各ファイルの構成は以下の通りです。

ファイルの構成
├─ css
│   └─ common.css
├─ img
│   └─ sprite.png
├─ js
│   ├─ enchant.min.js
│   └─ my.js
└─ index.html

まずは、実物を見ていただくのが、一番理解しやすいと思っています。
そこで、jsdo.it上に、実際に動かせるサンプルを設置しました。
スイカをモチーフにした、2次元のフィールドになっています。
PCからは画面をドラッグ、スマホからは画面をフリックして、画面を上下左右に自由にスクロールさせてみてください。

サンプル

#HTML

HTMLでは、各cssファイルやjsファイルを読み込むだけです。
そのため、bodyタグの中に何かを記述する必要はありません。

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Suika</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/common.css" type="text/css">
        <script src="js/enchant.min.js"></script>
        <script src="js/my.js"></script>
    </head>
    <body>
    </body>
</html>

#CSS

CSSでは、ブラウザごとに異なる隙間をなくしておきます。

common.css
* {
  margin: 0;
  padding: 0;
  border: 0;
}

#JavaScript

ここではまず、enchant.jsを動かす上で「最低限必要」なコードだけ抜粋します。

enchant();

const SCREEN_WIDTH  = 612;
const SCREEN_HEIGHT = 714;

window.addEventListener("load", () => {

    const core = new Core(SCREEN_WIDTH, SCREEN_HEIGHT);

    core.addEventListener("load", () => {
        // ※ここで、自分が処理させたいロジックを書いていく
    }, false);

    core.start();

}, false);

軽く解説しますと
1.「enchant();」を呼ぶ
2.「Coreのインスタンスcore」を作って、coreの「loadイベント」の中で、自分の処理させたいロジックを書く
3.「core.start();」を実行する
という処理を行っています。

#フリックできるようにする

enchant.jsには、ちゃんと各種イベント処理が定義されています。
今回やりたいことは「スマホでフリックして、画面をスクロールさせたい」というものです。
そこで、touch系のイベント処理を使用します。

// タッチイベント設定
map.addEventListener(enchant.Event.TOUCH_START, (e) => {
    e.target.originX = e.x - e.target.x;
    e.target.originY = e.y - e.target.y;
});
map.addEventListener(enchant.Event.TOUCH_MOVE, (e) => {
    const x = e.x - e.target.originX;
    const y = e.y - e.target.originY;
    e.target.moveField(x, y, e.target);
});

まずは「TOUCH_START」イベントで、最初の座標を保存しておきます。
そして「TOUCH_MOVE」イベントで、新しい座標に移動させます。

#スクロールを補正する

実は、スクロール処理は、際限なくできてしまいます。
そこで、画面で見えている範囲内で、スクロールが収まるように補正する必要があります。

map.moveField = (x, y, map) => {
    const northEdge = 0;
    const southEdge = (SCREEN_ROW_COUNT - map.rowCount) * TILE_SIZE;
    const eastEdge  = (SCREEN_COL_COUNT - map.colCount) * TILE_SIZE;
    const westEdge  = 0;

    // 左にスクロール(マップを右にずらす)し過ぎたら、端まで戻す
    x = Math.min(x, westEdge);

    // 右にスクロール(マップを左にずらす)し過ぎたら、端まで戻す
    x = Math.max(x, eastEdge);

    // 上にスクロール(マップを下にずらす)し過ぎたら、端まで戻す
    y = Math.min(y, northEdge);

    // 下にスクロール(マップを上にずらす)し過ぎたら、端まで戻す
    y = Math.max(y, southEdge);

    map.moveTo(x, y);
}; 

最初は単純に「if文」で処理を書いておりました。
ただ何となく、リファクタリングできそうな気配を感じ取りました。

そこで、数学系のメソッド「min」「max」を利用してみました。
すると、比較的シンプルなコードで実装できたため、このまま正式採用となりました。

#コード全体

最後にコード全体です。

my.js
enchant();

const TILE_SIZE        = 102;
const SCREEN_COL_COUNT = 6;
const SCREEN_ROW_COUNT = 7;
const SCREEN_WIDTH     = TILE_SIZE * SCREEN_COL_COUNT;
const SCREEN_HEIGHT    = TILE_SIZE * SCREEN_ROW_COUNT;
const IMAGE_FILE       = "img/sprite.png";

const MY_MAP = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
    [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];

window.addEventListener("load", () => {

    const core = new Core(SCREEN_WIDTH, SCREEN_HEIGHT);

    core.preload(IMAGE_FILE);

    core.addEventListener("load", () => {

        const mapRowCount = MY_MAP.length;
        const mapColCount = MY_MAP[0].length;
        
        // マップを作成
        const map = new Group();
        
        map.originX  = 0;
        map.originY  = 0;
        map.rowCount = mapRowCount;
        map.colCount = mapColCount;
        
        // 2次元配列をマップに直す
        for (let row=0; row<mapRowCount; row++) {
            for(let col=0; col<mapColCount; col++) {
                const s = new Sprite(TILE_SIZE, TILE_SIZE);
                s.image = core.assets[IMAGE_FILE];
                s.frame = MY_MAP[row][col];
                s.x     = TILE_SIZE * col;
                s.y     = TILE_SIZE * row;
                map.addChild(s);
            }
        }
        
        map.moveField = (x, y, map) => {
            const northEdge = 0;
            const southEdge = (SCREEN_ROW_COUNT - map.rowCount) * TILE_SIZE;
            const eastEdge  = (SCREEN_COL_COUNT - map.colCount) * TILE_SIZE;
            const westEdge  = 0;

            // 左にスクロール(マップを右にずらす)し過ぎたら、端まで戻す
            x = Math.min(x, westEdge);

            // 右にスクロール(マップを左にずらす)し過ぎたら、端まで戻す
            x = Math.max(x, eastEdge);

            // 上にスクロール(マップを下にずらす)し過ぎたら、端まで戻す
            y = Math.min(y, northEdge);

            // 下にスクロール(マップを上にずらす)し過ぎたら、端まで戻す
            y = Math.max(y, southEdge);

            map.moveTo(x, y);
        };      
        
        // タッチイベント設定
        map.addEventListener(enchant.Event.TOUCH_START, (e) => {
            e.target.originX = e.x - e.target.x;
            e.target.originY = e.y - e.target.y;
        });
        map.addEventListener(enchant.Event.TOUCH_MOVE, (e) => {
            const x = e.x - e.target.originX;
            const y = e.y - e.target.originY;
            e.target.moveField(x, y, e.target);
        });

        // マップをシーンに追加
        core.rootScene.addChild(map);

    }, false);

    core.start();
    
}, false);

#まとめ

「enchant.js」はとにかく楽しい!
サクサクゲームを作れる!

今回紹介したノウハウを活用して、オリジナルのブラウザGameを作りました。(3年ほど前ですが。。。)
もしよろしければ遊んでみてください。

SG TAP

PC向け:遊ぶ
SP向け:遊ぶ

[SG TAP]の説明
このゲームは、Start地点「S」から、Goal地点「G」まで、
オレンジ枠をタップしながら、移動していくゲームです。

赤枠が現在地セルで、オレンジ枠が移動可能なセルです。

オレンジ枠のセルをタップして、移動してください。
移動するとそのセルが赤枠に変わります。

セルには将棋の駒が書いてあり、
移動すると、その駒の移動能力を得ます。

そのため、白いセルに移動するとアウトです。

オレンジ枠が常に出ますので、
将棋の駒の動きを覚えなくても、
適当にタップしてゴールできます。

次は 3日目 @yanyan_ys さんの記事です。お楽しみに!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?