2016年9月26日月曜日

('ω'乂) 実装の不具合は \( 'ω')/ テストでカバー

なんか今回、自分の書いたコードに自信持てなかったんですよね。
なんで、職業プログラマ流の力技で解決しました。

ああああああああああああああああああ


はい、バグいっこ見つかって、全ケース完走しました。
あー面倒くさかった。ケースの妥当性? 知るか。

居合

お久しぶりです。
宿屋成長システムは置いておいて、先に「居合」というシステムを実装していました。このシステムは、武器を持ち替えるのと同時に攻撃する戦闘中技を可能にします。

このゲームは、主人公が常に一人であることを前提にデザインしてあるので、戦闘が単調になりがちです。そこで戦闘の幅を持たせるため、この「居合」システムを実装しました。


戦闘シーンのクラスを、複数箇所上書きして作成しています。
ちょっとしたハックじゃないかと思うくらいの修正箇所です。

ウィンドウの仕組みとか、いちいち説明めんどいので、割愛します。


さて、割愛したので、早速ですが出来た物の紹介です。
まず技ですが、メモ欄にキーワードを書く定番の実装です。
居合をstripoutと訳すのは、何かのTRPGで見かけた訳例です。
そこまで良い訳とも思いませんが、iaiと書くのもなんかダザいので、これでいきます。

武器が複数必要なので、武器の入った宝箱を設置します。
これは別に普通の武器と宝箱です。

対応した技を選択すると、武器一覧が表示されます。
これは、装備変更画面で使われているウィンドウを流用しています。

武器の選択が終了すると、武器ウィンドウが閉じ、敵キャラ選択ウィンドウが出ます。
なお、敵選択をキャンセルすると、再び武器ウィンドウが出ます。

攻撃エフェクトから判断する限り、きちんと武器が切り替わっているようです。


戦闘終了後、確認すると装備が変更されていました。
これが仕様として良いかどうかはともかく、正しく実装は出来ているようです。




居合システムはプレイヤーが一人であるという特殊な仕様を前提に実装しています。戦闘参加プレイヤーが複数人いると、バグが発生します。


さて次こそは、宿屋成長システムを実装します。

2016年9月23日金曜日

採取場_イベント側

前回記事で、作るよって言ってた採取イベントのイベント側実装です。

イベントタブ構成や名称のルールは前回記事で紹介した通りです。

ランダムで、袋が落ちていて、ポーションが拾えるというイベントです。


この羊は、前回作ったセルフスイッチ初期化スクリプトを呼び、また日替わりの乱数に値をセットします。実際のゲームにおける宿泊イベントを想定したテストドライバです。

第一タブでは非表示になっていますが、この袋を5つほど落としてあります。
2個セットの袋は前回のテストデータなので無関係です。

初期状態では、日替わりの乱数がセットされていないので、何もありません。
羊に話しかけ、イベントの一時消去を解除するためにマップ移動を挟みます。

袋が2つ落ちています。

回収します。

再び、羊に話しかけ、部屋を往復すると、今度は3つ袋が落ちていました。

続きまして、おもらしした場合の検証です。
ぬいちゃんには毎度申し訳ありませんが、おしっこを漏らしてもらいます。

おしっこ臭さの表示が現れるのと同時に、マップ内の袋が消えました。


さて、採取場の実装はこれで完了です。
そもそも課題として挙げるのを忘れていたので、今バージョンに含める予定も無かった仕様なのですが、作ったので含めます。


あれ? おしっこ臭さ関連機能としてついでに盛り込んだけど、
別におしっこ臭さ参照してなくね…?(参照しているのはおもらし回数)

採取場の実装

前回、おしっこ臭さが役に立つものの例として、採取場を挙げました。
それで採取場のことがずっと気になっていたので、一思いに実装しました。

実装してみると、採取場というのは結構大変なものでした。

なお、採取場の仕様は以下の通り
  • 一つの採取場につき、取得できるアイテムは一種類
  • 採取できるかどうかはランダム変数を参照
  • ランダム変数は日替わりなので、有効な採取場も日替わり
  • おもらししていると、採取場は使えない

そして以下のような、イベントページ構成を想定しました。

  • 初期状態。ランダム変数を参照して、イベントの状態を切り替える(自動実行)
  • 採取可能状態。アイテム取得後、イベントを採取不可状態に切り替える
  • 採取不可状態。イベントを一時消去する(自動実行)
  • おもらしによる採取不可状態。イベントを一時消去する(自動実行)

このうち、セルフスイッチを用いて状態を判断する必要があるのは、「採取可能状態」と「採取不可状態」の2つです。

しかしここで問題が発生します。
この仕様と方式の場合、日を跨いだ後は再び初期状態に戻ってイベントの状態の切り替えが行われる必要があります。しかし、セルフスイッチを使って切り替えている以上、他のイベントからはアクセスできません。

セルフではないスイッチを使えば原理的には実現可能ですが、複数のマップに散らばった多数の採取場が重複せずに各自のスイッチを利用し、それらを漏れなく初期化することは現実的ではありません。

そこで、飛び道具としてスクリプトを使い、セルフスイッチをOFFにすることにしました。

ソースはこんな感じです。

これだけのソースですが、これを書くにはちょっとした調査を要しました。
要点は以下の2点です。

  • セルフスイッチはツクールのシステムクラスにラップされたハッシュに真偽値として保存されていて、キーは[<マップID>,<イベントID>,<スイッチ番号>]の配列である
  • GUIから入力できるマップの情報(イベントを含む)はRPG::Mapというクラスのオブジェクトとして保存されていて、このオブジェクトを取得するにはload_dataというメソッドを用いる

これだけのことを調べるのに、えらい時間がかかりました。

さて、このスクリプトではイベントの名前を参照しています。
採取場として扱うイベントは、名前に"<gathering/>"という文字列を含めることにしました。
アイテムのようにメモ欄があれば良かったのですが、まあプレイヤーに見えるところではないので、良しとしましょう。

さて、テストです。
テストデータとして、このようなイベントを作りました。
採取場初期化スクリプトではAとB、2つのセルフスイッチをOFFにする仕様としたので、このイベントではA,B二つのスイッチを使って、実行するごとに袋が2つ→1つ→0と減っていくようにしました。

袋を設置しました。右にあるレバーはスクリプト起動用です。実際には宿屋イベントの中で起動することになります。

袋を拾います。片方は1個だけ残しておきます。

マップを跨いでも有効であることを確かめたいので、別のマップにも袋を設置しました。

こちらも同様にします。

では、レバーを引きます。

袋が元に戻りました。

こっちも同様です。


以上が採取場初期化スクリプトでした。
ところで、今回は採取場の実装というタイトルにしましたが、実はまだ採取場イベント自体は出来ていません。
次回は、今回のスクリプトを前提とした、テンプレートとなるイベントを作成します。

2016年9月22日木曜日

おしっこ臭さシステム

さて、ver0.2公開に向けて、既に次バージョンに含める決定し、開発を進めています。

今回は、「おしっこ臭さシステム」というものを実装しましたが、この構想についてはまだ紹介していなかったので、ちょっと説明します。この機能は、このゲームの設計思想にも関わるところなのですが、そのあたりはこちらの過去記事に詳細に記しています。


この中で、おもらしのデメリットを大きく設定することが重要であることを述べましたが、今回の機能は、まさにおもらしのデメリット関するシステムです。

しかし、戦闘力の低下はおもらしのデメリットとして、単体では不十分かつ、程度が大きければ不適当であると考えています。
理由は以下の二つです。
  • トイレが宿屋の近くにあることを前提に、トイレ直前でのおもらしにもデメリットを課したい
  • おもらしが全滅に直結すると、おもらしの羞恥や不快感などを回避するのとは違う趣になる

そこで、おもらしのデメリットは成長やアイテム入手に対するマイナス修正とするのが適当と考えました。

今回の「おしっこ臭さシステム」は、そのうちアイテム入手に対するものです。
このゲームでは「おしっこ臭さ」というパラメータがあり、それがアイテムドロップ率に対するマイナス修正となります。また、将来的にはこれを参照するイベントフォーマットを作成し、採取場を使えるかどうかにも関わるようにする予定です。
おしっこ臭さは以下のように決定されます。上に書いたものほど、影響度が大きいです。
  • おもらししたぱんつを穿いている場合、加算
  • おもらしした服を着ている場合、加算
  • おもらしした装備品を装備せずに持っている個数に応じて加算
  • 今日、おもらしした回数に応じて加算


では、仕様はこのくらいにして、実装に話を移そうと思います。
今回の機能は、以下の小機能から成ります。
  • おもらしにより衣服が濡れる処理
  • 濡れた衣服を洗濯して元に戻す処理
  • おしっこ臭さを取得する処理
  • アイテムドロップ率を修正する処理
  • おしっこ臭さをステータス表示する処理

これら処理は、濡れた後の衣服を別データとして、必ず通常時の衣服の次のインデックスに配置するフォーマットを前提にしています。
また、濡れた後に衣服には、濡れた衣服であることを示した"<wet/>"というタグを付けています。濡れた衣服のステータスは個別に設定していますが、本来よりもかなり低い値にしています。

おもらしによって衣服が濡れる処理は、以下のように別のアイテムと交換して装備を変更する処理として実装しています。なお、服が濡れるのは、前押さえをしながら漏らした場合か、パンツタイプの衣服であることを表す"<pants/>"というタグが付いている場合に限ります。

おしっこ臭さ取得処理は、"<wet/>"タグの付いたアイテムを探して計算することによって実装しています。
洗濯処理は、逆の手順を踏んで濡れた衣服を濡れる前の衣服に交換する処理になっています。

なお、ステータス表示は、既に実装したものを拡張しています。


ドロップ率を修正する処理は、毎度おなじみの既存の処理を再定義する方法で実装しています。

ここは、アイテムドロップ率の補正値を取得する処理です。これに、おしっこ臭さによるマイナス修正を乗じています。


では、実際に動かしてみましょう。

おもらしをしてしましまいた。この時点では何も表示されていません。

おもらしが終わると、尿意の下に水滴のマークと数字が表示されます。これが「おしっこ臭さ」です。

なお、ぱんつが濡れている場合のおしっこ臭さは4、おもらし回数は一回につき1としているので、合計値でおもらし臭さ5となっています。

装備を確認すると、ぱんつがおもらしぱんつになっています。今のおもらしは前押さえ無しのおもらしで、かつ白ワンピはパンツタイプではない服なので、服は無事でした。 

濡れ物を洗濯すると。ぱんつの分のおしっこ臭さが無くなって、おしっこ臭さは本日のおもらし分の1になります。

なお、スクショを貼っても面白くないので割愛しますが、ドロップ率が下がることも、なんとなく確認しました。


さて、今回は「おしっこ臭さ」というアイテム入手に対するマイナス補正となる要素を実装しました。
ところで、記事前半に以下のような記述をしています。
>おもらしのデメリットは成長やアイテム入手に対するマイナス修正とするのが適当と考えました。

そういうわけで、次回はおもらしによる成長へのマイナス修正となる「宿屋成長システム」を実装します。
概要としては、戦闘勝利時の経験値の取得を保留し、宿屋に止まった際に一括で経験値取得するというものです。この経験値に、本日おもらし回数によるマイナス補正を加えます。

宿屋イベント全般的なUIにも関係するので、ちょっとボリュームが大きくなりそうです。
更新間隔開くかも知れませんが、あしからず。

2016年9月19日月曜日

ver0.1体験版完成

さて、体験版が完成しましたので、公開します。

今作は体験版なので、漏らしたらゲームオーバーにしています。
難易度高めの漏らし覚えゲーになるように調整しています。
オープニングとチュートリアル終了後、すぐセーブすることをおすすめします。

以下、操作方法

Z : 決定
X : キャンセル メニューを開く
A : 前押さえ
S : HP回復ポーション
D : SP回復ポーション
Shift : ダッシュ(前押さえ中は不可)


ダウンロードは以下リンクから
https://drive.google.com/open?id=0B__QDdlVzb5LZGE4VDFqV2NLODQ

なお、ツクールの機能で圧縮したところ、自己解凍形式EXE形式のファイルになったのですが、EXE形式で上げるのも嫌だったので、zipで固めています。
なので、お手数ですが2回展開して下さい。

また、プレイするにはツクールの実行環境が必要ですので、お持ちでない方はこちらからダウンロードして下さい。
http://tkool.jp/support/download/rpgvxace/rtp

2016年9月11日日曜日

ソビエトロシアではソースコードを元に設計書が書かれる

さて、ソースが一通り完成したので、一旦こないだのようなメモ程度の設計書を起こそうと思っています。しかし、前回同様の呼び出しや参照・更新を線で繋いだような図では対応しきれないことに気付きました。
それもそのはず、モジュールを分割し、内部処理を隠蔽して、明確なインターフェースを定義するのは、その処理を必要とする広範な状況に対して呼び出しを許すためでした。

そこで、各モジュールを役割とインターフェースができるだけ明確になるように再び紹介することで、設計書に代えたいと思います。


Interval_Execute

毎フレーム実行すべき処理をキックするためのモジュールです。
他のモジュールでそうした処理を実装した場合、ここに起動する処理を追加します。
なお、ツクール既存の毎フレーム実行処理を再定義して拡張することで実装しています。


Pee_Holder

尿量、尿意、利尿度の3つのパラメータと、それらを更新するためのメソッドを持つモジュールです。
各更新メソッドは毎フレーム呼び出されることを想定しています。
尿意更新メソッドは尿意が100%になった時に、限界フラグを立てることで、おもらしイベントを誘発します。
尿量更新メソッドは排尿中の場合のみ、尿量を減ずるモードで動作します。


Status_Drawer

マップ上の画面左上の各ステータスの表示を管理するモジュールです。
文字画像のビットマップと、表示位置を保存したスプライトを管理しています。
HP,SPなどのプレイヤーステータスとPee_Holderの各値を参照して表示を更新するメソッドがあり、これは毎フレーム実行されることを想定しています。


Potion_Manager

ポーションの使用に関する処理をまとめたモジュールです。
ポーションの効果やエフェクトを実現する各メソッドを持っています。
また、ショートカットキーの入力を検知して他の処理を呼び出すためのメソッドもあり、これは毎フレーム実行されることを想定しています。
なお、ショートカットキー以外からポーションが使用された場合、利尿度以外の値の更新はこのモジュール内ではなく、通常のアイテムの効果として実装しています。


Hand_Hold_Manager

前押さえに関する処理をまとめたモジュールです。
前押さえ状態であるかどうか、前押さえの強さなどを返すメソッドを持ちます。
また、前押さえ状態のフラグと歩行グラフィックを更新するメソッドがあり、これは毎フレーム実行されることを想定しています。


Script_Item

アイテムのメモ欄に任意のコードを記述し、使用時に実行するためのモジュールです。
ツクール既存のアイテム使用処理を再定義して拡張することで実装しています。
戦闘中とメニュー画面で、別の処理になっていたので、双方に同様の拡張を加えています。


ツクールのイベント、変数、スイッチなど

モジュールとは違いますが、使い分けを明確にすべきだと思うので追記します。
ゲームシステムのコア部分はスクリプトで、プレイヤー視点でイベントが発生したと言えるようなものはイベント、コモンイベントで実装するのが良いと考えています。
スイッチと変数は、イベントやコモンイベントとして実装する部分と、スクリプトで実装する部分が連携する場合に使います。
スイッチと変数はグローバル汚染に対して脆弱な部分なので、スクリプトからは上記以外の目的では使わないようにします。
また、イベントからの使用はセルフスイッチだけで解決できない場合にのみ限定します。




こんなもんですかね。これ書きながら何か所か役割分担という観点から見て望ましくない実装を改良できたので、書いた価値はあったと思います。
最大の目的は、後から自分が見返して昔書いたコードを解読する助けになることですが。

さあ、あとはイベントを最後まで作り切って、おもらし絵を描いたらいよいよプレビュー版の完成です。

おしっこ流量の調整

排尿中の尿量の減少が自然な変化になるように、排尿を管理するUrinationクラスをおしっこ我慢クラスの内部に作りました。

ソースはこんなもん。

flowは1フレーム間に排出された尿量を返します。
Urinationインスタンスの内部では排尿の速度を管理しており、flowは1回呼ばれるたびに、その値を1回修正します。

排尿速度の修正値は以下のようになるようにしています。

  • 定数として定義された最大値・最小値を持つ
  • 初期値は0なので、初期状態直後では最小値に満たないが、この間は急激に上昇する
  • 最小値を超えてからもゆるやかに上昇する。最大値を超える場合は最大値となる
  • 現在尿量が排尿開始時半分以下になった場合、減少に転じる。最小値を下回った場合、最小値となる
  • おもらしかどうか、前押さえをしていたかどうかによって、値は違う

なお、最大値と最小値に関しては以下の記事を参照しました。
http://ja.healthline.com/health/uroflowmetry#Results


最初はじわわわっと、その後ジョーっと、最後は弱い勢いでチョロチョロ出続ける感じを多少出せるようになったと思います。


あとはイベント面でのボリュームをもう少し充実させて、バランス調整して、おもらし絵描いたらVer.0.1は完成といっても良いかも知れません。思ったより早く公開できそうです。

さて、今日はもう眠いので寝ます。おやすみなさい。

おもらし

さて、おしっこ我慢ゲーの一つのコアとも言えるおもらしの実装を紹介します。

おもらしは、スクリプト側で実装しているおしっこ我慢と密接に関わると同時に、グラフィックや台詞の表示などを含む一つのイベントです。スクリプトとして実装したい部分も、イベントとして実装したい部分も多分にあります。

そこで、おもらしは以下の2つの実装に分割しました

  • コモンイベント
  • 尿量増加メソッドの特殊モード

両者はスイッチを更新することで、状況を伝えあって連携して動作します。

コモンイベントはこんな感じ。


そして、尿量増加メソッド。コード量でいうと、この部分はほとんどがおもらし用ですね。


おもらし進行のフローの概要は以下の通りです。
なお、尿量増加メソッド・尿意増加メソッドは常に平行実行されています。

尿意増加メソッドが、尿意が100%になったことを検知した場合、限界フラグを立てる

おもらしイベントが限界フラグをトリガーに起動する

おもらしイベントが排尿フラグを立て、待機状態に入る

尿量増加メソッドは、排尿フラグが立っている場合、尿量を減少させる動作をする

尿量増加メソッドは尿量が0になった時点で排尿中フラグを落とす

おもらしイベントは排尿フラグが落ちた時に待機状態を解除する

おもらしイベントの続きが実行され、おもらしが完了する

なお、これはあくまで概要で、上記以外に他イベント中のおもらしを防いだり、おもらしイベントの連続起動を防いだりするためのフラグの操作などもあります。

まだおもらし用のグラフィックが無いので、ゲーム画面のスクショを乗せるのは後にしますが、おもらし中は、尿量の表示を見ていると尿量が減っていくのが分かるようになりました。

次回は、この尿量の減り方が自然になるように配慮した部分を紹介します。

尿意の波と前押さえ

フレームごとの尿意の更新処理は、尿量を基本値としていますが、これに前押さえと尿意の波が補正として掛かります。

ソースだとこんな感じ。


波生成のコードはこんな感じです。ここだけで完結してるので、コードさえ書ければ簡単ですね。ウディタだとGUIでやらなきゃいけない上に、扱える数値の制限の関係で変な仕様になっていたので、えらい大変でしたが。



前押さえのほうは、歩行グラフィックの切替、ダッシュの禁止、停止中と歩行中の前押さえの強さを制御しなければならないので、もう少し大変です。

上が、前押さえの強さを、尿量換算で何ml分に相当するかを返すメソッドです。
下は、ダッシュ禁止のためにシステム側のメソッドを再定義したものです。

グラフィックの切替は、毎フレーム実行処理として以下の部分を追加しました。


さて、前押さえのグラはこんな感じです。



うーん、押さえてるところ単体の静止画だと分かりにくいですね。
まあ、グラフィックは仮置きなので、当面はなんか動いてるなって分かればいいです。

キーボードでいうとAを押すと前押さえします。その間は尿意の増加にマイナス補正がかかり、相当おしっこが溜まっていなければマイナスになります。立ち止まって前押さえしている場合は、特にマイナス補正は大きくなります。また、ダッシュはその間できなくなります。


前押さえがあると、ちょっとおしっこ我慢ゲーっぽいですね。
され、次回はいよいよおもらしを実装します。

ポーションの使用

しばらくブログの更新を後回しにしてしましました。
スクリプトを中心に、かなり進んでいます。
今から連投しますが、まずはポーションの使用を。


ポーションは以前にウディタで作った時と同じ以下のような仕様です。

  • HPポーションとSPポーションがあり、どちらも利尿作用があるが前者のほうが強い
  • 特殊コマンドとして実装し、ショートカットキーで使用できる
  • 個数という概念はなく、無限に使用できる
  • 回復量は最大HP・SPの半分


使用方法は以下の3つあります

  1. マップからショートカットキーで使用
  2. 戦闘中に特技として使用
  3. メニュー画面から、特技として使用

実際のゲームプレイの中で主に使われることを想定しているのは、1と2ですが、特技として実装したものをメニューから使えなくするのも不自然ですし、キーボードショートカットに関する説明を書いておけばチュートリアルで見逃された場合の救済にもなるので、残しました。

ツクールでスクリプトをがっつり書いていると、コモンイベントやその他のツクールのGUI機能を使うか自分で書くか迷うものですが、特殊効果のあるアイテムや特技は、ちょうどこの境界上にある要求だと感じました。

結局のところ、以下のようになりました。

  • ショートカットキーからの使用は全てスクリプトで実装する
  • 戦闘中とメニューからの特技使用は、利尿度の更新以外はツクールの機能で実装する


コードはこんな感じになりました。酷いラビオリコードですね。
これがベストプラクティスだったかどうかは疑問ですが、それなりの理由があってこうなっています。

なお、check_inputが、毎フレーム呼び出される部分で、ここから他のメソッドが呼び出されます。


そして特技はこんな感じです。回復やダメージの計算式を書くことができるのは、確かウディタには無かった仕様です。便利ですね。

利尿度だけはスクリプト側でオブジェクトのフィールドとして管理している値なので、コードを介さなければアクセスできません。
しかし、チュートリアルに、アイテム使用時の処理を再定義・拡張してメモ欄を参照するようにする方法がありました。

これに倣って以下のようにしました。また、戦闘中のアイテム使用に関しても同様にしました。

これでアイテムのメモ欄に書いた任意のコードを使用時に実行できます。
これを利用して、別出しした尿意更新の部分の処理だけを読んでいます。コードが断片化してしまったのは、このようなアクセスを可能にするためです。


さて、これでポーションの使用が可能になるはずでしたが、ショートカットキーが反応しないことがあることがわかりました。
どうやらコモンイベントからの呼び出しが良くないようです。必ずしも毎フレーム呼ばれるわけでは無いのでしょうか。
そもそも常時並行実行を目的にコモンイベントを用いる方式は良くないと思っていたところなので、結局インターバル実行のコモンイベントは廃止し、Scene_Map.updateにまとめることにしました。


で、こんな感じになりました。上から順に、ショートカットキー、戦闘中、メニューから。





はい、こんな感じです。
次は何について書こうかな。