ヤバウチといっしょ

マジで誰も見てないブログ

自作ゲーム 進歩⑧

俺だ、ヤバウチだ。

前回の11/23の更新から1週間、何をしていたかというと。

今まで書いたコードの書き直しをしていた。

その中でバグを見つければ、逐次修正も行った。

今までのワイはclass構文を使っていなかったが、

今回の書き直しで全てをclass構文に置き換えた。

developer.mozilla.org

最初は「新しいこと覚えるの面倒くさいなぁ」と思っていたが、class構文は確かに書きやすい。


        class Example {
            eventHandler = (e) => {};
            
            constructor(prop) {
                this._prop = prop;
            }
            
            static type = 'AAAAA';
            
            get prop() {
                return this._prop;
            }
            set prop(prop) {
                this._prop = prop;
            }
            
            sayProp() {
                console.log(`prop: ${this._prop}`);
            }
            
        }
    

こんな感じに書ける。

ただ、なんか気になるのが、staticの扱いだ。

↑のExampleクラスを継承したクラスにも静的プロパティとして、

typeプロパティが定義される挙動がなんか不自然だと思った。


        class ExtendedExample extends Example {}
        
        console.log(`${ExtendedExample.type}`); // 'AAAAA'と出力される。
    

ExtendedExample = Object.create(Example)

↑こういう処理になっているのだろうか。まあいいや。

まあまあ順調なので続けて頑張りたい。

自作ゲーム 進歩⑦

youtu.be

最近寒くて足が冷えることヤバウチだ。

↑はインベントリとオブジェクト動的生成のデモだ。

インベントリの部分について

難しく思うのは、マウス操作などのユーザーの操作を通して、アイテムを操作することについてだ。

マウスイベントやキーイベントに対応すればするほどビューの操作が膨らんでいく。

あと、このへんの実装のお手本を知らないので、コードがとっ散らかっている。

動的生成の部分について

まず、設定オブジェクトを引数にしてゲームオブジェクトを組み立てるクラスを作った。組み立ての詳細は

  • モデルクラスをモデルコンフィグを引数にnewする
  • ビュークラスをビューコンフィグを引数にnewする
  • できたモデルとビューを関連付ける(ビューがモデルのプロパティ変更イベントを監視する)

となっている。

そして、このクラス自身にもイベントエミッターをつける。↑の組み立てが完了した時に'created'イベントを発火し、購読コールバックに出来上がったモデルとビューを渡す。

このイベントをコントローラーが購読して、

  • モデルをアップデートリスト(毎フレームモデルの更新メソッドを呼ぶ)に加える
  • ビューをドローリスト(毎フレームビューの描画メソッドを呼ぶ)に加える

ようにハンドリングする。

すると組み立てられると同時にそのモデルとビューは、コントローラーの制御下に加わることになる。

↑の動画内でも、アイテムビューがドロップされたとき、

アイテムビューの'dragEnd'イベントが発火して、

それをアイテムリストビューがハンドルしてインベントリ内にドロップされたのか、それともその外にドロップされたのかを判断して、後者だった場合、そのアイテムビューの'use'メソッドを呼び出す。そしてそのメソッド内でモデルとビューを組み立てるクラスインスタンスのメソッドを呼び出している。

次にやりたいこと
  • 殺風景なので床タイルを敷き詰められるようにしたい
  • イメージローダーみたいなもの。(画像を読み込まれるまでちゃんと待つ処理をまだ作っていない)
  • パーティクルシステム
  • デモゲーム
  • クラス構文使ってないところの書き直し
  • オブジェクト間の関係の整理

end...

 

 

 

自作ゲーム 進歩⑥

無職になって2ヶ月、ヤバウチだ。

更新していなかった先週はPhaser3を触っていた。

phaser.io

vscodeやnodejsや、webpackの設定は以前からしていたので、環境構築には手間取らなかった。そしてPhaser3の概要を掴むために↓のイントロダクションをやった。

phaser.io

コールバックを理解していないとちょっと難しいとは思うものの、かなり宣言的にプログラミングができる。簡単に最初のPhaser3のゲームを作ることができた。

  • この画像をテクスチャに使うぞ!
  • この物理ボディにこのテクスチャ使うぞ!
  • この物理ボディは画面端で跳ね返るぞ!速度はこうで、弾性はこうだぞ!
  • プレイヤーと足場は衝突するぞ!衝突した時のハンドラはこれだぞ!
  • アニメーションを作るぞ!この設定オブジェクトから作ってくれな!

...こんな感じでしたいことを並べていけばいい、そしてそのしたいことの詳細は一切知らなくていい...そんな感じ。すげええええと思った。

もうPhaser3でゲーム作れるじゃん!と浮かれた俺は、APIリファレンスや豊富なデモを参考に数日色々試した。

しかし、色々試すうちに「使いこなすの難しいな...」と苦しむようになってしまった。

あんまり深入りせずに素直に使うなら、用意されたメソッドに既定の設定を与えて使うだけでいいけども、少しだけ既定とは違う設定にしようとしたときに、APIリファレンスを結構読まないと、意図した動きにならなかったりする。dynamicBodyとか。設定が山ほどある。どれがどれだかわからないぐらい沢山あるので大変だ。

パーティクルシステムとかも特にわかりづらく思える。sceneのメソッドやプロパティから直接パーティクルエミッターを触る方法とかが調べても調べてもわからなかった。

sceneに色々textureやらsoundやらanimやらのManagerがぶら下がってるのになんでparticleのManagerはないんだろう?と思った。

...先週はそうやってPhaser3を触り、自作のゲームフレームワークの方は触っていなかった。

今週は自作ゲームフレームワークを触っていた。

インベントリシステムを作ろうと頑張っていた。そして考えあぐねてもいた。所持アイテムをインベントリビューで一覧表示するやつ。ソートしたりアイテムクリックで使用したり、アイテムをドラッグして場所を変えたりするやつ。最低限の機能は作り終えたけれども、悩んでいるのはアイテムの使用。アイテムを使うってどういうことなんだろうか。

あと、動的にゲームオブジェクトを追加する仕組み。サンドボックスゲームみたいにアイテムをフィールドに設置するやつ。今までは初期化時に全部のゲームオブジェクトを用意する処理を書いていた。その意味で静的だった。ボタンをぽちっと押したらキャラが上から降ってくるような(新たにゲームの世界にキャラが生成されるような)デモを次の更新であげたい。

綺麗な処理を書きたい(少なくとも俺にとって自然に思える処理)を書きたいので、なるべく相互参照みたいな実装をしたくなく、そのたびに考えてしまう。このせいで、ちょっと進みが鈍くなっている。でも、下位のオブジェクトからマネージャーへの参照があればいいのになと思う場面が増えてきている。オブザーバーパターンにすればいいのか。マネージャーは集約しているオブジェクトすべてを購読する...

 

自作ゲーム 進歩⑤

youtu.be

髪が伸びてきたが散髪に行きたくないことヤバウチだ。

↑の動画は前回からの進歩を示す動画だ。

動画内のドット絵素材は

0x72.itch.io

こちらを使用させていただいた。

ブラウザAPIMediaRecorderを使ってCanvasを録画したものを脳死youtubeにupしているため、せっかくのドット絵がつぶれてしまっている。

しかし、この動画を見ての通り当たり判定やらアニメーション効果やらが

ちゃんとついている。

 

ハンマーは振られると150度回転して、そのあと150度逆回転する。

金の騎士が振ったハンマーに当たったデーモンは弾みながらのけぞる。

デーモンに当たった金の騎士もまた弾みながらのけぞる。

デーモンはまた、ピョンピョン跳ねながら左へ移動する。

 

↑の4つはすべてアニメーションで設定している。

のけぞるアニメーションの再生は当たり判定がトリガーになる。

  • ゲームループ内で衝突判定を行い、衝突情報を各モデルに積む
  • 次に全モデルを巡回して積まれた衝突情報を消化する(衝突に応答する)。このとき、各モデルはあらかじめ定義しておいた衝突相手に対する反応(例えば、金の騎士は衝突相手がデーモンだった場合、「のけぞる」)をしようとする。ここで、さらにモデルの状態に依存して、その反応の可否を決める。(例えば、金の騎士がすでにのけぞり状態の場合には騎士はのけぞれないようにプログラムしている。騎士がのけぞるのはのけぞっていない状態の時だけにしている)そして反応が可能だった場合に初めてのけぞりアニメーション再生メソッドが呼ばれる。(デーモンの場合、このメソッドを呼び出すと同時に移動アニメーションとピョンピョンアニメーションを一時停止している)そして騎士の状態に「のけぞり中(無敵中)」を表す値をぶちこんでおく。次フレームでまた当たり処理が走ったとしても、その時騎士の状態は「のけぞり中」なのでのけぞりアニメーションは再生されない。
  • のけぞりアニメーションは終了後に実行されるコールバックを格納できるようになっているので、このコールバックに騎士の状態を「通常」を表す値をぶちこむ代入文だったり、デーモンにおいては一時停止していた各アニメーションをリジュームするメソッドを呼ぶ処理を書いておけば、のけぞり終了後にちゃんと元の状態に戻すことができる
見えてきたやること

当たり判定はおちおち直さないといけないと思う。騎士やデーモンをのけぞらせて分かったが、「当たった」という情報だけではなく「どちらの方向から当たったのか」とか

「どんな勢いで当たったのか」みたいな、追加情報が、あるとその分難しくはなるけど、より動的になると思う。今はとりあえず向いてる方向と逆向きにのけぞらせている。でも思ったけど、静的にすればするほどシンプルになってわかりやすいといえばわかりやすいし、これはどこに力を入れたいかによるものだと思う。

あと、キャラの向き。左向き、右向き。上向き、下向き。素朴だけど、難しそう。

これはもっとあとだけども、キャラのAIは苦労しそうだ。

あとはインベントリみたいなUI。

あとはゲーム遷移。

まあ最初から最後までとりあえず作るのが一番いいと思う。

↑の動画だって、タイトル画面と決着画面追加したり、音を入れたりして、

ミニミニ簡単なゲームとしてでもとりあえず最低限のゲームとしての体裁を整えたものを実装してみることこそが、全体感をつかむ方法だと思う。と、

yaba-outi.hatenablog.com

↑FlappyBirdをつくったときにも実感した。

狭い範囲の問題解決は局所解になりやすいと思う。

「あ~そんなこと考えてなかった~」になると書き直さないといけなくなる。

パフォーマンス改善なども最初っから手をつけてはいけないと思う。まだ俺は2dゲームに必要な要素みたいなのを把握しきれていないからだ。

真に必要なのは部分を100%にすることではなくて、全体を30%ぐらいのふんわり度で把握することだと思う。俺の内なる声がそう言っている。だけどもそれはとても面倒くさいことだ。作っていて楽しいとこばかり触ってしまう、ポイズン。

しかしまあ、幾度となく挫折してきた

「んほ~、javascriptで自作ゲームフレームワークっぽいの作りてぇ~~!」も、

今まで一番長く続いて、より進歩を見せているのが現在制作中のそれだ。

三歩進んで二歩下がる人生。進みたくなるものがあるだけ幸せなのか。

 

 

自作ゲーム 進歩④

youtu.be

曜日感覚を失ってしまったヤバウチだ。

↑の動画は親子関係機能の「お披露目」だ。

動的に親子関係を構築解除することができている。

多分バグがあるだろうけれども、

確実に言えるのは、「前よりかはマシになった」ということだと思う。

面倒くさくても頭の中で考えないで紙に書いて考えることは、

ついつい忘れがちな大事なことだと改めて思った。

あと、情報の洗い出し。

「俺今なにをどうやろうとしてんだっけ???」

の状態だと無駄に時間を食ってしまう。

面倒くさくてもできるだけひとつひとつ丁寧に考えを列挙していくことは

頭の整理になる。これも億劫になりがちな良い習慣だと思ふ。

 

 

 

自作ゲーム 進歩③

進歩はありません。

むしろ退化している。

あと先日の動画のプログラムは間違っていました。

見た目はそれっぽくできていましたが、ひょんなことでバグるヤベープログラム、でした。

親子関係の機能を組んでから、複雑になったね。

親という基準に対して子供は相対的な位置を保持する必要が出てきて、

親子関係を解消した時(removeChild)や

逆に作った時(addChild)の計算が難しい。

俺の脳みそが沸騰してダメになってきているのを感じます。

今俺が躓いているところは

多分ベクトルの計算なんだろうなと思って、

色々調べています。

そしてプログラムの書き直しをしていると、

前まで動いていたテストプログラムが動かなくなっちゃうんだよな。

変更に強いプログラムって難しい。

いや~、昨日はいい気分だったのに、今日はダメっすね。

 

 

自作ゲーム 進歩②

youtu.be

youtu.be

先日ハロワで失業認定を受けてきた自己都合退職野郎Aチーム、ヤバウチだ。

虚無ったりしながら自作ゲームフレームワークをシコシコ作っていたぞ。

今回作ったのはアニメーション機能と親子関係機能だ。

「アニメーション機能」とは俺なりの解釈で説明すると

始点と終点と期間と遅延とイージングを指定したら、

時間経過にそって始点から終点までの間の動きを補間してくれる機能のことだ。

ん?イージングとはなんだ!イージングとはd3.js(有名なライブラリ)の説明によるとこうだ。

イージングとは、アニメーションの見かけの動きを制御するために時間を歪める方法です。最も一般的には、スローイン、スローアウトに使用されます。時間をイージングすることで、アニメーションのトランジションがよりスムーズになり、より説得力のある動きを見せることができます。

github.com

 なお自作のフレームワークのイージング関数は、このd3-easeから拝借して使っている。これでもまだなんかイメージはわかないと思うが、↑の動画はイージング機能を使っている。正方形の動きが跳ねたり、緩急がついているのは全部イージング関数のおかげだ。

ソースコード内ではこんな風に使っている.


import * as d3_ease from 'd3-ease'

function Animation(obj, prop, from, to, duration, ease, delay) {
    // 省略
    this.easefunc = d3_ease[ease];
}

Animation.prototype.update = function(now) {
    this.stopwatch.update(now);
    /*
    * 省略
    **/


    this.obj[this.prop] = this.from + (this.to - this.from) * this.easefunc((this.stopwatch.elapsedTime - this.delay) / this.duration);
    // ↑こんな感じに使っている
};

経過時間をアニメーション期間で割った数値が正規化された時間tになる。

このtをイージング関数がいい感じにゆがめてくれる。

歪んだ時間と全変化幅を掛け算するとその時点での変化幅が取得できる。

これを開始値に足すことで、その時点での値が決まる。これを毎フレーム行うと、

始点値から終点値までの間を補間できる。→なめらかな動きがつく。

といった具合だ。

2つめの親子関係機能は↑の二つ目の動画を見た方が早い気がする。

動画内では4つの正方形が相対的な位置を保ったまま一緒に動いている。

しかし、内部的には1つの正方形にしかアニメーションを設定していない。

だから本来は他の3つの正方形は止まったままになる。

でも動画内では4つとも動いている。その理由を説明するのが親子関係の有無だ。

正方形A, B, C, Dとあって、

[親] A : [子] B,

[親] B : [子] C,

[親] C : [子] D,

という親子関係をプログラムの中で設定している。

子は親のプロパティを基準とするように実装している。

なのでAをアニメーションさせてその内部の状態を変更すると

Aを基準とする子Bも親からの相対的な値は変化していないが、

基準が変わっているのでBもAに追随する。

そしてそれがBからCにそしてCからDに伝わる。

そんな風につくってある。

これで例えば「勇者」と「剣」に親子関係を設定したり

「隊長」と「兵士」の間に親子関係を設定したりできるんじゃないかと思う。

けっこう大変だった。だいぶコードが荒れた。

一度整理してセッターやゲッターを設定し直したいと思う。

developer.mozilla.org

↑ 存在は知っていたけど黙殺していたsetter構文getter構文。便利だと思う。

あとclass構文も使いたい。古い関数コンストラクタをつかって書いているが,class構文に書き換えたい。

 

がばがばテストでバグは残ってるのは間違いないけれどもインフラ的なプログラミングはまあまあ終わったのでまたこのフレームワークを使って簡単なゲームを作りながら

追加機能を考えていきたいと思いやす.

 

しかし、作りながら思うことはやっぱり自作なんてするもんじゃないなあと思う。

ある程度気が済んだらphaser3とか覚えたい。ゲームを公開したい、そう思う。