Entityについて解説したい 3
InputとOutputについて解説すると言ったな
します
まずEntityのInputとOutputとは何か、なのですが
単純にEntityに何かを入力する、Entityが何かを出力するという認識でOKです。
僕はオブジェクト指向プログラミングというのがよく分かっていない人間なのでこういう說明をするのもなんなのですが
EntityClassnameはそのままクラス、Entityの実体はインスタンス、InputとOutputはメソッドと返り値みたいな感じです。
また別に解説するとは思いますが、インスタンスのようにポンポンEntityを作成する事も可能です。
ブン投げるようでアレですが、InputとOutputに関してはHammerを起動した方が早く分かります。
Hammer講座でドアを作っている部分の解説がそれに当たります。
Hammerだと、設置したEntityがプレイヤーの動きやゲームの進行によってOutputを発信するように設定し、
そのOutputを別のEntityのInputに送り込むようになっています。*1
SourcePawnからInputを行う場合とは流れが少し違うのですが、まずEntityのInputとOutputがどう設定されているかを上記ページでおおまかに理解しておいてください。
では、SourcePawnからInputとOutputを操作するにはどうするか
とりあえずはInputから。
例としてやはり"team_control_point"を使いますよ
Entityのページを復習しておいてね
team_control_point - Valve Developer Community
new ent = -1; while((ent = FindEntityByClassname(ent, "team_control_point")) != -1){ //名前からエンティティを探す AcceptEntityInput(ent, "Disable"); }
関数のリファレンスはこちら
AcceptEntityInput · sdktools_entinput · SourceMod Scripting API Reference
これでDisableというInputを叩いたので、CPが無効化されます。個別のチェックしてないから見つかったCP全部無効になるね
activator、caller、outputidは省略可能です。
ただし必要とするInputもあるので、上手く動かなかったら指定してやってください。outputidが必要なのは今のところ見たことがないです。
具体的には本来Outputを送るはずだったEntityや、起動したプレイヤーを入れてやると良いです。特になければ0でも。
使えるInputはEntityによって違うので、Entityのページは良く見るようにしましょう。
HammerからもInput名は見えますが、說明は無いので…
なお、KeyValueのところは違います。
HammerでEntityのプロパティを開いた時、最初に表示されているプロパティ一覧がKeyValueです。
Flagは隣のタブだよ
次は、引数を必要とするInputの場合。
例えばSetOwnerというInputは、チーム番号を受け取ってCPをそのチームに取得させます。
SetVariantInt(TFTeam_Blue);
AcceptEntityInput(ent, "SetOwner", client, client);
TFTeam_Blueは定数です 3が入ってます。 TFTeam_Redは2 要tf2.inc
今更だけどこの記事で説明してる関数はほぼ全部sdktools.incが必要です*2
SetVariantInt関数の説明はこちら。
SetVariantInt · sdktools_entinput · SourceMod Scripting API Reference
Sets an integer value in the global variant object.
グローバルバリアントオブジェクトに整数値を設定します。
なんだよグローバルバリアントオブジェクトって。
…またよく分かってなくて申し訳ないのですが
僕は専用のバッファかなんかあるんかなぁという認識です。
SetVariant~関数でバッファに値を入れて、AcceptEntityInputでInputを送信する時にバッファの値も一緒に送信しているんだと思います
確かAcceptEntityInputした時に中身消えたと思うから次同じ値使う場合も再度SevVariant~した方がいい…はず した方が無難
SetVariantうんたらという関数が幾つかあるのですが、
これらはInputの引数の型に対応していて
与える値の型に対応した関数を使う必要があります。
んで
AcceptEntityInput(ent, "SetOwner", client, client);
ここでactivatorとcallerにclient番号入れてますが、SetOwnerはactivator渡さないと動きません…
ポイント取得者を表示するために必要な情報なのだと思います。*3
とりあえずこれでInputは送信できるはず
次はどうしようかな OutputにするかKeyValuleにするかSpawnにするか
EntPropは最後にしようと思ってる*4
Entityについて解説したい 2
InputとOutputについて解説すると言ったな?
あれは嘘だ
InputとOutputするにはまずInputOutputしたいEntityを見つける必要がありますね
InputOutputについてはそれから
ここでは例として"team_control_point"エンティティを探してみるよ
これはキャプチャーポイントのEntityで、A/Dや5CPやKOTHに設置してあるアレね。
なお、画面に表示されてるCPのHUDやキャプチャー可能なエリアを設定してるのは別のエンティティだよややこしいNE
team_control_point - Valve Developer Community
Entityの詳細ページはこちら。
Entityを探す関数はFindEntityByClassname関数
FindEntityByClassname · sdktools_functions · SourceMod Scripting API Reference
関数の説明はこちら。
この関数は、指定したEntity番号以降のEntityの名前を順番に検索していって、最初に指定の名称のEntityを見つけたらそのEntity番号を返します。
なので検索して出てきたEntityが、自分の求めているEntityかどうかはまた色々しないと分かりません。
使い方。はいこれテストに出まーす。
new ent = -1; while((ent = FindEntityByClassname(ent, "team_control_point")) != -1){ //名前からエンティティを探す PrintToServer("Entity %d はteam_control_pointです",ent); }
まず、初期値が-1なので、存在する一番若番のEntityから検索を開始します。
Entityのクラス名が"team_control_point"のEntityを発見したら、そのEntity番号を返してくるので、entの値が更新されます。
見つかったEntity番号に対して処理を行った後、そのEntity番号を引数に再度検索します。
Entityが見つからなかったら-1が返されるので、ループを抜けます。
つまり、Entity番号が0から9の10個のEntityがあったとして、そのうち2と5がteam_control_pointだったとすると、
Entity 2 はteam_control_pointです Entity 5 はteam_control_pointです
となるわけ。
例えば、kothとかだとCPは1つですが、5CPだと5つあるので上記の例だとPrintToServerが5回実行されるはず。
何故ループを回す必要があるかは単純に同じ種類のEntityが複数あった場合、探しているEntityが検索した1件目とは限らないため。
Entity番号がどう振られているかは決まっていないので、上記の場合探しているteam_control_pointが2か5かは分からない。今回2だったからって次も2とは限らないし、4になってるかもしれない
では中央CPだけ取得したい場合はどうすれば良いか、なのですが
GetEntPropでm_iDefaultOwnerが0のCP探せばいいんじゃないかな多分
これの說明はまた後でします。
基本的には総当りして、条件に合致するEntity見つけたら抜ければOK
とにかくこれでteam_control_pointのEntity番号が分かりました。
次こそInputとOutputやるよ 多分
Entityについて解説したい 1
詰まるようなところでは無いのかもしれないが、自分は延々と詰まったので解説したい
だがどこからどう解説したものか…
「自分はこういう認識をしている」という体で話します。
実際どうであるかとはかけ離れている可能性は大いにあります。
Entityとは、ゲーム上に存在するほぼ全ての物がEntityです。地面を転がっている酒瓶から、プレイしているプレイヤーキャラクターもEntityです。
ここではそう認識します。ぶっちゃゲーム内で管理されていていて個別の番号を割り振られているオブジェクトの事をEntityだと思ってて特に困らないと思います。
逆に、Entityで無い物もあります。地面や壁等のsolidがそうです。ただし、Entity化されたSolidを除きます。*1
このあたりはマップ制作の話に被ります。Entityを分かるのに避けて通れないと思うので、プラグイン開発者はHammerの最低限の知識が必須です。*2
Valve ハンマーエディタ講座 4.1
必読ですよ というかHammerの資料少なすぎやしませんか…
こちら必要な事は一通り抑えてあり、記述している所を一通りやれば次に必要な事は自分で見つけられると思います。
尚、TF2のHammerEditerはtf2インストール配下のbinフォルダ内にあります。SourceSDKは不要です
大事なことなのでもう一度言います。SourceSDKは不要です
話が少しそれましたが、Entityは大きく分けて2種類あります。
・SolidをEntity化したbrushエンティティ
・マップ上に直接設置、もしくはゲームエンジンが動的に生成するpointエンティティ
ポイントエンティティは実体を持つ(ゲーム上に表示される)物と、実体を持たない(表示されず、機能のみを持つ)ものがあります。
ブラシエンティティは例えばキャプチャーエリアの範囲やリスポンルームの範囲等を作る事ができます。
ポイントエンティティは弾薬やヘルスキット等のアイテムや、ゲームのタイマー、物理演算オブジェクト等多岐に渡ります。
Entityの一覧を貼っておきます。
どのようなEntityがあってどんな機能を持っているのか、見てみても良いかもしれません。
SourceEngine全般
List of base entities - Valve Developer Community
TF2
List of Team Fortress 2 Entities - Valve Developer Community
次があったらInputとOutputの話をします。
とりあえず今回はゲーム上の殆どのものはEntityなんだって思ってくれたらOKです。
KothIntelプラグイン
KothでCPの代わりにインテルを使うプラグイン。
インテルを拾っている間タイマーが動作します。落とすと止まります。
[TF2]KothIntel プラグイン pic.twitter.com/LtNrPKVjn7
— ArcMage (@Alchemist_Ark) 2018年1月11日
リスポン前に要塞作った園児がインテル持って立てこもるんですよね分かってます
ソースは貼りません(面倒になった)
希望者はご連絡ください
kothのタイマーを操作する
クソみたいに遠回りした…
とりあえず順番に語ります。本題だけ見たい人は最後のコードを見てください。
kothのタイマーを操作したい
とりあえず止めたり動かしたり時間を変えたりしたい
ではkothのタイマーはどこにあるのか?
とりあえず思いつくのはtf_logic_koth、tf_gamerules、team_round_timer
tf_logic_kothはとりあえずkothのHUDを表示してる
後タイマーにセットする時間を持っている
tf_gamerulesにはkoth関係と思われるInputはSetRedKothClockActiveとSetBlueKothClockActiveしかない
これはkothのタイマーをスタートさせるだけ 一方が動き出すともう片方は止まる。
team_round_timerは複数のマップをHammerEditerで開いてみたところ、
そもそもkothマップには置いてない事が多いように見える。
つまり、bspファイル内にkothのタイマーを記録しているEntityは存在しない…?
と思っていたらtf_logic_kothのページにこのような記述を発見。
It creates two entities named zz_red_koth_timer and zz_blue_koth_timer which have inputs like pause,resume,etc
これは、zz_red_koth_timerとzz_blue_koth_timerという名前の2つのエンティティを作成します。これらのエンティティには、一時停止、再開などの入力があります。
動的に作ってんのかよ!!!
じゃープラグインからzz_*_koth_timerってEntity探したり作ったりしてみようか
まで考えたけど見つからないし作成できず。
うん、僕バカなのでzz_*_koth_timerってClassnameでEntity探したよね
個別のEntity名ですってば。プロパティ名で言うとtargetname
恐らくEntityClassnameはteam_round_timerだと思われ
HammerEditerでOutput先にzz_~を指定するとOutput先が存在しないって言われるけど動作します。
何かのイベントが起きるとタイマーが止まるkothマップとか作れます。
zz_~で調べてたら、その名前で引っ掛けてEntityを特定してるコードを発見。
けどもう少し調べたらtf_gamerulesのNetPropに普通に格納されてた
んでtf_gamerulesはsdktoolsをincludeしたらGameRules_GetPropEntで読めるから…
あれ、これコード凄い単純じゃね…?
以下コード。
public Action:Cmd_get(client, args){ //タイマーのEntityを確保する new bluetimerEnt = GameRules_GetPropEnt("m_hBlueKothTimer"); new redtimerEnt = GameRules_GetPropEnt("m_hRedKothTimer"); new float:fBluTime; new float:fRedTime; //青タイマー確認 //止まっていると1、動いていると0 if(GetEntProp(bluetimerEnt, Prop_Send, "m_bTimerPaused") == 0){ //タイマー動作中(タイマー開始時の時刻-現在時刻) fBluTime = GetEntPropFloat(bluetimerEnt, Prop_Send, "m_flTimerEndTime") - GetGameTime(); } else{ //タイマー停止中 fBluTime = GetEntPropFloat(bluetimerEnt, Prop_Send, "m_flTimeRemaining"); } //赤タイマー確認 if(GetEntProp(redtimerEnt, Prop_Send, "m_bTimerPaused") == 0){ fRedTime = GetEntPropFloat(redtimerEnt, Prop_Send, "m_flTimerEndTime") - GetGameTime(); } else{ fRedTime = GetEntPropFloat(redtimerEnt, Prop_Send, "m_flTimeRemaining"); } //表示する PrintToChat(client,"Blue:%f Red:%f",fBluTime,fRedTime); PrintToChat(client,"BlueTimer:%d RedTimer:%d",GetEntProp(bluetimerEnt, Prop_Send, "m_bTimerPaused"),GetEntProp(redtimerEnt, Prop_Send, "m_bTimerPaused")); /* SetEntProp(bluetimerEnt, Prop_Send, "m_bTimerPaused",1); "m_bTimerPaused"に1を書き込むとタイマーが停止するが、同時に"m_flTimeRemaining"の値でタイマーが上書きされる 停止させる前に手動で"m_flTimeRemaining"の値を更新すること また、CPは取得されたままになるのでCPの所有者を開放する等の処置を取ること */ }
多分team_round_timeのInputが使えるので、全部GetEntPropする必要は無いと思う。
コメントにも書いてるけど、タイマーをただ停止させるとタイマーが動く前の時間に戻されるので注意。
先にTimeRemainingの値を書き換えておけばOK
そういえば両方動かしたら両方同時に動き出してちょっと笑える
ていうか最終的にコピペしたのがmorestocksなのちょっと納得行かない
つまりmorestocksをincludeした方が断然早い。
sourcemod-snippets/tf2_morestocks.inc at master · powerlord/sourcemod-snippets · GitHub