投稿記事

プラグインの記事 (3)

ニル 2020/12/10 00:00

スクリプトの知識がなくても、自分と一緒に簡単なプラグインを作ってみましょう!

ツクールフォーラムアドベントカレンダー Advent Calendar 2020

https://adventar.org/calendars/5074

https://forum.tkool.jp/index.php?threads/【募集中】アドベントカレンダー2020.4530/#post-26453

まえがきの後は、特定スロットの武具の名前を、職業欄に表示するスクリプトを作成していきます。


まえがき(読み飛ばして頂いて構いません)

さて、今年は書く方が不足しているということで、久々にci-enで筆を取ってみたわけであります。

自分は、RPGツクールMV Trinityのps4版を発売直後に定価で購入したのが、初のツクールであり、
紆余曲折あり2019年の春前にMVへと移行してきました。

その時に感動したのが、プラグインという素晴らしいモノがあること。
そして、プラグインを利用するにも、スクリプトへの理解という壁が、何処までもついてまわるという事を実感しました。

競合の問題。欲しいゲーム内情報の取得法。何度も掲示板やSNSで諸先輩方に助けてもらって今があります。

そんな自分の現在はというと、バリバリスクリプトを書けるようになった!
なんてことはなく、初心者の粋を出て初級者にはなっている……と信じたい。
といった程度です。

自分で必要な分のゲーム内の情報を取得したり、
自分用のプラグインを(複雑なものではないです)書いたり、
他の方のプラグインを自分のゲーム用に多少調整出来る程度は、
なんとか出来るようになりました。

画面は現在作っているゲームのステータス画面です。
一応完全自作。頑張って作りました。


教える立場にいるのかといえば、
そんなレベルには達していないと自覚しておりますが、
右も左も分からなかった頃が直近であるからこそ、
特に何が分からなかったかをまだ覚えております。

もしここで自分がおかしな事を書けばきっと諸先輩方が指摘をしてくれるでしょうし、
もうそうなった場合は自分も一緒に学ばせてもらおう。
そして、お世話になった界隈に少しでも還元をと思い、書いていきます。

ぶっちゃけ記事の中で多くの部分に多分とついてしまう程度なのですが、かといって文章中に(多分)(多分)と
書きまくるのはあまりにウザいので割愛しますが、
実際問題、その程度の知識量であるということをご了承くださいませ。

スクリプトに関して、まず何に躓いたのか。

自分が当時、最も始めに疑問に思い、理解に時間がかかった事を書いていきます。

プラグインとはどうやって、いつロードされているのか。

プラグインっていつどうやってロードされてるんだ?
コモンイベントみたいに、呼ぶための命令をすれば良いのか?
もしそうなら、その命令とは?

プラグインコマンドで呼ぶものやメモ欄に記述するもの。
呼ばなくても動くもの。それらが混在することで、
特に、呼ばずに動くものは何故動くのかが当初理解できませんでした。

プラグインへの認識が、お借りして入れると(何故か)動く。
そういう風に作ったのであろうという事は理解出来ても、
それがどういう風に作ったらそうなるのかわからない。という感じでした。


これに関しては、

ゲーム中は常にスクリプトは常に絶え間なく呼び出されているものであり、
何かしら起動しているからです。

イメージ的にはイベントコマンドの並列処理がずーっと走っている感じでしょうか。


そして、プラグインとはコアスクリプトを上書き・或いは拡張するものであり、
コアスクリプトの処理に追加したり、
本来の処理と別のルートを辿らせる事で、
コアスクリプトが起動していく一連の動作の中で、呼び出されていきます。


つまり、然るべき場所(処理の近しい場所)にやりたい処理を追加する事が出来れば、
それだけで簡単なプラグインであれば書くことが出来ます。

例えばクリティカル威力を変更したり、アイテムの取得時にはそのIDをゲーム内変数に代入したり、TP再生を固定値ではなく割合にしたり。リザルト画面を消したり。
などなど。

その為にはまず、然るべき場所とはコアスクリプトの何処であるのかを見つける方法を身に着けなくてはいけません。


今回は例として、ステータス画面に表示されている職業名の場所に、
装備中の防具の名を参照するようにする。……ということをしてみます。

例えばその防具を称号として扱えば、付けている称号がステータス画面に表示される。
ということになりますよね? そんな感じです。

何処を修正したいのか探そう。

コアスクリプトは

rmmz_core
rmmz_managers
rmmz_objects
rmmz_scenes
rmmz_sprites
rmmz_windows

から構成されています。詳しい説明はもう他の方でしてる方も多いですし、
絶対そっち見たほうが良いので割愛します。

何処に入ってるかわからない?
そんなもん何となく分かるようになってくるまで、
全部開いてCTRL+Fで検索掛ければ良いんです。

料理だってそうでしょう?
レシピ見なくても作れたり味見しなくてもマトモな味が作れるようになるには、
それ相応に料理に触れていかねばならないし、
触れてるうちになんとなく分かってくるんです。
右も左もわからないうちは手間がかかる。それはしょうがない事なんですよ。


因みに自分はプラグイン触るときは未だに全部コアスクリプト開きっぱなしです。



今回はステータス画面で、職業の表示です。

まず、statusでコアスクリプト内を検索してみます。487件ヒットしました。
これじゃダメですね。一個一個見ていっても良いですが……。

では、次にclassで検索します。これは176件ヒットしました。だいぶマシですね。
慣れてくればステータス画面の表示だから、
このコアスクリプトの中かな……と絞ることが出来て、
この状態でも簡単に然るべき場所にたどり着けるのですが、
当時は自分もそれが出来なかったので、考え方を変えてみます。

ステータス画面。表記は他にもあります。
最終的に変えたいのは職業の表記ですが、近くには二つ名などもありますね。
処理が近しいものは、大体同じコアスクリプトの中にありますので、
次は二つ名で探してみましょう。

でも職業はクラス。ステータスはステータスでわかりましたが、二つ名とはどう探せばいいのか?

ここでは2つの方法を提示します。

一つ、トリアコンタンさんのMZの非公式スクリプトリファレンスをお借りします。
二つ名と検索することで、

$dataActors[id].nickname

と記述してあります。
二つ名に関するデータがnicknameであると気づければok。


もう一つは、テストプレイ中のコンソールログを使います。
コンソールログは、エラーが出てくる画面。

……だけではなく、下の入力欄に適正な記述を行うと、
ゲーム内のデータを見ることが出来ます。

コンソールログの使い方

テストプレイ中にF12を押すと出てきます。

こんなのですね。


とりあえずこれを開いて。

$gameActors.actor(アクターID).setNickname("変更する二つ名")

次に、こういう記述がどういう意味なのか紐解いておきましょう。
これも正直、自分は理解までに時間をかけました。

. ←は、そのデータ群の中の……或は命令という感じです。
何が情報群で何が命令なのか、分かってくるまで非常にわかりにくいです。
例えばですけど

$gameActors.actor(アクターID).setNickname("変更する二つ名")
↑これはこんなイメージ
植物.野菜(大根).品種名を変えなさい(”おろし”)

一行の中に、何処のデータで何をしろ。
というのが収まっているので理解がしにくかったんですよね。
ここから命令部分を切り落としてしまえば、そのデータを参照出来るものもあります。

カッコの中の数字は何番のIDの情報を見るか。という指定なので、

$gameActors.actor(1)

この記述で見てみましょう。
▶を押してみるとずらーっとデータの羅列が出てきます。

見ていくと、見覚えのある名前が出てくると思います。
自分の場合だと、アクターの名前である ブレン や、二つ名のEクラス冒険者ですね。

このデータを見れることはとても重要で、
ゲーム内情報を得るだけでなく、変更する際にも大きな足掛かりになります。

今回であればアクターの情報はもう見えています。
そして、中の値を書き換えてしまえば、それを変更出来るんですから。

例えばこのコンソールログに

$gameActors.actor(1)._paramPlus[3] =999
と打ち込めば、アクター1番の防御力に999に入れなさい。となります。


HPにも10万入れていたので、職業由来の値と合わせて
HP:10450
防御:1015
のチート使ったみたいなアルドくんが数十秒で完成です。
中の値を見れるということは、簡単に書き換えられるということ。
よって、中の値を発見する事こそ、大事であることをよく覚えておいてください。

ともあれ、$gameActors.actor()の中身を覗いてみたことで、
二つ名は _nickname に入っていることがわかりました。
とりあえず_は抜いて、nicknameでコアスクリプト内を検索をしてみましょう。

そうすると、14件しかヒットしません!
これなら絞り込めそうですね。

色々見ていくと、いかにも怪しげな

という記述が見つかります。名前、クラス、ニックネーム。
それと、window_Statusという名前。

そうです、ここはもう然るべき場所の一歩手前です。

this.はとても難しいのですが、
今回の場合は、現在の参照値と同じ名を持つフロアの。というような感じ。

ここで、本来変更したいのはクラスであることを考え、
drawActorClassでもう一度検索します。
すると、3件だけヒットしました。

Window_StatusBase.prototype.drawActorClass = function(actor, x, y, width) {

width = width || 168;
this.resetTextColor();
this.drawText(actor.currentClass().name, x, y, width);

};

そのうちの1件がこれ。
drawTextというのは、非常によく出てきます。
文章を表示している命令です。
これは、actor.currentClass().nameをx座標はxにy座標はyに幅widthで記述せよ。と言った感じ。


ここが目的地です。お疲れさまでした!
俺ももうかれこれ、3時間くらい記事書いてます。疲れてきました。

これをプラグインにする。以下をコピーして貼り付け

/*============================================================================
syokugyouhyouziwohenkousuru.js
---------------------------------------------------------------------------
(C)2020 あなた
This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
---------------------------------------------------------------------------
Version
1.0.0 2020/12/09 初版


[Blog] :
[Twitter]:
============================================================================/
/
:
@target MZ
@plugindesc 職業表示を変更する
@author あなた

*/

(() => {
//ここから必要な記述を行う
Window_StatusBase.prototype.drawActorClass = function(actor, x, y, width) {

width = width || 168;
this.resetTextColor();
this.drawText(actor.currentClass().name, x, y, width);

};
//ここまで必要な記述を行う
})();

↑ここまで

これに、適当な名前をつけて拡張子を.jsで保存します。
メモ帳の場合はUTF-8じゃないとダメだったかと思います。

自分も暫くメモ帳をつかっていましたが、エディタをオススメされまして。
実際、色分けされているとコードの意味がわかりやすいので、
そういった機能があるやつを使うほうが良いかと思います。

因みに自分はatomですが、他人にコードを見せる(相談する)
場合に自動整形するなりして、せめて見やすくするのは最低限度のマナーである。
……みたいな事を目にして、なるほどじゃあ自動整形機能があるのにしようと、
最初に目についたのがこれであったというだけで、その他に特に理由はありません。

諸先輩方がきっとおすすめを教えてくれることでしょう。



で、これを普段使っているプラグインと同様の場所に入れて、ゲーム内からいつもどおりに入れれば、あなたのプラグインが完成しました!

とはいえ、このプラグインは、
コアスクリプトを全く同じ記述でを上書きするだけのものです。
現実的には、競合を引き起こす可能性があるだけのプラグインということになります。


ここで競合についても少しお話します。
今回、プラグイン化にあたって、これ↓の中身を改変します。

Window_StatusBase.prototype.drawActorClass

プラグインはコアスクリプトに対して、上に置いてあるものから上書き保存をして、最終的に出来上がったものを、あなたのゲームで起動します(多分)

プラグインの競合というのは、この過程で、
同じものを複数の場所で上書きした時には必ず起こります。

クリティカル威力は本来の威力の100倍にせよ。

と、コアスクリプトに上書きをした後に、

クリティカル威力は本来の威力の1000倍にせよ。

という上書きをすれば、片方は機能しなくなりますよね。そういうことです。
これが、クリティカル計算の値を100倍する挙動を、本来の挙動にプラスせよ。
みたいな書き方になると、挙動の追加が積み重なり100000倍になったりしますがー。


とりあえず概要の話なのでここでは置いておきます。


さて、次にプラグイン化した方の記述を変えていきます。
これが職業を記述している項目です。

this.drawText(actor.currentClass().name, x, y, width);

では、これをどうしたいのかを考えます。

称号の装備がない時は、職業本来の名前を表示し、
称号があるときはそれを優先表示することにしました。

はい、どーん。 ……流石に疲れてきたので。

改変後

Window_StatusBase.prototype.drawActorClass = function(actor, x, y, width) {

width = width || 168;
this.resetTextColor();
if ($dataArmors[actor._equips[4]._itemId] == null) {
  this.drawText(actor.currentClass().name, x, y, width);
  return;
}
if (actor._equips[4]._itemId == 0) {
  this.drawText(actor.currentClass().name, x, y, width);
}else{
  this.drawText($dataArmors[actor._equips[4]._itemId].name, x, y, width);
}

};

ここまで

actor._equips[4] というのは、アクターの装備で5箇所目を意味します。
プラグインとかで変化していなければ、装備画面で上から5番目の位置です。

そこを参照します。
actor._equips[4].itemId
となると、装備画面で上から5箇所目の装備エリアのアイテムのIDとなります。
今回は5箇所目に防具を装備しているので、防具のIDを参照します。
プラグインで弄らない限りは0番が武器でそれ以外は防具ですが。

$dataArmors[].name

というのは、防具データ[]番の名前を参照する。ということです。
つまり、この2つを合わせて

$dataArmors[actor._equips[4]._itemId].name

こうなると、五箇所目に装備中の”何か”のIDと同じIDを持つ防具の名前を参照せよ。です。

this.drawText(,x,y,width)は少し難しいのですが、

そもそも、大本のこれ↓が呼び出された際、
Window_StatusBase.prototype.drawActorClass

actorとxとyとwidthの数値を受け取ってきています。


Window_Status.prototype.drawBlock1 = function() {

const y = this.block1Y();
this.drawActorName(this._actor, 6, y, 168);
this.drawActorClass(this._actor, 192, y, 168);
this.drawActorNickname(this._actor, 432, y, 270);

};

この中にある、

this.drawActorClass(this._actor, 192, y, 168);

呼び出し元のこの記述ですね。
this._actorはこの場面では、ステータス画面で選択中のアクターを指します。
xは192と指定され、yはblock1Yというところから取ってきたモノを、更に渡しています。

因みにblock1Yを追いかけると、

Window_Status.prototype.block1Y = function() {

return 0;

};
となっています。returnというのは、これが呼び出された時には右の値を返せと言うことなので、0を返します。

つまり、block1Yは0です。block1YをYという名前に変えて、
値はそのままに現在プラグインで作成中の、
Window_StatusBase.prototype.drawActorClass に持ってきたということですね。


Window_StatusBase.prototype.drawActorClassの中で
先程説明した actor._equips[4] ですが、アクターの番号の指定がないのにも関わらず、それがID何番のアクターであるかの情報を持っていたのは、直前に受け渡されている

this.actor が何番のアクターであるかの情報をもっていて、それをactorという名前で受け取ってきているからですね。


……俺のこんな説明でわかるでしょうか?
同じ actor に見えるのにある場所ではカッコが付いて番号指定があったり、
ある場所では直接参照しているように見えたり、理解がし辛いと思いますが、

その文字列に拘って見るのではなく、それに入っている情報が
何処からきた情報であるかを追っていかないとダメ。ということですね。

ここでお役立ち情報。

これなんの情報持ってんだよって思ったときには

console.log();

をスクリプトの間に記述してみましょう。


Window_StatusBase.prototype.drawActorClass = function(actor, x, y, width) {

width = width || 168;
this.resetTextColor();
this.drawText(actor.currentClass().name, x, y, width);

};


例えば今回の大本。改変前のこれで言えば、actorとかthisなんかはわかりにくいですよね。こんなときは


Window_StatusBase.prototype.drawActorClass = function(actor, x, y, width) {

width = width || 168;
console.log(this);
console.log(actor);
this.resetTextColor();
this.drawText(actor.currentClass().name, x, y, width);

};

のように、記述することで、thisとactorが持っている情報をコンソールログに出力せよ。という命令になります。この状態でテストプレイを開始し、F12でコンソールログを開けば、該当した場所が呼び出された時に、このスクリプト内の何行目の出力結果がこれ!

今回であればステータス画面を開いたりすると、コンソールログが出力されると思います。このように console.log(); は値の特定に極めて役立ちます。

困ったら console.log(); です。
勿論、カッコ内に何を出力させるかの指定を忘れずに。


こんなものでしょうか。
……プラグインを書いたりしていたら7時間もかかってしまいました。

今回書いたのはステータス画面用に。ではあるのですが、

Window_StatusBase.prototype.drawActorClass

は機能が最小限で、とても汎用的なモノなので、
ステータス表示の一環として、スキル欄での職業表示でも呼び出されているようです。
なので、特に何もせずともステータス画面と同様に防具名になったりします。

その他のプラグイン独自のシーンに呼び出されているケースもありますし、
その場合でも、

Window_StatusBase.prototype.drawActorClass
を呼び出しているのなら同様に特に何もせずとも変更されます。


さ、これで自分の記事も終了です。


誰かのお役に立てば幸いです。
そして、間違いの多い記事だったら大変申し訳ありません。


最後に、完成後にもう少し使いやすくした状態のプラグインです。
職業名か二つ名の表示欄に武具の名前を表示させるプラグインは
スクリプト内に注釈を書きまくりました。何かの役に立てば幸いです。


そして、以前Twitterでひっそり公開したプラグインの再掲示もしておきます。

職業名か二つ名の表示欄に武具の名前を表示させるプラグイン

https://drive.google.com/file/d/11fgMnFm9sEArMJyab8Q8A9gz_0QPHbJ7/view?usp=sharing

TPBにおいてスキル後にゲージが溜まっているスキルや装備がつくれるプラグイン

https://drive.google.com/file/d/1BOsEBFdsESVJSZzfIkEH3EKfhLvQb5DZ/view?usp=sharing

TPBにおいて、キャストタイムを軽減するスキルや装備が作れるプラグイン

https://drive.google.com/file/d/18nIe1hp1vEi0dwexfFu_S0Ag52EFIdcL/view?usp=sharing

ニル 2020/06/22 10:39

スキル計算式とプラグインの話

スキルのダメージ計算に自作関数を

これ自体はより詳しい先人もいらっしゃいますが、
当時自分で何処がよくわからなかった事を思い出して、記事を書いてみます。

スクリプトはまだまだなので、
どこか間違ってたら申し訳ないけど、多分あってる、多分。

うるせえ!サンプルだけよこせ!
って人は一番最後にプラグインが置いてあるんでそちらにどうぞ~


Ci-enのブログ、なんか米印が潰されてしまうので × にしてあります。

作ろうとするスキル

デフォルト
a.atk × 4 - b.def × 2

つくるやつ
(a.atk - b.def × 0.5) × スキル威力

これをベースとします。ツクールのデフォ計算式に近いですね。
スキル威力が1だと、それを丁度4分の1した値となります。
スキル威力4で、デフォの通常攻撃と同じ威力ですね。

0.5の値は相手の防御力影響を決める数値ですね。
ここも例えば貫通率が高いスキル……みたいに変動させたいので、

(a.atk - b.def × 貫通率) × スキル威力

といった感じにします。
これが全ての基礎になる計算式ですね。




次に、運の値を持ってきます。ちょっと複雑なので順を追います。

① 0~自分の運の数値までをランダムで抽選

② 0~相手の運の数値までをランダムで抽選

③ ① - ②

例をあげますかね。
ハロルド君の運は999。スライムの運が10だとします。
この場合、0~999の中で抽選された数値 - 0~10の中で抽選された数値

つまり、答え(ダメージ)は -10 ~ 999 という事になります。

自分の運が高ければ高い程、高いダメージが出やすく、最大値も高い。
但し、相手の運が高ければ高い程ダメージを抑えられる確率も高い。

…という感じですね。式にするとこんな感じになります。

a.luk = Math.floor( Math.random() × (a.luk + 1))
b.luk = Math.floor( Math.random() × (b.luk + 1))

damage = (a.luk - b.luk) × level

このままじゃスキルの計算式には入りませんけどね。
もっと簡潔に書けるかもしれないけど俺は分かりません!



この、基礎となるといった
自分の攻撃・相手の防御から算出するダメージと、
自分の運・相手の運から算出するダメージのを比較し、高い方を取る。
……というのが、今回のサンプル計算式となります。


実際の設定

計算式には

Luk_atk(a, b, 0.5, 1)

という値が入っています。


そして、プラグインファイルには、18行目から

function luk_atk(a, b, perforate, level){

から続く関数が入っています。
ちょっと文字の色に注目して見てくださいね。


luk_atk(a, b, 0.5, 1) ← スキル計算式

function luk_atk(a, b, perforate, level){ ← プラグインの中身の関数


これはスキルで記述した名前(緑の文字)をプラグインから引っ張っています。
そして、()内の青文字は , で区切られて4つの数値が入っています。

スキル計算式の方は
(a, b, 0.5, 1)

プラグインの方は
(a, b, perforate, level)

1~2番目の数値

a と b は、デフォルトの計算式でも用いられている、a.atk や b.def に用いられる情報で、主体と対象の情報です。デフォルトであれば

主体の攻撃 - 対象の防御

というような形になっているわけですね。
今回は a と b という情報だけをプラグインに渡しています。

つまり、HPやら会心率やら、属性有効度やら。

原理とか仕組みとか正直あまり詳しくはわかりませんが、
主体情報・対象情報のデータベースを開く鍵を渡しているようなものです(多分)

3番目の数値

0.5 と  perforate は、貫通率です。
別に元々そういう機能が用意されている、とかいうわけではなく、

スキル計算式の方から、3番目に送った数値が0.5というだけです。
そして、プラグインの方ではその3番目の数値に俺が勝手に
perforate という名前を付けて、貫通率として計算しているだけですね。

4番目の数値

1 と level ですね。

これはスキル威力になっています。
4であればデフォルトの通常攻撃と同じになります。
これも3番目の数値と同様に、俺が勝手に名前をつけただけです。
プレイヤーレベルとちょっと混同しやすいかもしれませんけど。


計算に必要な値の説明や記述

少しわかって来たでしょうか?


スキル計算式の方は
(a, b, 0.5, 1)

luk_atk という関数を参照せよ。その際、4つの情報を持っていけ。

( a = 主体情報, b = 対象情報, 0.5 = 貫通率, 1 = スキル威力)

という感じですね。



そして、プラグインの方は
(a, b, perforate, level)

受け取った4つの値にそれぞれ、
(a,b,perforate, level)という名前を付けて、計算をしていくことになります。



function luk_atk(a, b, perforate, level){
↑ここまで説明が終わりました

{ ← は、これを使って計算するスペースはここからだぜ!ってことですね。
その計算が↓から始まります。

var a_atk = a.atk;
var a_luk = a.luk;


var ← これは変数を作れってこと
var a_atk ← これで、a_atk という名前の変数を作れ
var a_atk = a.atk; ←これでa_atk という名前の変数を作れ。中身はa.atk だ。になります。

元の値を弄ってしまうのは良くないので、a_atkという名のコピーを作っている感じです。これも、名前に関しては俺が勝手に決めています。

仮に var で作った名前が、sasaki であろうと suzuki であろうと中の値に影響はありません。

でも、佐々木や鈴木の中に攻撃力とか運が入ってたら後で見返した時に訳わからんでしょ? っていうだけです。

こうしてコピーを増やした理由は、
例えばダメージ計算の為だけにキャラの攻撃力自体が増えたらバグの温床になってしまうからですね。

今回はa.atk と a.luk の情報が必要なので、それを呼び出し、コピーしています。
以下の記述も概ね同じですね。対象の防御と運をコピーしています。

var b_def = b.def;
var b_luk = b.luk;

最後のこれは、最終的にスキルの方に計算結果であるダメージを返すのですが、
攻撃力側の算出と運側算出を比較するために、こうして先に変数を用意している感じですね。

var damage = 0;
var damage2 = 0;


さて、↓まで説明が終わりました。これでもう半分ですよ!

function luk_atk(a, b, perforate, level){ //スキル計算式から受け取った4つの値を持つ
 var a_atk = a.atk; //a_atk という変数を用意し、a.atkの値を代入
 var a_luk = a.luk; //a_luk という変数を用意し、a.lukの値を代入

 var b_def = b.def; //b_def という変数を用意し、b.defの値を代入
 var b_luk = b.luk; //b_luk という変数を用意し、b.lukの値を代入

 var damage = 0; //damege という変数を用意しておく。中身は0
 var damage2 = 0; //damege2 という変数を用意しておく。中身は0


では続きを行きましょう。

攻撃と防御の計算式

damage = (a_atk - b_def × perforate) × level;

もう何を書いてあるかそろそろわかりますかね?

damage ←さっき作った。中身は0の変数
a_atk ←さっき作った。中身はa.atk つまり主体の攻撃力
a_def ←さっき作った。中身はb.def つまり対象の防御力

perforate ←スキル計算式から受け取った3つめの値。受け取った時点で名前を付けた。中身は 0.5

level ←スキル計算式から受け取った4つめの値。受け取った時点で名前を付けた。中身は 1


damage = (a_atk - b_def × perforate) × level;

damage =(主体攻撃力 - 対象防御力 × 貫通率)× スキル威力
ってことが書いてあるってわけですね。

一番最初にかいた、攻撃と防御からなる基礎計算式はこれで終わりってことです。

運を扱う計算式

では、運を扱う二つ目の計算結果を出しましょう。


var luk1 = Math.floor( Math.random() × (a_luk + 1));

新しく luk1 という変数を作り、その中には
0~主体の運までの乱数値を代入する。

var luk2 = Math.floor( Math.random() × (b_luk + 1));

新しく luk2 という変数を作り、その中には
0~対象の運までの乱数値を代入する。


damage2 = (luk1 - luk2) × level;

damage2 =(0~主体の運までの乱数値 - 0~対象の運までの乱数値) × スキル威力
ってことが書いてあります。

これで二つ目の計算結果も出ましたね。

比較して値を返す

もう終わりですよ!

return Math.max(damage, damage2);

値を返しなさい。大きい方です。(damage,damage2)
と書いてあります。ここまでで、damage には物理部分の算出。
damage2には運部分の算出が出来ているので、それで大きかった方を返します。


}
↑これは呼び出した関数はここまでですよというやつ。これを書いたら、
やっとスキル計算式に戻ります。


これで全部終わりです。最後におさらい。


function luk_atk(a, b, perforate, level){ //スキル計算式から受け取った4つの値を持つ
 var a_atk = a.atk; //a_atk という変数を用意し、a.atkの値を代入
 var a_luk = a.luk; //a_luk という変数を用意し、a.lukの値を代入

 var b_def = b.def; //b_def という変数を用意し、b.defの値を代入
 var b_luk = b.luk; //b_luk という変数を用意し、b.lukの値を代入

 var damage = 0; //damege という変数を用意しておく。中身は0
 var damage2 = 0; //damege2 という変数を用意しておく。中身は0

damage = (a_atk - b_def * perforate) × level; //物理部分の計算式

var luk1 = Math.floor( Math.random() × (a_luk + 1));//新しく luk1 という変数を作り、その中には0~主体の運までの乱数値を代入する。

var luk2 = Math.floor( Math.random() × (b_luk + 1));//新しく luk2 という変数を作り、その中には0~対象の運までの乱数値を代入する。

damage2 = (luk1 - luk2) * level;////運部分の計算式

return Math.max(damage, damage2); //damage, damage2の大きい値を返す

} // luk_atk という関数はここまで。




最後にそのままそっくり置いておきます

https://drive.google.com/file/d/1_4O3YNXNEcHPgvZx-XMlXucj95pg8uyx/view?usp=sharing

サンプルとして説明していたのを加えて、ぱぱっと7つだけ式が入っています。

貫通率が決められる物理攻撃
貫通率が決められる魔法攻撃

運・物理参照攻撃(サンプルと一緒)
運・魔力参照攻撃
運・敏捷参照攻撃

攻撃・魔力参照攻撃(複合ではなく、それぞれ参照しダメージの高い方を取る)
攻撃・敏捷参照攻撃(複合ではなく、それぞれ参照しダメージの高い方を取る)


何かのお役に立てば幸いです。


ちょこっと追記

複合ダメージはどうやりたいかで色々変わってきますが、
記述的にはそう難しいものでもありません。

atk_mat2(a, b, 0.5, 10 , 5)

スキルの方はこんな感じで設定。
貫通率50% 物理部分の威力が10 魔法部分の威力が5です。
仮に物理部分と魔法部分の貫通率も変えたいならさらに値を増やす必要がありますね。


function atk_mat2(a, b, perforate, atk_level, mat_level){

 var a_atk = a.atk;
 var a_mat = a.mat;

 var b_def = b.def;
 var b_mdf = b.mdf;

 var damage = 0;
 var damage2 = 0;

 damage = ((a_atk  -  b_def * perforate) * atk_level) + ((a_mat  -  b_mdf * perforate) * mat_level);

return damage;
} 

レベルをatk_levelとmat_levelという2つパラメータに変更。
物理によるダメージと魔法によるダメージをそれぞれ算出し、最後に加算します。

物理威力が5
魔法威力が2

とか色々変える事が出来ます。
一応、これもテンプレに入れておきます。

ニル 2020/05/29 21:39

YEP_Element CoreとBattleKnowledgeについて

ちょっと趣向を変えてプラグインのお話

俺はYanflyさんのプラグインを割と愛用しているのですが、
プラグインの記述が難解であることから、代替手段が有るときは、
日本の作者さんのプラグインを用いることが多いです。

本題

今回はそんな中で、
YanflyさんのYEP_ElementCoreと、
やなさんのBattleKnowledgeのお話になります。

前提として、何方も素晴らしいプラグインである。
と言わせていただいた上で、話を進めていきましょう。

元々俺は、やなさんのBattleKnowledgeを使わせていただいていたので、
YEP_ElementCoreは導入していなかったのですが、

1ヶ月前とかですかね。
スキルにいつものように〇〇の知識を入れていたらあることに気づいたんですよ。

結論から言いますね。

BattleKnowledgeでは、該当属性を含む場合、
算出されるダメージはデフォルトのダメージ計算で出される値に、
それぞれの知識の合計倍率を乗算した数値である。ということです。

前提としてMVで複数属性をもつ場合、
ダメージ計算時に最も高い属性が選ばれます。


その上で例えましょう。
デフォルトの話からしていきますね。

スキル 100ダメージ 属性/通常攻撃 分散0
炎の剣 武器 属性/物理・炎
敵A 炎有効度200%

この状態で100ダメージ固定ダメージで、
通常攻撃属性のスキルを用いるとどうなるか。

通常攻撃属性は、武器の持つ属性とステートで付与された属性等、
全てを適用する属性です。

この場合、ステートは無し。
武器で物理と炎属性を持つので、2属性で計算されます。

物理 100 × 100% =100
炎  100 × 200% =200

結果、炎有効度の差により、敵へのダメージは炎属性が選ばれました。
ここまでがデフォルトです。

では、この状態でやなさんの
<炎の知識> を使ってみましょう。

スキル 100ダメージ 属性/通常攻撃 分散0
炎の剣 武器 属性/物理・炎 <炎の知識 50%>
敵A 炎有効度200%
敵B 炎有効度0%

敵A 300ダメージ
炎  100 × 200% ×150%=300

はい、計算通りですね。知識の50%が威力に加算されるのでこうなります。
では・・・Bは?

敵B 150ダメージ
となります。炎が効かないが、炎の知識のダメージが加算されている。

物理 100 × 100% ×150%=150

もう一度最初に書いた事を貼りますね。
BattleKnowledgeでは、該当属性を含む場合、
算出されるダメージはデフォルトのダメージ計算で出される値に、
それぞれの知識の合計倍率を乗算した数値である。ということです。

つまり、例えば
炎の知識+50
氷の知識+50
雷の知識+50
で、炎・氷・雷の属性を持った武器を持っていた場合、
通常攻撃は、3属性を持つのでそれぞれが加算され、250%の威力。
純粋な炎魔法、属性が炎しか無いので、50%足されて150%の威力。

となる訳ですね。

それが良い悪いではない。と改めて言っておきましょう。
この辺りは、やなさんの意向とプラグイン利用者、
今回で言えば俺の意向がマッチするかというだけの話です。
プラグインを作ってくださることは本当にありがたいことですから。
例え希望と違っても素材作成者さんへの感謝の心は忘れてはいけませんね。


某所見てるとそういうの欠如してるように見える人そこそこいるんですよね。

不必要に謙る必要は無いですが、与えられて当たり前。
やってくれて当たり前みたいな態度の人への対応なんて、
最低レベルになって当然だと思うんですけどね。
そんな相手にも丁寧に対応している方も見られて、
ホント優しいなぁって思ってはいるんですけど。



話がズレましたね。

さて、俺の目的の挙動は、
それぞれの属性のダメージ参照時に50%増やされた状態で比較
してほしいと言うものでした。
条件的には・・・
スキル 100ダメージ 属性/通常攻撃 分散0
炎の剣 武器 属性/物理・炎
<Element Amplify 物理: +50%>
<Element Amplify 炎: +50%>

敵A 炎有効度0%/物理有効度100%

BattleKnowledgeでは、
物理属性が選ばれ、物理と炎それぞれの知識50%が適用され、
最終計算に威力を100%加算。
合計200ダメージが算出されます。

複数属性ルールを 3 ’最高’ (ツクールデフォルトの属性式)にした、
YEP_ElementCoreでは、
物理属性が選ばれ、150ダメージが算出されます。

最初から目的の挙動でしたね!
これで、目的のものが作れます!

目的のアイテム

武器強化で、微弱な炎を付与する。というのがしたかったんですよね。
例えば、敵の属性で
物理  有効度 10%
炎   有効度 200%
付与炎 有効度 200%

というように設定をしておいて、

通常の魔術や攻撃に影響を与えずに、
武器エンチャントの場合だけ参照される属性が欲しかったんですよ。

この状態で武器に
攻撃属性”付与炎”と付与炎の倍率50%というように
エレメンタルコアで設定してやれば、
攻撃時に”付与炎”属性が参照され、
微弱な炎エンチャントでも100%のダメージを与えられますよね。
魔術は変わらず200%です。

イメージ的には、序盤のエンチャントアイテムは弱い感じで。
後半になってくると普通に高い参照値になっていくみたいなね。

終わり

・・・というわけで、特に何もせずに俺の理想の動きをしていた
YEP_ElementCoreに嬉しくなったのでちょっとした宣伝と、

プラグインの中でもかなり人気と思われる
BattleKnowledgですが、ちゃんと想定の動きをしてますか?
というような話でした。

記事のタグから探す

月別アーカイブ

限定特典から探す

記事を検索