パスワードを忘れた? アカウント作成
17462624 journal
日記

yumeの日記: またゲーム作ったよ〜

日記 by yume

itch.ioで
▹ph◉tonを公開したよ。
2Dマウスはえたたきゲーム。

使ったことのないゲームエンジンとかに挑戦してみようという主旨の「勉強会ジャム」が10月に開催されてたので参加した。Godot 4.1.2を使用。

使ってみた感じ、(2Dでは)そんなにUnityと変わらないな、という印象だった。Unityは覚えなきゃいけない語彙が多いけど、Godotはそこが少なめな感じがする。Godot mono(C#で書けるバージョン)だと、webglに未対応だったので、今回はブラウザゲームじゃない。

ゲームの内容は、昔『マリオペイント』にあったおまけのハエたたきゲームを下敷きに、もっとごちゃごちゃたくさんオブジェクトが出てくるのはどうだろう、と考えたのでそのようにした。Godotでどのくらいオブジェクト作ると重くなるかためせるし、物理も使うし、いい感じ。

複数種類の武器が登場して、武器ごとに操作の反映のされかたが違う。クリックした瞬間に発動するもの、離したときに発動するもの、押し続ける間発動するもの、押し続けたらチャージ、離したら放つものなどなど。
「押しっぱなしにすると強い武器は連打する武器と相性が悪い」みたいな相性がある。武器と敵との相性とか、武器同士の悪い相性を補う方針の強化とか、いろいろ工夫できる点は多い、と思う。

ゲーム自体は「たくさん倒すとよりたくさん敵が出る」という仕組みで、うまくプレイすればするほどスコアがどんどん上昇する。480秒生存でゲームクリア。

ソースコードもあるよ

16718402 journal
日記

yumeの日記: またブラウザゲーム作ったよ〜

日記 by yume

itch.ioで
『Bullet Ballet』を公開したよ。
Mini Jam 138: Rewind 参加作品
2Dトップダウンシューター。ただし弾を撃つにはそのたびに銃を拾わなきゃならない。

制限は「Limited Use」Mini Jamは最近制限の解釈の自由度があがってて、これも自由に解釈していいらしい。シンプルに「使用に制限がかかる」と解釈しよう。

トップダウン2Dシューターってitchのインディーゲームではかなり大きいジャンルで(多分作りやすいから多いんだと思う)、それで自分でも何か思いついたら作ろうと思ってた。
このジャンルのゲームは本質的には「立ち位置を決めるゲーム」だなぁと思ったので、立ち位置を決める要素がユニークだったら変わった遊びになるだろうと思った。そこでここでは、一番基本となる「攻撃する」という動作(スキル)の発動条件を「アイテムを拾うこと」に制限することで、立ち位置を決める要素に戦略性を追加した。

普通のトップダウン2Dシューターの場合
-どの敵を優先して倒すか
-どの位置が安全か
-アイテムがどこにあるか(いつ拾うか)
あたりが重要だけど、このゲームの場合はアイテムを拾わないと攻撃できないので、将来的な安全を買うために今いる敵を倒す必要があるが、敵を倒すためには攻撃アイテムを「効率よく使える位置・タイミングで」拾うことも考えなきゃいけない。
わかりやすい例は「ソード」で、これは範囲攻撃なので非常に効率よく敵を倒せるが、効果を最大化するには敵を巻き込める範囲とタイミングを考えなきゃいけない。

敵を倒すとレベルアップして、新たなアイテムを解禁したり、アイテムを強化したりできる。
アイテムが生成される総量は固定で、アイテムの解禁は「生成されるアイテムの比率を変えること」を意味する。つまりどのタイミングでどのアイテムを解禁するか、そしてそれらをいつ使うかも戦略になる。アイテムを強化するまで放置して数を貯めるのは有効な戦略だけど、そうすると立ち位置を考えるのはもっと難しくなる。
「ポーションを後々のために貯めておきたいけど、その辺に今使いたいソードもちょうどよくおいてあるなぁ……」みたいなジレンマが発生するといいな。

実装したいアイテムの種類や敵の種類がまだまだあって、例えば「バフオーブ」は拾うと数秒間攻撃力が二倍になる。非常に強力だけど拾う順番はとても重要だ。「ブーメラン」は行きと帰りに当たり判定があって、帰りの方が威力が高い。これらも立ち位置を考える要素になる。そのうち実装しよう。

ちなみにゲームは全15ステージ(時間経過でシームレスに移行)を生き延びれば勝ち。クリア自体は10分もかからない。

16675653 journal
日記

yumeの日記: またブラウザゲーム作ったよ〜 1

日記 by yume

itch.ioで
『Hands』を公開したよ。
Mini Jam 135: Deception 参加作品
手が動くインタラクティブ・コラージュ。
収録曲は全部で4曲。

itchで少しコメントがついたんだけど、「ここの攻略法はこうだ!」「いや、こうだ! そいつは嘘をついてる!」みたいな流れがあって。それぞれの心の中にある『Hands:完全版』みたいなのがあるのかな。だとしたら、ぜひ遊んでみたいと思う。

16563486 journal
日記

yumeの日記: またブラウザゲーム作ったよ〜

日記 by yume

itch.ioで
『10 Seconds FARM!』を公開したよ。
Mini Jam 130: Luner 参加作品
1日が10秒で終わる忙しい農業ゲーム。

今回の制限は「10 Seconds」シンプルな制限だけど、10秒でできることって案外少ない。
パッと思いつくのは、メイドインワリオみたいなミニゲーム集(10秒以内にピンチを切り抜けろ、の連続とか)。これは誰かがやりそう。
もうちょっとひねって「10秒でやれ」と言われて無理そうなことを考えた。農業を10秒でやるのは無理そうなので、これでいくことにした。

ゲームは1日10秒を40回ループすることで実行される。
作物の成長判定は1日の終わりに行われる。このとき、与えた水や肥料は(種を植えてない地面も含めて)全て取り除かれるので
・(植えてないなら)種を植える
・水を与える(できれば)
・肥料を与える(できれば)
ということを10秒以内に、なるべく多くやらなければならない。
「水を撒く範囲が広すぎて、肥料を撒けなかった!」みたいなことになると結果的に損なので、1日のうちに今の自分ができる範囲を考えなければならない。
たまに雨が降ったりするので、計画を急遽変更して肥料と種範囲拡大を考えたり柔軟に動く必要がある。

また、プレイヤーはスコアに応じてレベルアップし、3枚のカードからスキルや追加の作物を選ぶ。俺この仕組み好きだな。
追加の作物は、どれもスタート時から植えられるにんじんより効率がよい。高級な作物ほど効率はよくなる。ただし高級な作物は成長にたくさんの栄養が必要なので、これを捌けるほどの能力がない低レベルのうちに植えてしまうと、低レベルの時間が延びてしまい、結果損をする。
スキルは大抵強力だけど、育てる作物の傾向に合わせて能力を選ぶ必要がある。例えば小麦は水を必要としないけど、安いので大量に撒く必要がある。ということは種まき範囲拡大+移動速度増加+収穫範囲拡大の能力と相性がいい。
作物カードは一度選べば抽選にはあがらなくなる。これにより欲しいカードが出る確率をあげられるので、時にはいらない作物カードを選ぶのも手。
作物の詳しい計算式やステータスはゲームページに。

16558203 journal
日記

yumeの日記: まだChatGPTで遊んでいる。

日記 by yume

PlayWithGPT(自己進化するリポジトリ……を目指す遊び)を相変わらずやっている(ちなみにゲームも作っているが、規模が大きくて全くもうという具合である)。

ChatGPTにPatchを当てさせることで、自然言語によりリポジトリを強化していくリポジトリ「pmon」

ユーザーが命令を指定すると、タスクリストを吐き出し、そのタスクを順番に解決し、さらにタスクを生成し……を繰り返し、最終的には命令を解決する「BabyAGI」

おもしろい。
pmonはまだ触れてないけど「pmonのリポジトリをpmon自身に強化させる」というアプローチはPlayWithGPTみたいだし、ずっと洗練されている。
BabyAGIは試してみて、色々考えさせられた。
・Pineconeにvector化したテキストを送り、後から必要になったらそれを検索してmetadataからtaskリストを管理している
・BabyAGI自身は、自分自身の機能を強化するすべが現時点でないので、どこまで行ってもタスクに対してなんやかんや言うだけ、みたいに収束してしまう。
・BabyAGIとpmonを合体しちゃえばいいのに。

つまり、命令に対して:
・現時点で解決可能なタスクと、そうでないタスクを分ける
(解決可能かどうかは、自身の能力リストみたいなのを参照することで判別する)
・現時点の能力で解決可能なタスクは全て解決する
・できないタスクに対して、必要な追加能力をリストする
・追加能力リストを上から順に実装していく(pythonで)
・解決可能になったタスクは順次解決する
・最終的には命令を解決し、しかも自分は進化している

というようなアプローチはどうだろ。経済的な問題はあるが(ロボットアームを購入したりはできないからね)、そこそこうまくいきそうな気がする。
PlayWithGPTでやってみたいところだけど、まだまだ機能が貧弱すぎてそこまで行ってない。でもpythonでコード書くのは楽しい。

16539070 journal
日記

yumeの日記: ChatGPTで自己進化するリポジトリ

日記 by yume

を書いた。

Pythonは全く触ったこともなく、事前知識もほぼゼロ(機械学習に使えるとかなんとか?)だが、webのChatGPTに聞きながらコードをコピペして、Github Copilotで補完してたら意外と動くものができた。

「なんなのこれ」というと:
ChatGPTはテキストで通信できるらしい。となると、特定の形式のテキストを「コマンド」として受け取ることでPythonのモジュールを.pyファイルとして生成したり、それを上書きしたりすることを繰り返すことができるのでは? そうしたら自己進化するリポジトリが作れるんじゃね?というシロモノ。

現状で、とりあえず「~~という内容のコードを書いて。ファイル名はhoge.pyで」と言えば、注文通りの(まぁそれなりの品質の)モジュールをmodulesディレクトリ下にほんとに生成してくれる。なんのことはない。文字列を検索して一致してたらsplitしてファイル名指定して保存するだけのことである。

で、「read: hoge.py」と発言すればhoge.pyのコードの内容をChatGPTに伝えることができるので、その後「このコードのこれこれこういうところを直して」と言えば改善してくれる。「read: fuga.py」と加えて「fuga.pyのこの機能に連携するように直して」という注文でも(多分)通る。

この時点でもうすげー楽しいんだけど、もっと改良したい。

まず、目下の課題はトークン数の消費が結構でかくて、わりとすぐに上限に達するところ。gpt-3.5-turboは最大トークン数が4kで、大体2つのソースコードを議題にあげて少し議論して、修正案を提示された後にもう一度修正を要求する、くらいのとこで上限で会話が続けられなくなる。

うまいこと文脈を消していけばもっと会話を続けられるだろうけど、どこを削るのかという問題は残る。定期的に「要約」コマンドを要求して、要約されたテキスト以外の文脈をさっぱり消すという方法はわりとありそう。

現状では、対話するAIはコードを書く上に議論にも付き合ってくれるというマルチプレイヤーなので、責務を切り分けて「マネージャー」と「コーダー」に分割してみたい。その上で、マネージャーは「要件を定義する役。要件は必ず1個のモジュールの追加か修正まで最小化する」という役割を負う。コーダーは要約を聞いてコードを生成するだけ。

更に将来的には、このマネージャーと議論をする役、つまり俺に相当する「クライアント」役のAIも登場させて、完全自動でどこまで進化できるか見てみたい。

--

トークンの課題は結構深刻で、こいつらができることのスケールをかなり制限してる。方針は2つあって:
・技術がさらに進歩するのを待つ
それなりに現実的。トークンが1000倍くらい使えるようになったら、それだけスケールできるようになる。後はサイフとの相談である。
・ファインチューニングを試してみる
これ全然わかってなくて言うけど、なんかモデルを微調整することがOpenAIのAPIでもできるらしい。使えるモデルは今のところ4つしかなくて、実質1択くらいの感じではあるが(しかも1応答しかできないモデルらしいが)。
となると
「PlayWithGPTのモジュールリストは?」>「fuga.pyとhoge.pyとpiyo.pyと……」
「fuga.pyの中身は?」>「#def なんたらかたら……」
みたいな学習をさせれば、そのモデルはPlayWithGPTについて全部知ってる上で議論やコード生成をできるわけだから、トークンの大幅な圧縮になる。かもしれん。
リポジトリが更新されたら、またファインチューニングを行う必要はあるが……。そのあたりも自動化するコードは生成してもらえるわけだから、後はサイフとの相談である。

トークンが短期記憶に相当するとしたら、学習は長期記憶に相当する部分で、ファインチューニングは追加の学習って感じなのかな。ちょうどこの間をとりもつ何かがあればいいんだけどなぁ。

16400802 journal
日記

yumeの日記: RogueLikeゲームを作るぞ 4

日記 by yume

カードの発動効果を実装する。

プレイヤーやエネミーのあらゆるバフ効果は、カードの発動という形で表現する。例えば「二倍速で動く特性を持つエネミー」は、このゲームでは「2倍速になるカードを最初のターンで使う」という形で表現するように。

・ActorModelクラスはInventoryModelクラスを持つ。
・InventoryModelは所有すべきカードを0-複数持つ。
・ActorBrainは、状況に応じてインベントリからカードを発動する。

カードの発動処理は:
・あらゆるカードは、発動効果を表す「IInovkeEffect」変数を持つ。
・IInvokeEffectはInvoke(IActorModel user, IItemModel parent)を持つ。
・Invoke()関数は、userに必要な影響を及ぼしたあと、parentを破棄する。

発動効果の種類は:
・あらゆるIInvokeEffectを実装したクラスは、InvokeType変数を持つ。
・InvokeTypeはInvokeEffectの種類を表す。

あらゆるカードはCardProfileによって生成される。ProfileにはInvokeType変数も含まれ、そのTypeに即したInvokeEffectクラスを生成し保持する。

こんな感じ。

書いてて思ったけど「ダンジョンそのものに影響を及ぼすカード」を発動したい場合、「使用者->カード->発動効果->使用者->ダンジョン」という流れになるなぁ。まぁ現状でもActorはダンジョンを変数として保持しているから、動くので特に問題はないんだけど。
ダンジョンの一部の「カード発動コントローラー」みたいなのを置いて、「使用者->ダンジョン->カード発動コントローラー(にカードを渡す)->カード->発動効果->使用者などのターゲット」とした方が読みやすそうかな?
その場合、カードの効果を受けうる「IAffectable」インターフェースを作れば、ダンジョンもActorも等しくカード効果を受けられそうな気はする。まぁとりあえずいいや。

16398734 journal
日記

yumeの日記: RogueLikeゲームを作るぞ 3

日記 by yume

メッセージ表示の仕組みを作る。

ResultMessageUIは、メッセージの出力を管理する。画面の表示はResultMessageUIViewが行う。

今のところ、メッセージが表示されるのは戦闘結果だけ(誰が誰を攻撃し、何点のダメージを与えたか)。
挙動の流れは次のようになる:

・ActorModelからIObservable OnActResultを生やす。
・OnActResultを購読すると、そのイベントが実行されたとき、IActResultを実装したクラスを受け取れる。
・これをActor全員分ResultMessageUIが購読する。
・Actorが戦闘を行うと、結果がOnActResultを通じてIActResultとして伝わる。
・ResultMessageUIは、受け取ったIActResultをResultMessageUIViewに伝え、画面に表示する。

この感じで、メッセージを表示したいあらゆる処理を、IActResultインターフェースを実装したクラスのインスタンスを飛ばすことでメッセージUIに伝達できる。
……関係ないけど「IActResultインターフェースを実装したクラスのインスタンス」って超長いな。「IActResult型で受け取れる」と書きたいけどクラスじゃねえしな……ってなってるんだけど、これ簡潔な言い回しあります?

結果はこんな感じ

次はアイテムの発動効果を実装したいんだけど……これ毎回困ってるんだよな。
パッと思いつくのは……
発動効果インターフェース「IInvokeEffect」を定義して、あらゆる発動効果はこれを実装したクラスとして表現する、ということにしたとする。
あらゆるカードは全てScriptable ObjectというUnityが用意したクラスを継承していて、これはUnityエディター上であるクラスの内部変数を変えたアセットを複製しておけるというものだが、この場合どのカードがどの発動効果クラスを使うかを当て嵌めなきゃならん。
そこで、InvokeEffectType列挙子を定義して、発動効果が増えるたびにそのTypeも増やす。
全てのカードはInvokeEffectType変数を持ち、そのカードの発動したい効果にあったTypeを選ぶ。
ゲーム中、発動効果を使う際に、Typeに応じて適切なInvokeEffectクラスをインスタンス化して、そいつを実行する……ってな感じかなぁ。
まぁ発動効果を100も200も作るわけではないだろうから、別にこれでもいいのかな。発動効果の効果量が変わる場合とかどうしよう。それも別のTypeとするか……うーん。

16397765 journal
日記

yumeの日記: RogueLikeゲームを作るぞ 2

日記 by yume

ゲームの根幹部分となるActorたちのステータスやアイテム・装備の概念を進めていく。

このゲームでは、あらゆるActorは武器・防具・基礎HPのみでステータスが構成される。
Actorクラスは座標とActorStatusクラスを持つ。
ActorStatusクラスは、EquipSlotクラスを持ち、HPや攻撃力などのステータスを表現する。
EquipSlotクラスは、武器と防具を保持するクラスである。

武器も防具もCardと呼ぶ概念で表現される。
Cardは武器・防具・消耗品としての能力をそれぞれ併せ持つ。つまり1つのCardは武器であり、防具であり、巻物や薬である。

Cardの武器としての性能は、6面の結果を持ち、攻撃するたびにそれのどれかが選ばれて能力として発動する。
例えば:
1の目:6ダメージ
2-5の目:2ダメージ
6の目:ミス
こんな具合である。
防具としての性能は、現状は単にHPを増やすだけである。

プレイヤーはInventoryを持ち、そこから自分の装備を選んだり、Cardを消耗したりする。
エネミーは1つのCardを武器・防具それぞれにセットし、それによりステータスを決定する。
つまり、エネミーは単一のカードでステータスを表現する。

あと、パラメーターを表現するUIを入れる。カーソルを合わせると敵のパラメータも見えるようになっている。

パラメータができたので、各レベルを終了したりゲームオーバーになったりする処理も追加。

レベルが終了できるようになったので、レベル終了時に報酬としてカードを3択から1枚選ぶ処理を追加。

アイテムが追加できるようになったので、アイテムを武器や防具として装備する処理を追加。

ここまでこんな感じ。結構時間かかっちゃった。

前回より画面の解像度があがっている。現状は480x270ピクセルで表現しており、これはフルHDモニターできっちり4倍に拡大した状態に等しい。
実際のモニターを24インチとして、文字が小さすぎるということはないと思うが、まだ検討中。最終的には様々なアスペクト比に対応しなきゃならん。まぁUIの細かいところは、一通り揃ってから考えないと。

次はActorの行動の結果をテキストとして表示する処理を加えたい。

16395419 journal
日記

yumeの日記: またブラウザゲーム作ったよ〜

日記 by yume

itch.ioで『Please, Stop my Laser!!』を公開したよ。
Mini Jam 122: Intermission 参加作品。
トップダウンアクションレーザー逆イライラ棒自爆タイムアタックゲーム。
マウスまたはゲームパッドで操作。1プレイ2分くらいで終わるぞ。

--

今回の制限は『Losing is Good』、つまり負けるが勝ちとか、負けると良くなるとか、負けることにインセンティブを持たせるとかそういうやつだった。
パッと考えて出る案は、死ぬとプレイヤーキャラが足場ブロックとして残り、ステージを攻略しやすくなるパズルプラットフォーマーとか、死ぬたびにRisk of Rainみたいに強化されていくとか、そんな感じのゲーム。

でももっとシンプルに「死ぬことがゴール」というゲームにしようと思った。
といっても、ゴールが針の山で、そこに触れたら即死=クリアとしちゃうと、ゴールの旗が針の山のグラフィックに変わっただけのことだし、さりとて途中のクリボーだのに触れて死んじゃえるならそれに触れればよくない?ということになる。
なので、ここでは「めっちゃ強いプレイヤーキャラをどうにかして自爆させる」という体験をコアにしようと思った。といっても単にプレイヤーキャラが硬いだけだと退屈なので、「制御不能なつよつよレーザーが出しっぱなしになっている」ということにした。
設備は壊すと爆発を起こし、プレイヤーが近くにいる場合は大ダメージを与える。敵キャラはプレイヤーキャラを発見すると追尾し攻撃する。そういうわけで、プレイヤーは敵キャラを壊さないように近づいたり、設備の爆風半径に近づけるまで進んでから設備を爆破するなどの精密さを要求される。プレイヤーキャラは常に前進する方向へレーザーを放つので、対象に近づこうとすることは対象を危険にさらすことになる。ここにジレンマが生まれる。
ゲームはクリア時間を計測し、それが記録される。よいタイムを目指すには素早さと精密さが要求される。
そんな感じ。

typodupeerror

私は悩みをリストアップし始めたが、そのあまりの長さにいやけがさし、何も考えないことにした。-- Robert C. Pike

読み込み中...