ランドストーカー ウォーキングシミュレーター on JavaScript 作成リポート

ランドストーカー ウォーキングシミュレーター on JavaScript 作成リポート












以下の記事は、旧版となります。
今ではCanvasを使った方法に変えてゼロから作り直しましたが、作成の経緯・変遷として残します。
新版の記事はコチラ になります。

覇邪の封印シミュレーターファンタシースター ダンジョンシミュレーター の記事も合わせてお読み頂くと、
コマ切れにしたImageをTableで配置してゲームグラフィック描画に挑むという狂気の世界を垣間見る事が出来ます。

また新版を作成するにあたり、
プログラミング講座のサイト及びyoutube動画の作成者 あきちょん氏に深く感謝します。
一方的に勝手にお世話に成りました。ありがとうございます。
シューティング編のみですが、全部観ました。







初めに

メガドライブの大好きなタイトル、スーパーハイドライド(ハイドライド3の移植版)のシミュレーターを作るべくアレコレやっていて
気付いたらランドストーカーの主人公・ライルをキャプチャーしていました。

発売から29年も経ちますが、今でも色褪せないで私を魅了し続けている稀有なソフトです。
詳しくは そんな偏愛をぶつけた記事 を参照してください。

そんなこんなでカーソルキーでライルを歩かせてみる方向へと舵をきり、とりあえず作り始めてみることにします。
相変わらず方向性が定まりませんので、どうなることやら。



まずは素材


他のシミュレーターの時もそうですが、いきなり html や JavaScript を書き始めずに、まずは画像の用意から始めます。
理由は コードで描画する技術力が無い というだけなので、良い子はマネしないで下さい。

最初は動かして動画で撮影します。
次にその動画をコマ送りして、パターンを数えます。
その後は画像にて保存し、順番をキチンと並べればOKです。

今回の対象・ライルは4方向に動きますので、静止時は4パターンです。
移動時を数えると、各方向でそれぞれ8パターンの計32パターン。
合計すると36パターンの絵が必要になります。

どの状態でも、動き始めは同じという所も確認出来ました。
また移動時から止まる際も、そのまま静止パターンに移行します。
スーパーハイドライドだと移動時の最初のパターンは前回の状態に左右されるので、ランドストーカーは少しだけ楽な仕様です。



素材の加工

いつかツイートしたかもしれませんが、私の作り方が特殊なのか、画像加工に物凄く時間が掛かります。
今回は画像の枚数も36枚だけなんですが、作り始めから加工の終了まで8~9時間程度掛かりました。
加工手順や使用するソフト等に問題が有るのではないかと睨んでいますが、
単純・保守的な人間なせいか他の方法を思いつきません。

実際の流れは、
1. 画像をキチンと並べ直す
2. ファイル名は通し番号にする
3. 8の倍数等のキリの良い数字で切り抜く
4. キャラクターを残して、背景は単色で塗り潰す
という感じです。

3番の工程は、操作をマクロに記述して自動でやっています。
同じ作業の繰り返しはマクロで行うと、物凄く時間効率が良いです。
画像の加工に使うソフトは、御存知MSペイント。
Windows付属のペイントソフトです。

4番の工程は流石にマクロではムリなので、気合の手作業です。
ディスプレイの解像度を下げて、なるべく拡大してドットを塗り潰していきます。
前回の ランドストーカーの記事 にある謎のマップを作る時なんかも同様でした。

実際にどんな風にやってるか、動画撮影しました。


手作業でやってると前述しましたが、実際はJoyToKeyを使ってパッドでやってます。
元の絵と見比べながら背景を潰していきます。
コレを、36回繰り返すだけです。
前回の記事の時と比べれば、今回は割と楽ですね。

単色に塗り潰す理由は、後の工程で別のソフトを使って素材のPNGファイルに透過色の指定をする為です。
とりあえずカーソルキーで4方向に歩くモーションを出したいだけなんですが、一応透過PNGにしておきます。
後に色々なBGを作り、操作に合わせてスクロール出来るようになるかも知れませんので…。

そして加工済みの画像達はコチラ。


気付いた人も居るでしょうけど、実はコレはやり過ぎなんです。
36枚のうち半分は、画像を左右反転させればOKです。
JavaScriptで書くなら、CSSのtransformを指定してあげれば良いわけです。
ファンタシースターダンジョンシミュレーターでは
    Element.style.transform = 'scale(-1, 1)';
のように記述しています。
JavaScriptじゃなくてスタイルシートじゃねェか!という突っ込みはナシでお願いします。

何故ワカっているのに敢えて画像を36枚も加工したのか不思議に思う方も居るかも知れませんが、エラーチェックの為です。
半分は別の背景でキャプチャしてあるので、反転して見比べると
キャラクターと背景の切り分けミスが簡単に炙り出せます。

厳密に言えば18枚では足りません。装備で色が変わるので、もっと必要です。
本来ならパレット書き換えでアッサリ終了なんでしょうが、画像をそのまま使ってるので全て用意しないといけません。
更に言えば実際のゲームでは歩きモーション以外に、
剣を振る・ジャンプする・物を持ち上げる/置く・ダメージで仰け反る・倒れる等の多彩なモーションが有りますので、
ライルを完全再現するには更に多くの画像が必要になります。

ここで気付いた重大な事実として、反転で描画されていると言う事は
・ライルは向きによって、剣の鞘を入れ替えている
・ライルは向きによって、剣を振る際の持ち手を変えている
わけです。

今回の作成過程で気付きました。
30年近く、全く気に成らなかったです。
いやー内藤さん!上手い手抜きですね!!(笑)



HTMLを書く

一番手間が掛かる面倒な作業が終わったので、早速HTMLを書いていきます。
覇邪の封印シミュレーターからの伝統で、中身は
 <script src='LandStalker.js'></script>
と、コレだけにします。
ファンタシースター ダンジョンシミュレーターも同様です。


以上で完成です。
簡単ですね。



まずはプリロード

覇邪の封印やファンタシースターの謎のシミュレーターを作ってる際に言及してきました、プリロードです。
ブラウザで画像を表示させる場合は、たとえイメージがローカルに在っても初回表示の際に一瞬ラグが出来ます。
キャラクターは複数の画像を連続で描画させることでアニメーションさせている為に、結構な「チラつき」が発生します。
それを回避する為には予め全ての画像を表示させてしまえばOKです。

でも予め表示するとなると


このようになり、レイアウト上というよりも明らかにおかしな事になります。
コレを回避する為には 画像のサイズを0px で描画させてしまえばOKです。
実際に搭載したプリロードのコードは

    for (let i = 0; i < strImageRyle.length; i++){
        image = document.createElement('img');
        image.src = strImageRyle[i];
        image.width = numSizePreLoadImage;
        td.appendChild(image);
    }

となります。

numSizePreLoadImage の値は通常は0で、テスト時のみ任意の数値にします。


サイズを0pxにしたところ、完全に居なくなりました。
バッチリですね。コレで安心してライルの歩行モーション作成に取りかかれます。



歩行モーションを書く

ライルの歩行パターンは四方向有りますが、とりあえず一方向だけ作ります。
プログラムですから、残りの三方向はどうせ引数を変えるだけで出来るワケですからね。

    for (let i = 0; i < 8; i++) {
        paintRyle(i, '1', numBaseSizeRyle);
        await wait(numWait);
    }
    paintRyle(8, '1', numBaseSizeRyle);

まずはfor文でこんな感じに書きました。
実際に描画する関数paintRyleの引数は、描画する絵の番号・反転か否か・画像サイズ です。


こんな感じになりました。
一応それらしく動いてはいますが、実際のゲームと違い、左キーで左下向きの歩行です。
更に言うと、一回のキー入力で全てのモーションを連続で表示します。
つまり本物と違い、歩行途中で止まれずに必ず8連続モーション+静止状態になります。
そして最も違和感が有るのが、連続動作時でも「静止時の絵」が挟まってる所です。
最後に静止モーションを入れ無ければ連続歩行時は違和感が出ませんが、キーを離して止まった際に歩行モーションの最後のカタチで止まってしまい、別の違和感があります。

とりあえず動かしてみました的な簡易実装ですね。



四方向化、不具合も直す

そういえばキー入力時の処理を書いてませんでした。
不具合も直した最終形ですが、こんな感じに四方向のカーソルキーとWASDキーに割り振ってます。

    window.addEventListener('keydown', eventKeyDown);
   
    function eventKeyDown(){
        if (numMoving && event.keyCode < 107) return;
        switch (event.keyCode) {
            case 87:  // Up
            case 38:
                numDir = 1;
                moveRyle();
                break;
            case 83:  //  Down
            case 40:
                numDir = 3;
                moveRyle();
                break;
            case 68:  //  Right
            case 39:
                numDir = 2;
                moveRyle();
                break;
            case 65:  //  Left
            case 37:
                numDir = 0;
                moveRyle();
                break;
            case 107:  //  Plus
                numWait += 10;
                break;
            case 109:  //  Minus
                numWait -= 10;
                if (numWait < 10) numWait = 10;
                break;
        }
        paintStatus();
    }

方向キーを押した際、変数numDirに方向を数値で代入しています。
その後に以下のmoveRyle関数を呼びます。

    async function moveRyle(){
        numMoving = 1;
        let i = (numDir == 0 || numDir == 3) ? numMotion : (numMotion + 9);
        let j = i + 8;
        paintRyle(i, strDir[numDir], numBaseSizeRyle);
        await wait(numWait);
        if (++numMotion >= 8) numMotion = 0;
        numMoving = 0;
    }

だったら方向は引数で渡せよって話ですが、eventKeyUpでキーを離した時に静止状態の絵にする為に共用できる変数に方向を格納しています。
一番大事なトコは、変数numMotionです。
コイツは、キー入力を続ける限り1づつ増え続け、8になったら0に戻るようにしてあります。
つまり、必ず0~7の値になるようにしました。
8個の歩行モーションを出し続ける為ですね。

前述のキーを離した際の処理は

    window.addEventListener('keyup', eventKeyUp);
    function eventKeyUp(){
        let numTemp = (numDir == 0 || numDir == 3) ? 8 : 17;
        paintRyle(numTemp, strDir[numDir], numBaseSizeRyle);
        numMotion = 0;
    }

こんな感じです。

コレで、連続に纏まってたモーションも分けられ、間に挟まってた静止モーションもキーを離した時に出て、四方向化も出来ました。

完成形はコチラ。






もう終わり?

とりあえず「ウォーキングシミュレーター」としては完成しました。
前述したように画像加工は9時間程度掛かりましたが、コーディングは3時間弱です。
動画撮影してエンコード、ツイッターにアップしながらですので実際はもっと短いかもしれません。
とりあえず動かす、の状態から思いのほかアッサリと仕上がったので、正直に言えば拍子抜けしてしまいました。

次に思いつくのは剣を振ったりジャンプしたり・・・ですね。
剣を振るのは同様にやれば簡単に出来そうですが、ジャンプとなると難しいです。
と言うのは、このゲームはジャンプ時にはライルのモーションがジャンプモーションになりますが、絶対座標は変わらずにBGが下上とスクロールする事でジャンプを表現しています。
ですので、 “ジャンプする=背景の高速上下スクロール” と言う事になります。

実はそういったコードを書いた事が無いので、難しいかどうかすら分からないのが現状です。
まずは剣を振らせてみたいですね。







御質問・御意見・御感想は@m_o_p_u までお気軽にどうぞ







  << 前の記事 次の記事>> 
イメージ   ファンタシースター ダンジョンシミュレータ ver 0.1 on JavaScript ランドストーカー on JavaScript作成記(2)   イメージ



コメント

このブログの人気の投稿

Ys IVのデバッグモードと未使用ボス

ランドストーカー ~皇帝の財宝~

イース4のデバッグモードを実機で

ランドストーカー on JavaScript作成記(4)

An intruder has penetrated our force field.

ランドストーカー on JavaScript作成記(2)

ランドストーカー on JavaScript作成記(3)

自作の楽しさ

チートの話