解決済み:被らないランダム変数

返信する
アバター
榎木なめこ
記事: 5
登録日時: 2016年7月03日(日) 17:11

解決済み:被らないランダム変数

投稿記事 by 榎木なめこ »

初めてこちらを使わせて頂くので、なにか不備などありましたらご教授ください。

0~nの乱数を生成して、
前回選択したコマンドと、今回選択したコマンドが同じ場合、
その生成した乱数が、前回の生成した乱数と同じ場合、生成をやり直す。
というのをスクリプトの練習を兼ねて、できるだけグローバル変数を汚さずにやろうとしたのですが、
イマイチスマートにできていない気がします。

var wordsAlt = (function(){
var beforerand;
var beforeCommandId = 0;
return function(randMax,box){
randMax++;
var rand = Math.floor(Math.random() * randMax);
if(beforeCommandId == $gameVariables.value(11)){
for( ; rand == beforerand ; rand = Math.floor(Math.random() * randMax));
}
beforerand = rand;
beforeCommandId = $gameVariables.value(11);
$gameVariables.setValue(box,rand);
}
})();

初めはコモンイベントで実現してしまおうと思ったのですが、コモンイベントでは引数が設定できず、
乱数の最大値が設定できなかった(コモンイベントの前に変数を弄るというのも考えた)為、
こういった感じになってしまいました。

個人的には引数であるboxの部分を設定せずに、
ツクールの変数操作でスクリプトコマンドwordsAlt();で代入できたらよかったのですが、
どうやらこの書き方だと正常に動作しないようで、常に0が代入されてしまいました。

スクリプトを介さずとも出来るだろ!とか、
こうするともっと綺麗になる。とかありましたら、ご教授いただけたらと思います。
よろしくお願いいたします。
最後に編集したユーザー 榎木なめこ [ 2016年7月04日(月) 06:23 ], 累計 1 回
アバター
yamachan
記事: 107
登録日時: 2016年6月19日(日) 22:34

Re: 被らないランダム変数

投稿記事 by yamachan »

こんばんは! :D

「コマンド(数値)ごとに前回生成したランダム値を覚えておき、同じ値を返さないランダム値生成関数」
を求められている、で正しいでしょうか?

であれば、ちょっと修正してみた結果が以下になります。

コード: 全て選択

var wordsAlt = function(randMax, commandId){
  var data = $gameSystem._wordsAlt = $gameSystem._wordsAlt || [];
  commandId = commandId || 0; // 第2引数を省略できる
  randMax++;
  var beforeRand = data[commandId] || -1;

  var rand = Math.floor(Math.random() * randMax);
  for( ; rand == beforeRand ; rand = Math.floor(Math.random() * randMax));
  return data[commandId] = rand;
};
たぶん元のコードはセーブに対応するために変数を利用していると思うのですが、JavaScript でコードを書く場合には $gameSystem オブジェクトに独自の値を保存しておけます。
今回は "_wordsAlt" という属性名を使いましたが、他のプラグインなどと名前が被らないように注意が必要です。

最後、単に値を return で返していますので、変数設定のスクリプトの欄にそのまま利用できるはず、です。
スクリプトコマンドで起動して、ゲーム変数に設定する場合には $gameVariables.setValue() などに変更してみてください。

以上、参考になれば幸いです。
なにか勘違いしてたらスミマセン。

ではでは。
Toshio Yamashita (yamachan)
Plugin https://github.com/yamachan/jgss-hack/b ... ADME.ja.md
Twitter https://twitter.com/yamachan360

私が作成して本サイトに投稿したコードは著作権を放棄し、利用・改変・配布など全て自由です。
ただし同じ投降内に制限を明記している場合はそちらが優先します。
アバター
榎木なめこ
記事: 5
登録日時: 2016年7月03日(日) 17:11

Re: 被らないランダム変数

投稿記事 by 榎木なめこ »

早い返信ありがとうございます。とても助かりました。
javascriptを勉強し始めてから、まだ日が浅いもので、ご迷惑をお掛けします。

変数に = || で代入する方法は初めて見たのですが、選択的代入というんですかね?
どうやら左がない場合、右のものを代入する。みたいな感じだということがふわっとわかったような、わからないような。

そういえば$gameSystemなどにオブジェクトとして保管しておく方法もありましたね。
完全に失念していました。

いくつか疑問点が出てきたので、それもご教授頂ければ幸いです。

まず、2行目の
var data = $gameSystem._wordsAlt = $gameSystem._wordsAlt || [];
は、何故2度wordsAltを挟んでいるのでしょうか?


つぎに、
(function(){})();
で全体を囲った場合は同じような処理をする方法などはあるのでしょうか?
曖昧な見解なのですが、私の適当な認識ですと、これはグローバル領域を侵さない為のものだと認識しています。
プラグインなどは競合の関係で、できればこれで囲ったほうがいいと思うのですが、
書いて頂いたコードを囲った場合、エラーを吐いて正常に機能しなくなりました。
$gameSystemにオブジェクトを用意する方法も、競合が発生しないことはないと思うのですが、
そういった競合による不具合を全て回避したうえで、同じことができるものなのでしょうか?
ここちょっとわかりにくくてすみません。


次に、
var wordsAlt = function(){};
の場合と、
function wordsAlt(){}
の場合だと、一体何が違うのでしょうか?
どちらも結局グローバル領域を1つ侵しているので変わらないのでは?と思っているのですが、
なにか違いがあるのでしょうか?
アバター
yamachan
記事: 107
登録日時: 2016年6月19日(日) 22:34

Re: 被らないランダム変数

投稿記事 by yamachan »

こんばんは! :D

JS(JavaScript) 自体の話になりますが、簡単にコメントしますね。

まず commandId = commandId || 0; はJS ではよく使いますね。

コード: 全て選択

if (commandId == undefined) {
  commandId = 0;
}
とほぼ同等で、略した書き方です。
2行目も同じで、これは以下を略して書いたものです。

コード: 全て選択

if ($gameSystem._wordsAlt == undefined) {
  $gameSystem._wordsAlt = [];
}
var data = $gameSystem._wordsAlt;
コードを最初に実行したときには $gameSystem._wordsAlt が存在しませんから、[] で初期化しているわけです。
二度目以降、そしてセーブファイルからロードした後には $gameSystem._wordsAlt が存在しますので、この初期化は実施されません。

全体を (function(){})(); で囲うのは、プラグイン作成でよく推奨されている方法です。
言われるように、その中で定義したものがグローバル環境を汚さないので、よく使われます。
でも今回は関数を1つ定義しているだけなので、そこまでの配慮は不要だとおもいます。
といいますか逆に、今回は、囲ってしまうと、その1つの関数の定義が「グローバル環境を汚さない」ので、せっかく定義した関数が使えなくなってエラーが発生します。

皆に使ってもらう関数名などは、どうしてもグローバルで見える必要があり、他のプラグインとの競合の可能性があります。
例えば私は作成したプラグインには "RTK_" で始まる名前を付けていて、こういったグローバルに影響するものの名前にはプラグインの名前を反映させています。
競合を完全に防止できるわけではありませんが、まあ、すごく似た名前のプラグインがあったら気が付いてもらえると信じています :D

最後に var wordsAlt = function(){}; と function wordsAlt(){} は結果として同じですよ。
唯一の違いは、前者が後で代入することで中身を書き換えられる(後者は関数を定義しているのに対し、前者は変数に関数定義を代入しているので)ことですが、今回のケースでは関係ないとおもいます。

以上、ざっとしか返答できなくてすみません。
ただ JavaScript に関しては検索すると山ほど情報がでてきますので、いろいろ検索してみるのをお勧めします。

またこのサイトには凄い人たちがおられますので、その方々の作成したのプラグインをみつけて、読んでみるのもお勧めします。 単機能で短いものが理解には良いです。
私も MV を購入してまだ1ケ月ちょいなので、いろいろ学ばせていただいている最中です :D

お互い頑張りましょう。ではでは。
Toshio Yamashita (yamachan)
Plugin https://github.com/yamachan/jgss-hack/b ... ADME.ja.md
Twitter https://twitter.com/yamachan360

私が作成して本サイトに投稿したコードは著作権を放棄し、利用・改変・配布など全て自由です。
ただし同じ投降内に制限を明記している場合はそちらが優先します。
アバター
榎木なめこ
記事: 5
登録日時: 2016年7月03日(日) 17:11

Re: 被らないランダム変数

投稿記事 by 榎木なめこ »

お返事ありがとうございます!

まさかここまで丁寧に教えていただけるとは…。
本当にありがとうございます。

2行目の書き方の謎が解けました。ありがとうございます。
commandIdでやってることを、更に別の変数に代入してるよ。みたいなことだったんですね。


やっぱりグローバル領域を侵さないと、外部から呼び出してこれなくなってくるんですね。
質問してばかりで申し訳ないのですが、例えば(function(){})();で全体を囲って、プラグインコマンドで一時的に中の式を使う。ということは出来たりするのでしょうか?
もし出来るのであれば、今回の被らない乱数ですと、プラグインコマンド名 最大値 代入変数番号 コマンド番号 みたいな引数を持ったプラグインコマンドを使う感じでしょうか?


最後に、変数に代入しているか関数として用意するかの違いについてもありがとうございます。
具体的にはどういう状況で使うのかまでは僕の頭では理解に及ばなかったですが、
多分その時がきたらわかるんだと信じています。 …多分。
アバター
yamachan
記事: 107
登録日時: 2016年6月19日(日) 22:34

Re: 被らないランダム変数

投稿記事 by yamachan »

こんばんは! :D

グローバル領域/変数ですが、そんなに気にすることもないと思いますよ。
_item とかベタな名前はともかく、ある程度ちゃんとした名前をつければ、そんなには被らない… とおもいます。

ちなみに私は慎重なほうなので、最初のトコで、グローバル領域で使う名前を定義しておいたりします。
万が一、プラグインが競合したときは、そこだけ修正すれば問題なく動くように。。

> 例えば(function(){})();で全体を囲って、プラグインコマンドで一時的に中の式を使う。ということは出来たりするのでしょうか?

はい、できます。

全体を囲ってしまうと、関数名まで外から見えなくなる、ってことでしたね。
しかし同じ囲みの中では関数名は使えるため、同じ囲みの中にプラグインコマンドの定義をかけば大丈夫です。

> 今回の被らない乱数ですと、プラグインコマンド名 最大値 代入変数番号 コマンド番号 みたいな引数を持ったプラグインコマンドを使う感じでしょうか?

はい、前回ご紹介した関数を囲みに入れ、プラグインコマンドの定義を追加すれば作れるとおもいます。
実装例をご紹介もできますが、まずはトライ!されてみては如何でしょうか :D
Toshio Yamashita (yamachan)
Plugin https://github.com/yamachan/jgss-hack/b ... ADME.ja.md
Twitter https://twitter.com/yamachan360

私が作成して本サイトに投稿したコードは著作権を放棄し、利用・改変・配布など全て自由です。
ただし同じ投降内に制限を明記している場合はそちらが優先します。
アバター
榎木なめこ
記事: 5
登録日時: 2016年7月03日(日) 17:11

Re: 被らないランダム変数

投稿記事 by 榎木なめこ »

なるほど。色々と教えていただき、ありがとうございました。

今回のものはプラグインとして公開するつもりもないですし、取るに足らないものなので実験はしませんが、
いずれプラグインコマンドについては、挑戦してみようと思います。

本当にありがとうございました。
返信する

“MV:質問”に戻る