スキルのダメージ計算に自作関数を
これ自体はより詳しい先人もいらっしゃいますが、
当時自分で何処がよくわからなかった事を思い出して、記事を書いてみます。
スクリプトはまだまだなので、
どこか間違ってたら申し訳ないけど、多分あってる、多分。
うるせえ!サンプルだけよこせ!
って人は一番最後にプラグインが置いてあるんでそちらにどうぞ~
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
とか色々変える事が出来ます。
一応、これもテンプレに入れておきます。