Terrariaの飛び道具のAIを調べる
はじめに
アイスロッドがブロック化してから消える前での秒数についてIce Rod - Terraria Japan Wikiでは次のように書かれている。
設置された氷ブロックは15秒ほどで割れる他、ツルハシで削れる。またIce Block.png Ice Block同様滑る
「15秒ほど」とあるので15秒なのだろう。
しかし、この15
はどのように定義されているのかがよくわからない。
というわけで、実際に正しいのか中身のコードを覗いてみることにした。
なお、結論としてはアイスロッドは魔法武器で飛び道具であるため、使用するとアイスブロックが飛び出す。 Terrariaではこうした飛び道具で飛び出すものは「発射物」として管理され、「発射物」としての性能があり、AIが定義されている。 アイスロッドで作成したアイスブロックのAIはブロック化した際に1f毎にカウントを始めて、900f (15秒) 経過したら削除される動作となっている。
コードの確認について
こちらを参考に。 【Terraria】tModLoaderからTerrariaをデバック実行する - プログラミング・動画編集 備忘録
アイテムの仕様を調べる
アイスロッドはアイテムなので、まずはアイテムとしての仕様を確認することにした。
Terraria.ID.ItemID
にてItemIDを確認する。
public const short IceRod = 496;
アイテムの基本的な性能などはSetDefaults
に記載されているのでそこを確認するが、手っ取り早くは== 496)
といった形でItemIDで検索すればそれらしい場所が見つかる。
if (type == 496) { this.rare = 4; this.mana = 6; this.damage = 28; this.useStyle = 1; this.shootSpeed = 12f; this.shoot = 80; this.width = 26; this.height = 28; this.UseSound = SoundID.Item28; this.useAnimation = 9; this.useTime = 9; this.rare = 4; this.autoReuse = true; this.noMelee = true; this.knockBack = 0f; this.value = Item.buyPrice(0, 50, 0, 0); this.magic = true; this.knockBack = 2f; return; }
見た感じ、ここで消滅までの秒数が定義されている様子はない。
それもそうだ。アイスロッドは魔法の武器でアイスブロックを射出してそれがブロック化する。
つまり、何かしらの発射物なので、確認すべきは projectile
となる。
発射物の性能を調べる
Terrariaでは「発射物」はTerraria.Projectile
に各種アイテムの性能やAIの動作が記載されている。
こちらも作成された際の仕様などはSetDefaults
に記載されている。
まずはIDをTerraria.ID.ProjectileID
で調べる。
public const short IceBlock = 80;
先ほどアイテムの仕様でthis.shoot = 80;
とあるので、ここが発射物のIDなのだと思うが、もう忘れている。
なお、名前が良くわからなければ、SetDefaults
の入口にでもブレークポイントを設定して実際に動かしてみれば良い。
つづいて、type == 80)
といった形で検索。
else if (this.type == 80) { this.width = 16; this.height = 16; this.aiStyle = 22; this.friendly = true; this.magic = true; this.tileCollide = false; this.light = 0.5f; this.coldDamage = true; }
aiStyle
が22
となっているので、aiStyle == 22
といった形で検索する。
該当のAIの処理の入口がわかったら後はそこからコードを見ていくのだが、よくわからなければデバッグで少しずつ確認していく他ない。
今回は、おそらくブロックが作成されたらそこから秒数のカウントなりが始まると思うので、ブロックが作製される部分に着目してみれば良い。
次のようになっていた。
if (flag6) { if (WorldGen.PlaceTile(num292, num293, 127, false, false, this.owner, 0)) { if (Main.netMode == 1) { NetMessage.SendData(17, -1, -1, null, 1, (float)((int)this.ai[0]), (float)((int)this.ai[1]), 127f, 0, 0, 0); } this.damage = 0; this.ai[0] = -1f; this.velocity *= 0f; this.alpha = 255; this.position.X = (float)(num292 * 16); this.position.Y = (float)(num293 * 16); this.netUpdate = true; return; } this.ai[1] = -1f; return; }
this.ai[1] = -1f;
となっているので、これが初期値だろう。次はこのブロックを削除する部分を確認する。
this.ai[0] -= 1f; if (this.ai[0] <= -900f && (Main.myPlayer == this.owner || Main.netMode == 2) && Main.tile[num281, num282].active() && Main.tile[num281, num282].type == 127) { WorldGen.KillTile(num281, num282, false, false, false); if (Main.netMode == 1) { NetMessage.SendData(17, -1, -1, null, 0, (float)num281, (float)num282, 0f, 0, 0, 0); } this.Kill(); return; }
this.ai[0] <= -900f
と判定が書かれているので、900フレーム、1秒60フレームで、900 / 60 = 15
ということで、15秒ということがわかる。