|
RPGツクール2000ではプログラミング言語を使えないので、 計算式を入力して直接計算するということが出来ません。 難しい計算を入れようと思うと、変数を一個一個定義して それらの四則演算を駆使する必要があります。 1+2×3 みたいな式であれば、優先度の高い掛け算の方を先に計算して ◆変数1番 = 2(2を代入) ◆変数1番 × 3(3倍する) ◆変数1番 + 1(1足す) みたいにしてやれば、1個の変数で足ります。 しかし、2×3+4×5 のような式を計算する際は変数1個では足りません。 一時的に計算用の変数を用意しておいて、それを途中計算で使うことになります。 ◆変数1番 = 2 ◆変数1番 × 3 ◆変数2番 = 4 ◆変数2番 × 5 ◆変数1番 + 変数2番 一般に、計算式が複雑になればなるほど一時変数は多く必要になります。 では、最低何個あれば足りるのか、というのを計算式から判断できるでしょうか。 まず、上のように計算式をツリー構造に置き換えます。 一つ一つの丸のことをノードと呼びます。 2+3×5だったら3×5を先に計算するので、3と5を×の木で結び、 その結果と2を足すので、それぞれを+の木で結びます。 計算するときは、下から順にまとめていけばいいですね。 上の式なら次のように1つの変数があれば計算できます。 ◆変数1番 = 3 ◆変数1番 × 5 ◆変数1番 + 2 3×5の結果を使い、それに2を足せばOKです。 計算によって各ノードに至るまでに必要な使用変数の個数を下に数字で書いています。 ただの数値は基本変数を使わないので0としていますが、 初めの3×5の計算を行うために、3か5のどちらかを一旦変数に入れないといけません。 ここでは3を入れるものとし、3に変数を一つ使っています。 3×5の計算結果を変数1番に入れればよいので、×の使用変数は1となっています。 さらに、それに足した結果をそのまま変数1番に入れますから、 +の使用変数はそのまま1となります。 複雑な式になっても同じです。 ただ、引き算や割り算のように交換法則が成り立たない演算の場合は 左の数の方を必ず変数に入れなければなりません。 それに注意しながら使用変数の個数を振っていくと上図のようになります。 ◆変数1番 = 1 ◆変数1番 ÷ 5 ◆変数2番 = 1 ◆変数2番 − 変数1番 ◆変数2番 = 8 ◆変数2番 ÷ 変数1番 1÷5ではまず変数1番に1を入れておき、そこから5を割り算。 次に1からその結果を引く必要がありますが、変数1個では無理なので 変数2番を用意して、そこに1を入れておき、変数2番から変数1番を引けばOKです。 (A−B=−(B−A)でいいじゃんというツッコミは禁止です^^;) これを繰り返し、変数2個で計算できるということが分かります。 では、子ノードの値から親ノードの値を求めるにはどうすれば良いでしょうか。 そのノードに振られている値は、言わば計算がそこに至るまでに 使用した変数の最大個数を表します。 例えば上の式では「−」の部分で2となっていますが、 −の計算を終えた直後はもう変数1番しか使っていないので、変数2番が使えます。 8をわざわざ変数3番に入れなくても、使っていない変数2番に入れれば済みます。 だから、最後の「÷」は1+2=3個ではなく、 それまでの最大個数であった2個がそのまま÷に振られます。 演算を行う際には、各演算に用いるノードで使用変数が多かった部分を先に計算して 計算時に変数1個としておくことで、使用変数の節約が出来るようになります。 上図でいうと、使用変数が0個で済む2の方ではなくて、 使用変数が1個必要な3×5の方を先に計算すると最大個数が少なくて済みます。 上図のように使用変数が1個必要なもの同士を使って演算する場合は、 変数1番に左の×の結果を、変数2番に右の×の結果を入れて足し算する必要があるので、 変数は2個必要になります。 以上のことから、使用変数の個数について次の法則が言えます。 【四則演算における親ノードの使用変数個数】
2つの子ノードの使用変数個数がそれぞれa, bとすると、
・a≠bのときmax{a, b}(a, bのうち大きい方)
・a=bのときa+1
使用変数個数がお互い同じときしか個数が増えないということになります。 さっきの例がその法則に従って得られるか確認してみてください。 ◆変数の操作:[0003:一時]代入,変数[0001]の値 ◆変数の操作:[0003:一時]乗算,変数[0001]の値 ◆変数の操作:[0003:一時]乗算,64 ◆変数の操作:[0003:一時]除算,2025 ◆変数の操作:[0002:結果]代入,変数[0003]の値 ◆変数の操作:[0002:結果]乗算,-20 ◆変数の操作:[0002:結果]加算,12000 ◆変数の操作:[0003:一時]乗算,変数[0003]の値 ◆変数の操作:[0003:一時]除算,100 ◆変数の操作:[0002:結果]加算,変数[0003]の値 ◆変数の操作:[0002:結果]乗算,変数[0001]の値 ◆変数の操作:[0002:結果]除算,6750 ◆変数の操作:[0002:結果]乗算,変数[0004]の値 ◆http://www.geocities.jp/orreiclan/content/report/tkool2000math/sin.html 一時変数を含めて変数を3個使っていますが、本当に3個必要なのか確認しましょう。 この計算過程を下図のようなツリー構造にします。 たどっていくと、確かに3になっていることが分かりますね。 このように、何らかの計算アルゴリズムを作ったときに
その必要な使用変数の個数を求める際に便利だと思います。 ツクール2000では使えますが、最近のツクールだとあまり使わないかもしれませんね。 |
├原理・アルゴリズム
[ リスト | 詳細 ]
|
ツクール2000のフォントはMSゴシックとMS明朝だけが提供されていますが、 裏技により自分で作った文字を使用することが可能です。 システムグラフィックの文字色の部分に自作文字を書いちゃう方法ですね。 ↑このようにしておいて、文章の表示でこのようにすれば、 黒字で「じさくもじ」と表示されます。 文字の影を透明にしておくのを忘れないようにしてください。 \C[0]■\C[1]■\C[2]■\C[3]■\C[4]■ ツクール2000では文章の表示で書いた文字を、システムグラフィックの文字色の部分に被せて 文字の部分だけ切り抜いたものを実際に表示しているのです。 そのため、■と書けば文字色の■の部分がそのまま文字として表示されることから、 このような自作文字を実現できるのです。■だと9×9の小さいサイズの文字しか出来ないのですが…… これを利用すれば一部の場面で好きな文字を描画できて便利だったのですが、 長らく一度に多量の自作文字を使用することは出来ないだろうと思っておりました。 単純に、一つのシステムグラフィックで使用できる文字色が20色までだからです。 しかし最近になって文字描画と並列してシステムグラフィックの変更をすることが可能と聞いて 20文字の制限をなくせることが判明したのです。そんなこと出来たのですね…… 単純に、2つのイベントを用意して一方を並列処理して動かせば良いだけです。 【本体】 ◆スイッチの操作:[0001:会話開始]をONにする ◆文章:■■■■ ◆ 【並列処理側(出現条件:スイッチ[0001:会話開始]がON)】 ◆ウェイト:0.1秒 ◆システムグラフィックの変更:システム1 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:システム2 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:システム1 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:システム2 ◆ウェイト:0.0秒 ◆スイッチの操作:[0001:会話開始]をOFFにする ◆ システム1とシステム2はそれぞれ文字色の部分を変えたシステムグラフィックです。 本体では同じ文字「■」しか表示していないのに、 交互に文字が変わっていることが確認できると思います。 並列処理側がなんで最初0.1秒ウェイトなのかはよくわかりません。たぶんおまじないです。 その後は1文字ずつのシステムグラフィックの変更で対応できます。 標準の文字スピードだと1文字のウェイト時間が0.0秒ウェイトと同じなためです。 複雑な文字表示に対しては、文字スピードについての考察を以下にまとめたのでぜひ参照してください↓ http://www.geocities.jp/orreiclan/content/report/tkool2000formula/text_speed.html これを利用すれば、20文字を超えた自作文字の使用が可能になり、 自作フォントの使用が可能ということになります。 ひらがなを書いてみました。80文字です。 ↑これを土台にして、システムグラフィックを4個作ります。 1: 2: 3: 4: 実際に次のように入力します。 ただし、文章の表示が長すぎて標準の方法では入力することが出来ません。 このブログでは相互変換モジュールの導入をオススメしてます↓ ぜひぜひ! https://blogs.yahoo.co.jp/fermiumbay2/38560312.html?type=folderlist 別途HSPをインストールする必要がありますが、イベント命令をプログラムに変換して 色々出来るので、きっと便利です。これでどれだけ長い文章でも入力可能です。 【本体】 ◆スイッチの操作:[0001:会話開始]をONにする ◆文章:\C[4]■\C[5]■\C[17]■\C[2]■\C[19]■\C[0]■\C[1]■\C[10]■\C[12]■ ◆ 【並列処理側(出現条件:スイッチ[0001:会話開始]がON)】 ◆ウェイト:0.1秒 ◆システムグラフィックの変更:ひらがな1 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな2 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな2 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな1 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな3 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな4 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな1 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな2 ◆ウェイト:0.0秒 ◆システムグラフィックの変更:ひらがな1 ◆ウェイト:0.0秒 ◆スイッチの操作:[0001:会話開始]をOFFにする ◆ きちんと「おはようございます」と表示されていますね。
|
|
ボクらの故郷の戦闘にステータス異常のシステムがあるのですが、最近やっとできました。 まだ(未だに)次のバージョン公開してないので妄言のように思われますが、 ちゃんと実装したので大丈夫だと思います^^; 割と入り込んだシステムになってしまいましたが、たかがステータス異常の発生率ですので ゲーム中にそんな入り込んだシステムをお目にかかる機会はございません。 てきとうに決めても大差なかったと思います。 でもちゃんと調整が効くように作ったつもりなので、 実際やってみたらきっとコンフォーテボーなんじゃないでしょうか。
ステータス異常の発生率は、使用者と対象者のレベル差に依存します。 基本成功率は、使用者と対象者のレベルが等しいときのステータス異常の発生率です。c値は後述します。 例えばレベル15のベイ助がレベル15のゴブリンにポイズン掛けたら、90%の確率で毒状態にできます。 その際に、敵のレベルを求める必要があります。 怠惰ですので、敵一人ひとりにいちいちレベルなど決めておりません。 敵のレベルはその敵を倒したときに得られる獲得経験値から計算することにしています。 敵のレベルレベルxのとき、プレイヤーが次にレベルアップするために必要な経験値は2x^2+7x+11と決まっています。敵から得られる経験値は、プレイヤーがそのダンジョンへ行くときの推定レベルから導かれます。 どっかの洞窟へ行く頃にはだいたいプレイヤーはレベル10ぐらいなのであれば、 そのダンジョン突入時の推定レベルは10ということになります。 ちょうど推定レベルであったとき、そのダンジョンに登場する基本的な敵を5体倒せば レベルアップするような獲得経験値が、その敵に割り当てられるようにしてあります。 5体でレベルアップなんて少ないように思われるかもしれませんが、 経験値はメンバーに均等に分配されますので、4人パーティーなら20体倒すことになります。 ということで、そのダンジョンの推定レベルがxのとき、基本的な敵1体の獲得経験値は (2x^2+7x+11)÷5として求められることになります。 ネタバレになるから先のことは述べませんが、例えばきのこ林の推定レベルは1ですので、 基本的な敵1体から得られる経験値は(2+7+11)÷5=4になります。 ゴブリン1体倒せば経験値が4入るようになっています。 (後にパラメータ周りを大幅に改変したので、いま公開してるのと若干違うかもしれません) 脱線しましたが、要するにレベルxのときに戦うにふさわしい敵の獲得経験値は (2x^2+7x+11)÷5であるということです。 このような敵のレベルは、xに等しくあるべきだろうと考えまして、 獲得経験値f(x)=(2x^2+7x+11)÷5と置いたときにf(x)から逆算して求めたxをその敵のレベルと決めました。 すなわち、x=(−7+√(40f(x)−39))/4ですね。これが敵のレベルです。 ゴブリンの獲得経験値は4だったので、f(x)=4を代入すれば x=(−7+√(40×4−39))/4=1となるため、ゴブリンのレベルは1と決まります。 こうやって決めておけばいちいち敵のレベル考えなくてよくなりますし、 ボスから得られる経験値は普通の敵より多いことから、ボスのレベルは必然的に大きいものになって便利です。 このようにして敵のレベルを算出し、ステータス異常の発生率に利用します。 ステータス異常の発生率対象者のレベルと使用者のレベルの差によって成功率が変わるものとします。ここで、使用者のレベルが対象者のレベルに比べて限りなく大きくなっていった場合、 ステータス異常の発生率は限りなく100%に近づいてほしくなります。 逆に、対象者のレベルの方が使用者に比べて大きくなれば、絶対掛かってほしくないわけです。 ゴブリンの唱えた即死魔法に、レベル100のベイ助が掛かって死んだら何だか恥ずかしいですよね。 漸近的にどちらかに近づくといった関数が望ましいこととなります。 そういう関数で身近なものといえば、そうですね。指数関数でございます(身近かな??)。 x=(対象者のレベル)−(使用者のレベル)としたとき、ステータス異常発生率yは
y=ab^(cx)+dの形で表わされるものとします。 何だかまたおかしいことしてるなと思われるかもしれないですが、大体合っております。 でもこんな感じのグラフにしたい、と思ったときは、そのグラフを作れるような関数、なんでもいいので 考えてみて、それでいけそう……!!とか思えたら、その関数に決定し、 各定数を求めていく手続きをとるのが色んな意味で安全です。 自分の望む形のグラフができますし、思った通りの挙動を示します。 グラフではなくて式から考えると、後で、え!!なんでこんなでっかくなるんだよ!!とか、結構なります。 今回は上の不気味な式で確定して、各定数を求めていきます。 まず、使用者のレベルが対象者のレベルに比べて十分大きい場合、すなわちx→−∞となるとき、 発生率yは限りなく100%に近づいてほしいという条件を与えてみます。 すると、ab^(cx)→0になりますから(マイナス無限大乗は0)y=dとなりますので、 d=1であれば100%になりますね。従って、d=1とします。 一方で、レベル差がないとき(x=0のとき)は上の表で挙げた基本成功率になってほしいので、 基本成功率をrとしてx=0のときy=rになるようにします。 x=0だとab^(cx)=ab^0=aになるため、y=a+1となり、a=r−1であることが求まります。 bは指数関数の底に当たる部分ですが、これは b=e(自然対数の底)と決めてしまった方が後々計算が楽になります。 bとcはお互いに影響しあいますので、どちらかを固定しても問題はありません。 後は調整です。レベル差がどれぐらいあれば、成功率はどう変化するか。 それをもとに残った定数のcを決めることとなります。 ここでは次のように決めて調整することにします。 対象者のレベルが使用者のレベルより5高いとき、成功率は基本成功率から50%減少する。 根拠があったかどうかは忘れましたが、このように決めると x=5のときy=r−0.5という条件が新たに付加されます。 すると、y=(r−1)e^(cx)+1より、 r−0.5=(r−1)e^(5c)+1 (r−1.5)/(r−1)=e^(5c) c=1/5 ln((1.5−r)/(1−r)) としてcの値がrに依存して求まります。 このcの値は計算が面倒なので、上の方にある表のように各々計算しておきます。これをc値とします。 あとはその確率に基づいてステータス異常を発生させるだけです。 攻撃開始の表示が出て、真ん中のムカデが毒攻撃してきます。 毒牙はダメージと同時に毒状態にする攻撃ですが、 ムカデは攻撃力が低いのでほとんどダメージがありません。 (ダメージ計算の方法もそのうち書くかもしれません) 2. レベル差の計算まず、行動者である敵のレベルを計算します。ムカデの獲得経験値は5ですから、 x=(−7+√(40f(x)−39))/4 に f(x)=5を代入します。 x=(−7+√(40×5−39))/4 =(−7+√161)/4 =1.422……≒1 小数点以下は切り捨てられます。よって、レベル1です。 次に対象者のレベルを求めます。単純にメンバーIDから取得するだけです。 攻撃を受けたレイベはレベル2でしたから、 レベル差x=2−1=1となります。 3. 毒の式に当てはめて成功率を計算レベル差xのときの成功率yはy=(r−1)e^(cx)+1 で与えられまして、毒はr=0.9、c=0.3584でしたから、 これらとx=1を代入してyを求めます。 y=(0.9−1)e^(0.3584)+1≒0.857より、85.7%となります。 指数関数の計算には誤差が含まれますが、大体このぐらいの値になってくれるはずです。(指数関数) 毒を防御できる装備をしている場合などを除き、 ここで得られた成功率に基づいて毒を発生させます。 具体的には、0〜999の乱数を発生させ、それが857(85.7%)より小さければ成功、とします。 この場合は乱数がどんな値だったか記録し忘れてしまったのですが、 毒が発生したようです(毒のエフェクトまだかいてません)。 毒は基本成功率が0.9ですので、行動者と対象者が同レベルだと90%で発生しますが、 今回は対象者の方がレベルが1高かったことから、若干確率が落ちました。 しかし依然として高確率で発生することが分かります。 レベルが10ぐらい離れていたら、確率がマイナスになって (そうなったら0に修正します)絶対に起こらなくなります。 相手がボスでも、こちらのレベルの方がずーっと高ければ、ステータス異常に掛けることも可能です。
でもそんなにレベルが高かったらボスだろうと一瞬で倒せるでしょうから、 ステータス異常を狙う目的だけでレベルを上げることはまずない気がします。 |
|
ピクチャーの回転をして途中で止めれば傾いた画像を実現できそうですが、 通常回転を中途半端に止めることはできないので、 回転速度を0にしてしまう方法を用います。 回転速度を1〜9以外にするために相互変換モジュールを用います。 途中まで回転したら回転速度を0にします。 ↑これは時計回りに120°回転させたまま固定したものです。 ピクチャーの回転の角速度はこちらで示しましたように ω=45S/32 [°/F] であると推測されています。Sは回転速度、Fはフレームです。 回転は一瞬で済ませて固定したいので、ここでは1フレームで目的の角度にすることを考えます。 つまり、固定したい角度θは θ=45S/32[°] で与えられるとします。これを回転速度Sについて解くと S=32θ/45 となり、これを用いるとθから回転速度を得ることができます。 時計回りに120°回転したければθ=120°を代入して、 S=32×120/45≒85 ですから、回転速度を85にして1フレーム停止、 その後回転速度を0にすれば任意角度のまま固定させることが可能です。 ◆ピクチャーの表示:1, (表示画像)(回転速度:85) ◆ウェイト:0.0秒 ◆ピクチャーの移動:1, 0.0秒(W)(回転速度:0) ◆ これでOKです。これを自動化するスクリプトは以下の通りです。 #include "rpgfunc.as" #module #deffunc rotate_temp int id, str filename, double deg, int x, int y, int zoom, int trans speed = int((64.0 * deg + 45.0) / 90.0) pic id, filename, 0, x, y, 0, zoom, 0, 100, , 100, 100, 100, 100, 1, speed pause 0 picmove id, 0, x, y, zoom, trans, , 0, 1, 100, 100, 100, 100, 1, 0 return #global #define rotate(%1=1, %2="", %3=0, %4=160, %5=120, %6=100, %7=0) rotate_temp %1, %2, %3, %4, %5, %6, %7 これを先頭に書けばrotate命令が使用できるようになります。 rotate (ピクチャー番号), (ピクチャー名), (角度), (中心x), (中心y), (拡大率), (透明度) ↑ちょっとずつ角度を増やしつつ縮小、透過度を下げていったものです。
残像っぽくなってかっこよさそうですが、重たくて使い物になりません。 |





