日別アーカイブ: 2023年3月5日

どうなる確定申告。

①副業と、②不動産収入、そして③ふるさと納税。

会社での年末調整は終わっているものの、これら3つの新要素が今年度は発生しているので、確定申告に初挑戦。

ただ、先週末に謎の39.0前後の高熱に3日間やられてしまい、予定していたタスクがさばけておらず、結構焦っている。

来週日曜日には、シビックテックの発表会もあって、プロトタイプ作成しているが、こちらもビハインドしているし…。

さて、どうしたものか。なんだかおもしろくなってきた。とりあえず、寝よう。

JSでゲーム開発の勉強メモ

index.html

画面を表示するためのhtmlファイル。body部分で、JSコードを読み込む。

main.js

JSのメインとなるコード。ゲームの主軸となる流れを書いていく。書く中で、各種JSファイルを適宜読み込んでいく。

game.js

ゲームエンジンのメインとなるコード。ゲームエンジンとは、ゲーム作りに使う機能をあらかじめ作ってまとめたもの。

例えば、画像や文字を表示する機能などを作っておく。そすうると、同じ機能を都度作成せずに、必要な時に呼び出せばOKなので、効率よく、かつ開発者目線でも分かりやすく開発することができる。

UnityやUnreal Engine、melon.js、phina.jsなどが有名。

canvas

HTML5の機能。絵を描画する範囲を示す。今回は、game.jsのコンストラクタでcanvasをcreateElementしてbodyに追加する形で使っていく。

メインループ(game.js内)

ゲームプログラミングでは、①変数、②条件分岐、③繰り返しがよく使われる、というか常に使われている。描画は繰り返し実行される。いわば、アニメでいうワンシーンごとを描画しているイメージ。特に、繰り返しは常に行われており、これをメインループとして実装する。

game.js内に、メインループおよび、メインループを呼び出す関数を書く。

メインループでは、canvasのコンテキストを呼び出して描画するという内容を書いておく。実際には、game.jp内に描画するモノ=オブジェクトを格納する配列を用意しておいて、スプライドのupdate()を呼び出す際の引数とし渡すことで、意図したオブジェクトを繰り返し描画する。

なお、オブジェクト格納する配列に、オブジェクトを追加していく関数はgame.jpにメインループとは別関数として書いておく。

スプライト

ゲームに表示させるキャラや背景などの画像をスプライトと言う。

ゲームエンジンの一つとして記載する。コードは別ファイルに保存する(例えば、sprite.js)。

sprite.jsの中身は、画像ファイルへのパスを受け取って、Imageクラスのインスタンスを作って、x座標y座標を初期化するコンストラクタと、画像を表示するためのメソッドであるrender()、およびrender()を呼び出して実際に画像を描画するためのメソッドupdate()とする。

個人的には、描画するコードを記載しているrender()と、そのrender()を呼び出すupdate()を別々に記載している構成が参考になった。一見、render()とupdate()は一緒にしておいて良さそうだが、「機能」と「その機能を実行する機能」を別々に記載しておけば、インスタンスを作って操作する際に細かな作り込みができそうなので良いのだろう、と今は思っている(要するに、現時点では、関数を分ける意味がなんとなく感覚でわかっているというレベル)

キー入力で操作できるようにする

game.jsにkeybind関数やeventListener()を使って、使うキー(今回は上下左右の矢印キー)の登録と、キーが押下された際の挙動を書く。

シーンを描画できるようにする

シーン専用のクラスを作成する。シーン(オブジェクト)を詰め込む配列と、その配列にシーンオブジェクトを追加するメソッドを書く。

game.jsでシーンを入れておくための専用の配列および、現在のシーンを格納する変数を用意する。また、シーンを追加するためのadd関数も用意する。

main.jsでシーンオブジェクトを作成する部分と、指定したシーンにスプライトを格納する部分、そしてそのシーンをgameに追加する箇所を記載する。

シーンクラスを作成するメリットは、画像や音楽や別シーンへの切り替えといった中身をシーンごとに記載して整理することができること。RPGはシーンの集まり、シーンの入れ替わりと考えると、確かにこの構成、すなわちシーンごとに機能を記載するプログラム構成は正しいと言える気がする。

タイルとタイルマップ

タイルマップとは、タイルを組み合わせることで作られるマップのこと。タイルとは、マップを構成する最小単位=部品のこと。

タイルマップ用にTilemapクラスを作成。基本構成はスプライト用のクラスと同じ。

コンストラクタで、Imageのインスタンスを作成して、タイル用のファイル指定や、xy座標、タイルの最小単位サイズを指定する。今回は32ビット。あと、二次元配列でマップを作れるようにするための配列も用意。

このTilemapクラスでも、描画する機能のrender()関数と、そのrender()を呼び出すためのupdate()関数を記載。update()では常に呼び出されるオーバライド用の関数も作成。

Tilemapクラスは、main.jsで呼び出して使う。マップ用の二次元配列は、main.jsに直で記載指定も良いが、map.jsとして別で記載しておけば、頭の整理がしやすい=分かりやすい構成になる。

キャラクターはタイルマップ上に表示するが、タイルの種類によって通過できる・できないを判定したり、例えばゴールや扉のような特定の場所に触れたら条件付きで動作を変更するなどの処理を施す場合は、単にスプライトとして表示するのではなくて、タイルとしてキャラも表示する方が処理がしやすい(のこと)。

そのため、タイルとしてキャラを表示するために、Tileクラスを作成。この際に、Spriteクラスを継承する。

タイルはタイルマップ上に存在する(ようにする)ため、タイルマップは同時に移動したり、タイルマップの何番目のタイルとして表示するかを取得したりする。

キャラクターではなくタイルマップを移動する

タイルマップのサイズが大きくなったら、キャラを移動させるよりも、代わりにタイルマップを移動させることで、あたかもキャラを操作しているように見せた方が便利だ。すなわち、常にキャラを中央に位置しておいて、タイルマップ(背景)を動かすようにする。

キャラを基準に、その背景であるタイルマップや、タイルマップ上に表示する他の部品(村人キャラなど)を設置して、なおかつキャラではなくてタイルマップを移動させる。キャラ自身もクラスやその継承でタイルマップやタイルと同じように表示するので、移動するかどうかの同期を取る・取らないの機能を追加した方が扱いやすい。

進もうとする先が、移動できるか・できないかを判定するための機能も実装する。some()というJSの関数を活用すると、簡潔に実装できる。

その他

各クラスやインスタンスで使用する「this」というものが、最初はなかなか分かりにくかったけれど、「そのインスタンス」を意味するということと、thisのおかげで他のインスタンスや条件などど比較したり参照したりできるということが、RGPを作成することが理解できた気がする。

thisって慣れないと、たまがごちゃごちゃする。というか、クラスとインスタンスという概念を、机上だけでなくて、実際にスクリプトを組むという手を動かしたり、デバッグなどの経験を通すことで「ちゃんと理解する」といいうことが大事だな、と改めて痛感。何でもそうだけど。

参考サイト

JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方
https://original-game.com/make-an-rpg-with-javascript/

FF

僕のFFは9で終わっているんだけど、たまたまYouTubeで10を見たら、8よりも映画っぽくなってて驚いた。あの頃のトレンドって、こういうのだったのか?

最新作の13とかどうなってるんだろう。召喚獣のシーンはYouTubeで見て、なんかもうゲームというジャンルじゃないなって思った記憶はある。ストーリー展開とか、演出とか、10よりもすごいのだろうな。