#author("2023-03-13T04:19:11-04:00","default:fear","fear") #author("2023-03-13T04:21:56-04:00","default:fear","fear") [[XS入門]]の続き記事。~ 先にそっちを読むことを推奨する。~ この記事の目標は以下の通り。~ ''資源が変更できる''~ ''変数や定数の定義ができるようになる''~ ''簡単な条件分岐ができるようになる''~ -''資源が変更できる''~ -''変数や定数の定義ができるようになる''~ -''簡単な条件分岐ができるようになる''~ #Contents *資源を変更 [#bcd811d2] まずは、前回できるようになったであろう、「属性を変更」を、資源を変更についてもやる方法。~ (資源を変更って何ですかって人は、→[[資源]])~ これは、xsEffectAmountの第一引数に、「cModResource」を記載することで実行できる。~ ↓イメージ~ xsEffectAmount(cModResource, resourceID, operation, value, playernumber); 例えば、プレイヤー3が、交易時に交易量の金の50%分の食料を確保できるようにするためには、以下のように記載する。~ xsEffectAmount(cModResource, cAttributeTradeFoodPercent, cAttributeSet, 50, 3); 復習になるが、全プレイヤーに同様の設定をしたい場合は、最後の数字(第五引数)は省略可能。~ xsEffectAmount(cModResource, cAttributeTradeFoodPercent, cAttributeSet, 50); それでは、順に説明していく。~ ~ まず、最初の「cModResource」は固定なので、これは資源を変更したいときに、何も考えずに記載すればよい。~ 次のresourceIDには、変更したい資源について記載する。~ 例えば、聖なる箱が生み出す金の量を調整したければ「cAttributeRelicRate」、聖職者が転向させたあとの信仰力を回復させる速度を変更したければ「cAttributeFaithRechargeRate」といった具合である。~ これについては例のごとく英語サイト「AoE2DE UGC Guide」からざっくり内容を持ってきたページを作成したので、上記[[資源]]のページと一緒に参考にされたし→[[resourceID]]~ 第三引数のoperationは、いわゆる「設定する」「足す」といった指令を記載する。~ ここは下記の二パターンだけ覚えればよい。~ -「''設定する''」:''cAttributeSet'' -「''足す''」:''cAttributeAdd'' 第四引数の「value」は、効果量を指定する。~ 引き算にしたい場合は、cAttributeAddを使用した上で、「-100」などの形で値を指定すればいい。~ ~ 注意点としては、元々の「資源を変更」自体、マスクデータや内部データ的なものをいじっている要素が強いので、何をどう変更したらどうなるのかが少々分かりづらいということ。~ ちなみに、未使用のものもいっぱいある。今後のアプデで拡張性を持たせるためか。~ 大変申し訳ないが、本wikiの[[資源]]ページも、まだあまり充実していない。~ この値をいじってみたらこうなった!というのが分かったら教えていただきたい。~ *パラメーターの定義 [#h4625df4] 次に、ちょっとプログラミング的だけど、使えると便利な話。~ [[attributeID]]の定数の話でもしたが、xsEffectAmountなどの引数に数字を直接入力すると、valueなどの値を除いて、後から何のことだか分からなくなることが多い。~ 例えば、以下のようなコードを書いたとする。~ xsEffectAmount(cMulAttribute, 236, cAttackReloadTime, 0.8, 7); さて、第二引数の236とは何の事だろうか?~ ほとんど休みなくXSを弄っている人からすれば分かるかもしれないが、~ 「さて、一週間ぶりにxsいじってみるか!」みたいな人からすれば、236って何の事だろう?となる可能性が高い。~ ちなみに正解は、「砲台」である。~ しかし、以下のように記述した場合はどうだろうか。~ const int BombardTower = 236; xsEffectAmount(cMulAttribute, BombardTower, cAttackReloadTime, 0.8, 7); これなら砲台のリロード速度をいじったんだな、ということが割合分かりやすいはずである。~ それでは、このようなパラメーターについて説明していく。~ まずは最初のconstではなく、次のintから。~ これはデータの「型」を示す。使いそうなものは以下の通り。完全に正しい説明ではなく、ざっくりと伝えさせてもらう。~ -''string'':''テキストデータなど'' -''int'':''整数'' -''float'':''小数点を含む数'' -''bool'':''真か偽'' 例えば、string型は、メッセージの表示、int型はユニット番号、float型は攻撃速度などに使われている。~ bool型についてはおいおい。~ 次に、BombardTowerの部分。~ ここは実は自分が分かりやすい名前をつければよい。~ ぶっちゃけ、int Pokemonだろうが、int fearだろうがなんだっていい。~ 半角スペースは使えない。半角英数(大文字可能)で命名しよう。~ おすすめはちゃんと一目で分かる名前にすること。~ しかる後に、半角イコールを入れて、値を記載し、最後に半角セミコロンを入れれば完成。~ 注意点としては、string型を使う場合、イコールの後の文字列を""でくくること。~ string message = "this is message"; xsChatData(message); ↑こんな感じである。~ **constについて [#uc452931] これらのパラメーターは、一度宣言(型を表記して名前を付けるのを、ここでは宣言と呼ぶ)した後、別の値を入れることも可能である。~ 例えば、 int hoge = 1; と記載した下に、 //型の宣言は、型を変更しない場合、二回目以降は不要 hoge = 2; とすれば、以降hogeは2になるし、 int piyo = 4; を更に宣言して、 hoge = 3 + piyo; とすれば7になる。 -''足す'':''+'' -''引く'':''-'' -''かける'':''*'' -''あまり'':''%'' ※ちなみに割るについては、float型で宣言して、小数をかけた方が良い。カンのいい人なら「/」でいけるだろうな、という事に気づくだろうが、ある程度プログラミングになれるまではやめておけ。~ ~ しかし、例えば、先程の砲台の値のようなものは不変であるから、後から変更しないはずである。~ この場合に、この値は変数ではなく、定数ですよという意味になるのがconstである。~ このconstは、つけなければバグるということはないが、定数として用いたいときにはなるべく付けるくせを付けよう。 *条件設定入門① [#u4de48d6] さて、ここまでの内容を読んだ人であれば、定数や変数を定義してプレイヤー毎に属性を変更したり、資源を変更したりできるようになっているだろう。~ (できないようであれば、それはこの記事の説明がヘタクソだということなので修正する)~ そうすると、次なる野望というか、興味として、以下のようなことができないか気にならないだろうか。~ ~ 自分の文明や、敵の文明おきにパラメーター変えたりできないの?~ ~ プレイヤー毎に設定できるようになってはいるが、文明というのはプレイヤーやAIがランダムで選択することがよくある。~ 予め、その文明のユニークユニットについて設定しておくことはできるだろう。~ しかし、文明間で共通のユニットや建物に対し、文明おきに設定することは、これまでの知識からはできないだろう。~ この際に役に立つのが、条件分岐である。~ **情報を取得しよう [#m0bb2514] ここでは、プレイヤー7の文明が何か判定し、その文明によって何か設定をする、という状況で考えてみよう。~ あなたは常日頃からAI過大とのバトルを楽しんでいたが、基本的に和平期間を設定しているため、帝王の時代があまり強くない文明を敵に回した時に物足りなさを感じていた。~ その中でもどうもブルガリアが物足りない。~ そこで、敵の文明がブルガリアであるときだけにバフをかけられないか考えたとする。~ そのバフの内容は、城のヒットポイントを一万にすることだとしよう。~ 城のIDは、AoE2DEのエディターなり、AdvancedGenieEditorなり使えば、82だと分かるので、↑の復習も兼ねて以下のように定義しておこう。 const int Castle = 82; ~ さて、まず、あるプレイヤーの文明を取得するためには、以下の関数を用いる。~ xsGetPlayerCivilization(playerNumber) これを使うと、そのプレイヤー番号の文明を、int型の数字で獲得することができる。~ このため、int型の変数を定義して、プレイヤー7の文明番号を格納してみよう。~ int player7Civilization = xsGetPlayerCivilization(7); 当然上の、「player7Civilization」は自分で好きな名前を付けてよいし、仮にプレイヤー7ではなくてプレイヤー8の文明を獲得したかったら、xsGetPlayerCivilization(8)とすればよい。~ ちなみに、文明おきの番号は→[[civilizationID]]に記載しているので、ブルガリアが何か調べてみよう。。~ ブルガリアは、32かcBulgariansという定数であることがわかるだろう。~ **if文 [#kce0f1f8] さて、そしたら以下のような文章をプログラミングする。~ ''「もし、プレイヤー7の文明がブルガリアだったら、城のヒットポイントを一万にする。」''~ これは、以下のように記載する。~ if(player7Civilization == cBulgarians){ xsEffectAmount(cSetAttribute, Castle, cHitpoints, 10000, 7); } ~ 順に説明しよう。~ まず、もし~ならを示すのが、if()である。~ 半角括弧の中が、条件である。条件は色々設定できるがとりあえず、以下の二つを覚えよう。~ -==:同じなら -!=:違うなら つまり、if(player7Civilization == cBulgarians)の部分で、もしプレイヤー7の文明が、ブルガリアだったら、という意味になる。~ 次に、間髪入れずに記載されている半角中括弧であるが、これが~するの部分になる。~ あくまで~するであり、何をするかは括弧の中に記載する。~ ちなみに括弧の中は何行になってもいい。例えばヒットポイントだけでなく、攻撃速度も倍にしたいなら、 if(player7Civilization == cBulgarians){ xsEffectAmount(cSetAttribute, Castle, cHitpoints, 10000, 7); xsEffectAmount(cMulAttribute, Castle, cAttackReloadTime, 0.5, 7); } とすればいい。~ さらに言えば、何も記載しなかったとしてもバグらない。何もしないだけである。~ ちなみに、if文の中身は、↑の例のように、半角スペースを使って4~6個スペースを入れてインデントしておくと、見やすい。~ 括弧の記載し忘れや余計に記載することによるバグは極めて発生頻度が高いバグであり、プログラミングをしているとまず遭遇するバグなのであるが、インデントを忘れずにしていればミスが見つかりやすい。~ もし付け忘れてバグっても、ゲーム開始時に何行目がバグってるかエラーを吐いてくれるのでそこまで心配はいらないが。~ ちなみにテキストエディタではなく、Visual Studio Codeなどのソフトをお勧めする理由は、括弧をレベルに応じて色分けしてくれたりするからである。ものによってはその括弧を選択していると対応する括弧が強調されたりもする。~ ~ ~ ここまでのコードの例をまとめると、こんな感じ。~ const int Castle = 82; int player7Civilization = xsGetPlayerCivilization(7); if(player7Civilization == cBulgarians){ xsEffectAmount(cSetAttribute, Castle, cHitpoints, 10000, 7); } ***else if、else [#a78e7732] あなたが好奇心と創作意欲の塊なら、「いや、俺はブルガリアだけじゃなくてビルマにもバフかけたい」、「さらにそれ以外の全部にもバフかけたい」なんて、考えるかもしれない。~ この場合は、これまでの知識を生かして、 //定数は、なるべく頭のほうにまとめておく。 const int Castle = 82; const int Champion = 567; int player7Civilization = xsGetPlayerCivilization(7); if(player7Civilization == cBulgarians){ xsEffectAmount(cSetAttribute, Castle, cHitpoints, 10000, 7); } if(player7Civilization == cBurmese){ xsEffectAmount(cModResource, cAttributeRelicWoodRate, cAttributeSet, 100, 7); } if(player7Civilization != cBulgarians){ //if文の中に、if文を書くことも可能。ネストとか呼んだりする。 if(player7Civilization != cBurmese){ xsEffectAmount(cMulAttribute, Champion, cHitpoints, 2, 7); } } のようにしてくれれば、動く。~ この際、''「同時発生することがありえない」''、''「同時発生させたくない」''条件については、上記のようにifを連発するのではなく、「それ以外で、もし~なら」を意味する''else if''や、「それ以外なら」を意味する''else''を使って記載するのがよい。~ 特にネストは、括弧の付け忘れが発生したり、プログラムが横に長くなりがちなので、回避できるシチュエーションならなるべく避けておこう。~ ※なお、視覚的にひと固まりになるので見やすいという利点以外に、プログラミング言語によってはif連発よりもelse ifを使った方が早くなるというメリットもある。~ 今回の場合、プレイヤー7の文明がブルガリアであると同時にビルマであるような状況はありえないので、else ifやelseを用いて書くとよい。~ そうすると、以下のようになる。~ //定数は、なるべく頭のほうにまとめておく。 const int Castle = 82; const int Champion = 567; int player7Civilization = xsGetPlayerCivilization(7); if(player7Civilization == cBulgarians){ xsEffectAmount(cSetAttribute, Castle, cHitpoints, 10000, 7); }else if(player7Civilization == cBurmese){ xsEffectAmount(cModResource, cAttributeRelicWoodRate, cAttributeSet, 100, 7); }else{ xsEffectAmount(cMulAttribute, Champion, cHitpoints, 2, 7); } ※else ifは、一つ前のif文の中括弧が終わってすぐに記載すると、固まりとして認識しやすい。~ ※elseは、上の条件すべてに当てはまらない場合になるので、「~」に該当する()を記載しない。~ ~ これで、文明おきにバフをかけることができようになるはずだ。~ ~