2016年11月前半ゲーム開発これ以上ブログ放置するとサボり癖が出そうなので、箇条書きで進捗メモ。GUIまわりをドット絵で暫定的に作成。アイテムアイコンなんかもいくつか書いてみる。楽しいメニューとGUI・キャラチップなどいくつか表示できそうなものが出来たのでプログラム再開オープニングメニューなんかをスプライトシート化したり、プレイヤーの設定ファイルの仕組みを整えたり土台部分でC++で上手く書けない箇所があったので結構リファクタリング(型とかテンプレートの問題です。API経由で書き直しゲーム起動〜メニュー部分のコードをもりもり書いているところ普通はゲーム部分のプロトタイプから作って面白さを確認しながらスクラップビルドするのがゲーム開発の王道だと思います。僕の場合はゲームメニューやらオプションやらを先に実装しています。理由はC++に慣れていないので、コードを書けば書くほど「これはC++で上手く書けるんだろうか」という不安が付いてまわるためです。簡単な部分から書いてC++の練習をしつつ、プログラムの基礎部分にヤバいものが見つかったら大胆にリファクタリングしていく。いう事を繰り返しています。おかげで全然開発が前に進んでいません。土台部分もゲームを完成させるに足る程度にはしっかりした気がしてきました。技術的な不安も多くが解消されつつあるので、ここからは少しずつペースが上がる予定です。開発期間がすでにC++の基礎学習部分をのぞいて1ヶ月半になりそうなのに、ゲーム部分がまったく開発できていないのに自分自身驚愕しているところです。初心者がC++でフルスクラッチに近い状態でシミュレーションゲームのようなものを作るのはとっても大変なようです。モチベーションが維持できているかというと、趣味なのでできているようないないような。最近は少しC++を書くのがダルいなあと感じ始めています。絵書いたりLuaでスプライト動かしたりするのはとっても楽しいんですけどね。年が開ける頃にはキャラクターがフィールドを歩けているといいなあ。2016年10月後半2ゲーム開発というわけでタイトル画面を仮組みしてみた。ゲームタイトルはVILLAGISM(ビレッジズム)という名称に仮決め。ロゴデザインも仮で、ある程度完成形の8ビット風のイメージが出来るようなところまで。背景画像は壁紙サイトさんから一時的にお借りしたもので、イメージに近いものを仮置き。このまま使えたらなんて思ったんだけど、件の壁紙サイトさんでは権利関係に一切言及が無かったので、残念ながらいつか置き換わる予定。これくらい描けたらなあ。Creativeなんとかを年払いしていたのでこれを利用。Lightroomとあわせて月額980円だかのサービスなので、Illustratorは使えない。使えても使えこなせないからいいんだけども。それを言えばPhotoshopも全然使えない。無い無い言い出すとゲームのインターフェイスデザインも勿論初体験なので、キリがない。グラフィックは未知の領域だらけだし、イラストとなるとまったく描いたことが無い。8ビット風を今回のプロジェクトに採用しました。誤魔化そうという魂胆です。ドット絵ならばプロと差が出にくい、プレイヤーが勝手に良い方へ補正して見てくれるんじゃないかという考えです。甘っちょろい考えですが、一人でちまちま作りたいのだからしょうがない。この目論見がある程度達成出来なければここでこのプロジェクトもお蔵入り。と10日くらいずっとドット絵描いていました。www.aseprite.orgドット絵エディターを軽く調べて、OSXで動作するもので評判が良いものとしてAsepriteが挙がっていたのでこれを採用する。書籍代以外で初の出費です。他のエディターを使った事が無いので比較できないのですが、すごく使いやすい。これくらいは描けるようになってきました。イラストは苦手分野、というかまったく未知の分野だったので、ちょっと援護射撃が必要だろうということでAsepriteを買って正解でした。それと、安いペンタブも援護射撃として購入。Computersこの商品を含むブログを見るまだまだ全然真っ直ぐ線も引けないけども、横幅20ドットくらいなので書いたり消したり時間を描けたらある程度見えのする形が浮かび上がってきます。キャラクターについては、僕はレゴが好きなのであれに近いプロポーションや色数をまずイメージしてました。それから過去のゲームのドット絵を参考に。任天堂のドット絵はどれも魅力的で大いに参考にしています。ポケモン、ゼルダの伝説、Motherあたりに強く影響を受けています。ポケモンは緑を、ゼルダは64まで、Motherは1−3まで全部やったことないですけど...。Asepriteに慣れつつ、ドット絵になれつつ、絵を描くこと自体になれつつ、んでもってアニメーションにも慣れる。いう素体をずーっと描いていました。絵を描くのは案外楽しかったです。いくつかのキャラと地面とを描いて1枚にしてみる。自画自賛とはいかないものの、なんとかゲームとして成立しそうな雰囲気が出ていてホッとする。水色の部分はインターフェイスが置かれる予定の場所。いくつかの静的なオブジェクトと、キャラ(動的なオブジェクト)、それからインターフェイスのデザインが終わったらまたプログラムのほうに戻る予定です。2016年10月後半1ゲーム開発2週間弱空きましたが、引き続きゲームを制作中です。前回からプログラム的に進んだところは、Luaをゲームシステムに組み込んでゲーム内に登場するオブジェクトをLuaで操作できるようにしました。どこまでLuaで、どこまでC++でという領分の切り分けをずっと悩んでいたのですが、オブジェクトの作成と削除以外はLua側で、というあたりを落とし所にしようかな、と思っています。オブジェクトやリソースをLuaに操作させるとオブジェクトのpoolingだったりリソースの再利用をLuaでじゃあするのかという話になってくるので、ここを線引きとしました。いえLuaからC++のメソッドを叩いて子オブジェクト作成リクエストをしたり、なんてのはできるようにする予定。それからシーンやレイヤーの管理方法を全体的にスッキリさせました。静的型付け言語はこういったリファクタリングを気軽に出来るのは大きなメリットだと思う。動的型付け言語だとテストが無いとちょっとやりたくない。とここまできて、次はスプラッシュやタイトルシーンの仮組み。このあたりからゲームに組み込む絵があったほうが作業が進めやすいので、ビジュアル関連の作業に手を出す事にしました。プログラミングも疲れてきたのでちょうど良い頃合いかなって。C++にはだいぶ慣れてきたけど、Luaの組み込みがちょっとダルかった。いうわけで、ここからいきなりグラフィックの話になるので、日記を分ける事にします。現在の個人プロジェクトでLua組み込んでみよかーと思ったので備忘と誰かのために。OSXLuabind公式のソースでOSXではソースからコンパイルできなかった。Makefileをちょろっと見たけど拡張子の指定とかがOSX用で無かったり、ネットで見つかるOSXの指定オプションが無視されたりとよくわからない状態だったのでbrewからインストールする。luabind依存のboostも合わせてインストールされる。"lualib.h"}これは他所サイトでもよく見かけるので解説はそれらを参考にしてください。-lluabindとライブラリ名を指定してやる。lib○○.dylibの○○部分にハイフンを付ける。dylibじゃなくファイル名がsoでも多分おなじ。brewからインストールした場合、/usr/local/libに上記のようにlua5.1とluabindの動的ライブラリが無い場合があるかもしれない。その場合は/usr/local/Cellar以下や/usr/local/opt以下にないか確認して/usr/local/lib以下にリンクを貼ると良い。貼らなくても自動で見つけてくれる気がする。見る入門用に上記の書籍に目を通した。LuabindではなくLuaAPIを生で触る所から解説されてある。わかりやすさも心がけて書かれているのでとても読みやすい。ネットに日本語の情報が少ないので最初は書籍に頼ったほうがいいかもしれない。(私は図書館で借りてきたこの1冊だけ)で私はイロイロだるかったのでluabindというちょっと高級なライブラリから連携を取ることにする。c++側のクラス登録も楽勝。この辺は他サイトに譲る。luaでc++側のクラスを扱うにはluabindで登録していくだけで基本OKなんだけども1つ注意点として、Luaの知らない戻り値型をluaで受け取らせるとエラーで落ちてしまう。自作の巨大なクラスをLuaで自由自在に扱わせようとすると全ての型をluabindで登録しなくちゃいけない。上記書籍では話を簡単にするために、登場するサンプルコードが極力lua側で物事を解決しようとしているので、あまり上記のような問題は検討されていない。一般的には、C++とLuaでインスタンスが行ったり来たりするのが現場の普通だと思われるので、いっちょテストコードを書いた。"make_instance");call_functionの引数は第一にVMのハンドラ、第二がlua側の呼び出したい関数名、第三以降にlua側の関数が受け取る引数を指定する構文になっているのですが、ここにポインタが普通に渡せます。参照で渡さないとコピーされるので注意。取り扱えるのはlualib.hで定義されている基本的な型と上記コードのluabind::class_のように教えてあげた型だけかと思われる。2行目は戻り値として同じくTestClass型のポインタを受け取っている。1行目があれば、c++で生成したインスタンスをlua側でゴニョゴニョさせれる。lua側のグローバル変数だかクロージャに突っ込んでおけば、C++側のentityとluaのVMを対で連携させていろいろ処理ができる。2行目は、luaで作ったインスタンスをC++で受け取っているので、処理の要なんかをC++で受け持ちたい場合もこれで対応可能。test_instance:hello();test_instance.my_count;Lua側では:コロンと.演算子でインスタンスとメンバをつなぐ。Luaで作ったインスタンスと同じ構文でC++から持ち込んだインスタンスが扱えるようです。<luabind/luabind.hpp>この一文がめちゃ重い。中は魔宮のようになっていてコンパイルするとテンプレートがばんばん展開されるらしい。Luabindとトレードオフだとしても許容できないくらい重い。これ1つでコンパイルが10秒以上は伸びる。cpplover.blogspot.jpここを参考にpchにすることで、1/10くらいの速度になりました。雑記10日ほど日記が開いてしまいましたが、ゲームは鋭意開発中です。骨組み部分なので見た目には何も進んでいません。開発を初めて約3週間ですがやってきた事はというと...。全ての要素(entity)の元になるベースクラス親子entityの直接会話(実際には親から子へのみ)スプライト管理、アニメーション管理機能(Luaに移行予定)状態によってクラスや関数ポインタを切り換えて挙動が変わるシステムアプリケーショングラフ(アプリケーション→シーン→レイヤー→オブジェクト)ゲーム遷移オブジェクト間のメッセージングシステム(遅延対応)キーイベント設定によるキーバインディング対応シーン毎のキーイベント処理システム(コールバック対応)window/フルスクリーンモード対応(OSXの仕様でちょい微妙)iniファイルみたいな、外部ファイルによるConfig機能(TOMLで)luaとluabind動作テスト設定シーン用にTgui動作テストと大仰に書けばいろいろやっています。C++自体の学習も並行していたので、コードも行きつ戻りつしています。プロトタイプではクラス設計を適当にすればよかったのですが、本組みとなるとそうもいきません。土台を固めようとちゃんと書いていると、アップキャスト、ダウンキャスト、vtableとvirtualメソッド、テンプレートなどの仕組みをキッチリ理解させられるハメになりました。動的型付けのスクリプトの世界から来た僕からすると、この強烈な静的型付けの世界では、便利な事はだいたい速度とはトレードオフな世界で、どうクラス設計をすればいいか本当に悩みました。できるだけC++っぽくなるように設計しています。していくと静的型付けの構文チェックやデバッグ機能が最強に機能して、そういう部分では開発が楽になってきました。いったものを乗り越えて、3週間ほどでだいぶC++コンパイラとの会話のキャッチボールにも慣れてきて、コードを通すという部分で苦労する事は無くなってきました。ここからは...あと1〜2週間引き続き骨組み部分の開発だと思います。Luaの本格的な組み込みTguiの本格的な組み込みスプラッシュ・タイトル・設定シーンの仮組みコマンドラインツールの組み込み(ゲーム走らせたままLuaのリロードとかシーンジャンプとかに使う予定)ゲーム部分の取り掛かりといってもデバッグ機能の実装からあたりが出来たらなあと思っています。ここまで来たら、絵とプログラミングが半々くらいになって「ゲーム作ってるぞ!」といった風情が画面から出てくるかなあ。C++昨日くらいからゲームで使うイベントハンドラを作っています。そこで各イベントに割り当てられたコールバック関数を管理するデータ構造を考えていています。hashの添字でアクションをバインドして、そこからコールバックを呼ぶみたいなやつ。これを管理するわかりやすいデータ構造とコールバックの関係は、アクションハッシュ[アクション名1]-*コールバック関数ポインタアクションハッシュ[アクション名2]-*コールバック関数ポインタアクションハッシュ[アクション名3]-*コールバック関数ポインタアクションハッシュ[アクション名4]-*コールバック関数ポインタみたいなのが分かりやすい。アクションハッシュ[ジャンプボタン]-*ジャンプを実現させる関数ポインタアクションハッシュ[パンチボタン]-*パンチを実現させる関数ポインタアクションハッシュ[キックボタン]-*キックを実現させる関数ポインタアクションハッシュ[必殺技入力]-*必殺技を実現させる関数ポインタと書くともうちょっとわかりやすいでしょうか。このままだと1アクションに1機能しか割り当てができない。シーンの移動などで、ジャンプが出来ない状態になった時、コールバックを削除する際に関数ポインタの型みたいなのを総なめにしないといけない。┣コールバック情報が入った構造体1┣コールバック情報が入った構造体2┗コールバック情報が入った構造体3みたいなデータ構造を検討してみた。アクションへはo(1)で到達できるし、コールバックのリストは基本1つか多くても片手で数えられるはずなので、そこを線形処理しても大してコストはかからないだろうというわけ。最終情報が構造体なのは、IDで管理したりコールバック属性(他のリスナーを排他にするかとか、スリープとか)を管理するため。それをスマポでくるんだunordered_map。上記までがデータ構造の準備。アクション"test"に登録されているデータの呼び出し例。world:3usingほげほげの部分がまず何をしているか意味がわかりづらい。これはデータ構造が3段階で、そのままデータ構造を表現するとあほみたいな表記になるので、3段階それぞれにusingで別名を付けています。std::shared_ptr<std::deque<std::shared_ptr<TestClass>>>>>;ということになる。3層構造ってだけでもう取り返しが付かないシンタックス。呼び出し部分(*(*map.get())["test"].get())[0]->hello();これもごちゃごちゃしてわからない。これ何してるかというとstdのスマートポインタには添字アクセスのオペランドを処理する機能が付いていない。そのため、生ポインタを取得する.get()を2度(ハッシュの添字解決、dequeの添字解決)行っている。->みたいにアクセスできるもんだとてっきり思ってたが、そうではないらしい。map->["test"]->[0]->hello();みたいなのをイメージしてくれたら良い。できないことはないC++なので、上記の表記もきっと実現できるんだろうけど、ここまで書いていったい僕は何をやっているんだろうという気持ちになってきて、やめました。目的のデータ構造は実現できたが果たしてコレが必要なのだろうか。上記ページなんかではvectorをmapやlistに代替えするにはそれ相応のデータ規模でないとむしろ遅くなるという言及があります。100や200のキーバインドにこんなデータ構造を使うのはバカげている気がしてきます。data(小さなデータを扱う時、std::listよりstd::vectorやstd::dequeのほうが常に速い)ふうむ。データへのアクセスに関しては線形探索は絶対避けるべき。できるだけo(1)を目指すのが正義だと思っています。今回のようなデータ構造を実現しようとしてきたわけです。この発想の根源というのは、秒間数万だとか数百万リクエストに対して数万数十万のユーザーを識別しつつスケーラビリティの乏しいDBを保護するためのものなわけです。これがスタンドアロンな実行環境になると、1度頭を切り替えたほうが良いと思えてきました。言えばループで総当りしたほうが良い場合のほうが多いのではないか?アクションへのo(1)アクセスのために添字が使いたいからといって、バインディングマップを馬鹿正直にunordered_mapで管理する必要があるのかもちょっとした疑問が出て来ます。vectorで良いということになります。プレイヤーから入力される情報は限られています。キーボードのキーの数、マウスのカーソル位置とボタンが3つくらい、あとはゲームパッド。これらの中からゲームが対応すべき入力の種類なんて、いいとこ10や20なんじゃないか。mapじゃなくてゲームに予想されるアクションを変数で確保しておくこともやぶさかじゃないんじゃないかなあという考えにも行き着く。1つのアクションに対するコールバックを複数管理する必要性もここまでくると良くわからなくなってきた。ジャンプボタンを押すと2人のキャラが同時にジャンプするにしたって...。1つのコールバック関数で管理してコールバック関数側で2人分を動かしたほうがいいんじゃないか。考えているため全然ゲーム制作が進みません。Makefileで階層(サブディレクトリ)を走破しながら依存を解決してコンパイルするC++C++でクラス毎にファイルを分け、ファイル群をディレクトリ構造で管理するのは一般的な方法かと思います。階層化したディレクトリの依存関係を解決しながら1つの実行ファイルを生成するのにはコツがいるようです。一般的には、サブディレクトリ毎にMakefileを設置して多段コンパイルするようですが、1つの目的で複数のファイルがあるとメンテナンス性も落ちるしトラブルを孕みやすいので、1つのMakefileで解決する方法がないか模索しました。いうわけで以下のMakefileで目的が達成されました。インクルードパスの指定。$(DEPENDS)ディレクトリ構成は以下を想定しています。example.cppベースは以下を参考にさせてもらいました。CXXFLAGSの解説は以下を参考にしてください。urin.github.ioまた問題が出たら修正版を書こうと思います。最近はCMakeやSConsというモダンなタスクランナーが存在するのでMakeに頼る必要はもはやないかと思いますが、Makeでどうしても、という人はご参考にどうぞ。(3)スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。