-
Notifications
You must be signed in to change notification settings - Fork 7
create object
- 1. 事前に済ませてね
- 2. テンプレートを作成する
- 3. オブジェクトの基本情報の設定
- 4. オブジェクトの処理を記述する
- 5. オブジェクトの召喚 (APIから呼ぶ側)
- 6. 継承 (extends) の仕組み
- 7. オブジェクトの削除
- 8. ハマりポイント
オブジェクトは、矢・弾・演出のマーカーみたいに 一瞬だけ場に出して消えるエンティティ をまとめて作るための仕組みだよ。ギミックにも使える。
神器・モブと違って、オブジェクトは「召喚 → 毎 tick 動く → 命中や時間切れで消える」 という流れで使い捨てるのが基本。既に作ったオブジェクトを土台にして派生 (例: 「矢」 から「炎付き矢」) を作れる仕組みもあるから、似た挙動のオブジェクトをまとめて書けるよ。
- TSBリポジトリのクローン, ブランチを切っている状態
- 推奨拡張機能の導入
- スプレッドシートの ID 欄からオブジェクト ID を取得
MCDatapackUtilityを利用してオブジェクトアセットのテンプレートを作成するよ。
Datapack: Create Datapack templateを実行してね。デフォルトだとShift + Alt + D -> Shift + Alt + Tを押すと動作するよ。
下記のメニューが出てくるからデータパックにテンプレートを追加するを選択してね。

データパックはAssetフォルダを指定。命名規則は他と同じ。
<四桁のID>.<オブジェクト名(snake_case)>で名前を記述してね- オブジェクト名は基本的に英語に翻訳したものを使うよ
- 各単語を
_区切ってね- 英語に翻訳できないような物はローマ字 (ヘボン式) にしてね
テンプレートの種別では「オブジェクト/テンプレート」を選んでね。必要な処理 (summon/init/tick 等) のチェックも入れる。
これでテンプレートが Asset/data/asset/functions/object/<オブジェクト名>/~ と Asset/data/asset/functions/object/alias/<ID>/~ に生成されてるはずだよ。
asset/functions/object/<オブジェクト名>/
register.mcfunction # ID/Field/Extends 等を定義
summon/.mcfunction # 召喚時の処理
init/.mcfunction # 初期化処理 (オプション)
tick/.mcfunction # 毎tick処理 (オプション)
(任意のメソッド)/.mcfunction # 自分で追加するカスタムメソッド
asset/functions/object/alias/<ID>/
register.mcfunction # 実装パスへのエイリアス
summon.mcfunction
tick.mcfunction
init.mcfunction
(任意のメソッド).mcfunction
alias/ は ID → 実装パスの間接参照層 だよ。オブジェクトは ID で呼ばれるから、 alias がないと実体のパスが見つけられないって仕組み。中身はだいたい function asset:object/<実装パス>/<メソッド> を呼ぶだけ。
note: alias は MCDatapackUtility のテンプレート生成時に自動で作られるので、基本的に手動で作る必要はないよ。カスタムメソッドを後から追加する時だけ、自分で alias を書き足す必要がある (詳細は4.5節)。
注: ここから先基本的に function 名は下記のような省略した形で記載するよ
Asset/data/asset/functions/object/<オブジェクト名>/register.mcfunction->~/register.mcf
生成されたテンプレートの~/register.mcfを編集していくよ。
| 設定名 | 必須 | 設定する型 | 説明 | デフォルト | 例 |
|---|---|---|---|---|---|
| Extends | × | int[] | 継承する親オブジェクトの ID (append で追加) 使うときは function asset:object/extends も併用 |
[] |
… append value 1001 |
| ExtendsSafe | × | boolean | 他のオブジェクトから継承されることを許可するか | false |
… value true |
| IsAbstract | × | boolean | 抽象オブジェクトとして扱う (直接召喚不可、継承用) | false |
… value true |
| IsTicking | × | boolean | tick を実行するか | false |
… value true |
| ID | o | int | オブジェクト ID | - | … value 1009 |
| Field | × | compound | カスタムフィールド (tick 等で asset:context this.<キー> で参照可能) |
{} |
… value {Speed:4,Damage:1.0d} |
オブジェクト個体ごとに持つカスタムデータ。召喚時に値が割り当てられて、 tick 等から asset:context this.<キー> で参照できる。
実例: 1009.arrow の Field
data modify storage asset:object Field.Speed set value 4
data modify storage asset:object Field.Range set value 40
data modify storage asset:object Field.Color set value 16777215
data modify storage asset:object Field.ShowCritParticle set value true
data modify storage asset:object Field.Damage set value 1
data modify storage asset:object Field.AttackType set value "Physical"
data modify storage asset:object Field.ElementType set value "None"召喚 API 側でArgument.FieldOverrideを指定すれば、個別の召喚時に Field を上書きできる。例: 「速度 2 倍の矢」「魔法の矢」 みたいな個別調整。
-
IsAbstract:true = 「抽象オブジェクト」 として扱う。直接召喚しようとするとエラー。継承用の親クラス (例:
1001.abstract_projectile) で使う -
IsTicking:true = 毎 tick の処理を実行する。 tick 処理が必要なオブジェクト (= ほぼ全てのオブジェクト) で
trueにする。静的な装飾オブジェクトならfalse
| イベント | 呼ばれるタイミング | 実装ファイル |
|---|---|---|
register |
load 時に 1 回 (クラス定義として) | register.mcfunction |
summon |
api:object/summon で召喚された時 |
summon/.mcfunction |
init |
召喚直後の初期化処理 (ObjectInitタグが付与された状態) |
init/.mcfunction |
tick |
毎 tick (IsTicking:true の時のみ) |
tick/.mcfunction |
| カスタム |
asset_manager:object/call_method/run_method.m で呼び出した時 |
自由なファイル名 |
実行コンテキストでは以下が参照可能:
-
@s= オブジェクトエンティティ -
storage asset:context this= Field の中身 -
storage asset:context id= このオブジェクトの ID -
storage asset:context originID= 召喚時の元 ID (継承呼び出し中も最初の ID を保持) -
tag @s this= 自分自身であることを示すタグ
新規エンティティを実際に生成する処理。 TSB が常駐させているマーカーエンティティ (UUID 0-0-0-0-0、別名 commonMarker) をテンプレートに使うと、座標・向きの引き継ぎが楽。
注意:
0-0-0-0-0は overworld の0 0 0に常駐する前提のマーカーだよ。 tp する時は 必ずin minecraft:overworldを挟んで overworld 内で動かすこと。 overworld 以外で素朴にtp 0-0-0-0-0 ~ ~ ~してしまうと、 0-0-0-0-0 自身が実行 dimension 側に飛ばされて、以降のシステム参照 (core:tick内の存在チェック等) が壊れる。後述のコード例のin minecraft:overworldはこのためのもの。
#> asset:object/1009.arrow/summon/
# 元となるEntityを召喚する (0-0-0-0-0をベースに座標 / 向きを揃える)
# in minecraft:overworld で dimension を overworld に固定してから tp する (鉄則)
execute as 0-0-0-0-0 in minecraft:overworld positioned as @s run tp @s ~ ~ ~ ~ ~
# 召喚に必要なFieldを取り出す
data modify storage asset:temp Args.Color set from storage asset:context this.Color
data modify storage asset:temp Args.Rotation set from entity 0-0-0-0-0 Rotation
# マクロでitem_displayを召喚
function asset:object/1009.arrow/summon/m with storage asset:temp Args
data remove storage asset:temp Argssummon/m.mcfunction (マクロ部) :
#> asset:object/1009.arrow/summon/m
#
# @input args
# Rotation: [float] @ 2
# Color: int
$summon item_display ~ ~ ~ {Rotation:$(Rotation),Tags:["ObjectInit"],item:{id:"minecraft:leather_horse_armor",Count:1b,tag:{CustomModelData:20451,display:{color:$(Color)}}},teleport_duration:1}ポイント :
- 召喚するエンティティに必ず
Tags:["ObjectInit"]を付与。これでinitフェーズが呼ばれる -
item_displayやarea_effect_cloudなど、軽量なエンティティを使うのが基本
召喚されたエンティティの初期化処理。 ObjectInit タグが付いている間に呼ばれる。 ObjectID スコアの設定や OhMyDat スロットの確保はシステム側で自動でやってくれるので、自分で書くのは個別の初期化だけで OK 。
#> asset:object/<name>/init/
# 個別の初期化処理 (例: 寿命カウンタを設定)
scoreboard players set @s LifeTime 200
# 自身に Asset.Object.<ID> 等のタグを付与 (asset_manager 側で自動付与されるので普通は不要)オブジェクトの本体処理。移動・衝突判定・寿命管理など。
asset:context this にオブジェクト毎のストレージが用意されているので、活用するといい感じの設計ができるよ。
#> asset:object/<name>/tick/
# 前進 (this.Speed の値だけ進む)
execute store result score $Move Lib run data get storage asset:context this.Speed 10000
function lib:score_to_move/
# 命中判定 (Mob にぶつかったら hit_entity を呼ぶ)
execute if entity @e[type=#lib:living_without_player,tag=Enemy,distance=..1.5] run function asset:object/<name>/hit_entity/
# 寿命カウントダウン
scoreboard players remove @s LifeTime 1
execute if score @s LifeTime matches ..0 run function asset:object/<name>/remove/
# tick 終了時、変更した Field を保存
# (システムが自動で this を ObjectField に書き戻すので、ここでは何もしなくてOK)asset:context this.<キー> を data modify で書き換えると、 tick 終了時に自動で OhMyDat に保存される。だから tick 中は普通の storage 操作として扱える。
# 残り射程を減らす
scoreboard players remove @s LifeTime 1
# Field の値を直接更新したい場合
execute store result storage asset:context this.RemainingRange int 1 run scoreboard players get @s LifeTime任意のメソッドを定義して、他のところから呼び出せる。ボス戦の演出オブジェクトに「攻撃メソッド」 「リセットメソッド」 を持たせる、みたいな使い方。
#> asset:object/<name>/attack/
# 自分の周囲の敵にダメージを与える
data modify storage api: Argument.Damage set value 5.0f
data modify storage api: Argument.AttackType set value "Magic"
execute as @e[type=#lib:living_without_player,tag=Enemy,distance=..3] run function api:damage/
function api:damage/resetカスタムメソッドの場合、 alias は自動生成されないので手動で追加する必要がある。
asset/functions/object/alias/<ID>/attack.mcfunction :
#> asset:object/alias/<ID>/attack
function asset:object/<name>/attack/オブジェクト自身、または別の場所からメソッドを呼ぶときは asset:object/call.m をマクロ呼び出しする。 as <対象 entity> で対象を指定すれば、そのオブジェクトの ID が自動で取得されて該当の alias 経由でメソッドが実行される。
# 自分自身のメソッドを呼ぶ (オブジェクト内部から)
function asset:object/call.m {method:attack}
# 別のオブジェクトのメソッドを呼ぶ (外部から、例: ボスの本体が分身に attack させる)
execute as @e[tag=Asset.Object.<ID>] at @s run function asset:object/call.m {method:attack}詳細は API を参照。基本的な使い方:
# 引数: ID
data modify storage api: Argument.ID set value 1009
# (オプション) Field の値を上書き
data modify storage api: Argument.FieldOverride set value {Speed:8,Damage:5.0d,Color:16711680}
# 召喚位置・向きは実行者のものが使われる
execute at @s anchored eyes positioned ^ ^ ^ rotated ~ ~ run function api:object/summonArgument.FieldOverride を渡せば、 register で定義したデフォルト値の一部を上書きできる。「弱い矢」「強い矢」「色違いの矢」 みたいなバリエーションを register を増やさず作るのに便利だよ。
オブジェクトは疑似 OOP で継承が使える。共通処理を親に集約して、個別の挙動だけ子で書く設計ができる。射撃体や弾系の「共通の移動・衝突判定」 を作る時にはほぼ必須。
継承される親は IsAbstract:true (直接召喚させない) と ExtendsSafe:true (継承を許可) を明示する。
#> asset:object/1001.abstract_projectile/register
# 抽象オブジェクトとして
data modify storage asset:object IsAbstract set value true
data modify storage asset:object ExtendsSafe set value true
data modify storage asset:object IsTicking set value true
# ID
data modify storage asset:object ID set value 1001
# 共通の Field (子で上書き可能)
data modify storage asset:object Field.Speed set value 1
data modify storage asset:object Field.Range set value 10
data modify storage asset:object Field.Damage set value 0親側の tick は共通処理 (移動とか) を書く:
#> asset:object/1001.abstract_projectile/tick/
# 前進
execute store result score $Move Lib run data get storage asset:context this.Speed 10000
function lib:score_to_move/
# 射程切れたら削除
execute if data storage asset:context this.RemainingRange{..0} run kill @s子の register で Extends に親 ID を追加して function asset:object/extends を呼ぶ。
#> asset:object/1009.arrow/register
# 継承
data modify storage asset:object Extends append value 1001 # 1001.abstract_projectile を継承
function asset:object/extends
# 自分の情報を上書き
data modify storage asset:object IsAbstract set value false
data modify storage asset:object ID set value 1009
data modify storage asset:object Field.Speed set value 4
data modify storage asset:object Field.Range set value 40
data modify storage asset:object Field.Damage set value 1これで Field は親の値で初期化されて、子側で書いた行で上書きされる。 ID と IsAbstract は子の値が優先される。
tick 等の実装ファイルで親のメソッドも実行したい時は、 function asset:object/super.<method> を呼ぶ。
#> asset:object/1009.arrow/tick/
# 子独自の処理 (矢特有の演出など)
particle crit ~ ~ ~ 0 0 0 0.05 1
# 親 (abstract_projectile) の tick も実行 (= 共通の移動・寿命チェック)
function asset:object/super.ticksuper.tick を呼ぶと、親側の tick/.mcfunction が asset:context id を親 ID に切り替えた状態で実行される。自動で context が戻されるから後片付けは不要。
super.method は任意のメソッド名版で、 asset:context method にメソッド名をセットしてから呼ぶ。
オブジェクトを削除したい時は、 ObjectID スコアをリセットすれば OK 。システムが次 tick で自動的にエンティティを片付ける。
# オブジェクトを削除
scoreboard players reset @s ObjectIDまたは kill @s で即座に削除してもいい。ただし OhMyDat スロットの解放が遅れるので、通常は ObjectID リセット推奨。
-
alias/ を作り忘れる → 召喚しても何も起きない。 alias は ID → 実装パスの間接参照で、必ず register / summon / tick / その他カスタムメソッドの分を
alias/<ID>/に置く必要があるよ - 召喚時に Tags:["ObjectInit"] を付け忘れる → init/.mcfunction が呼ばれない。さらに後続の自動初期化 (ObjectID 割り当て等) もスキップされる
-
IsAbstract:true を直接召喚しようとする → エラーになる。派生クラス (
IsAbstract:false) を作って召喚する -
IsTicking を false のまま tick を書く → tick 関数があっても呼ばれない。動かしたいなら必ず
trueにする - super.tick の呼び出し位置を間違える → 子の tick の中で呼ぶと「子の処理 → 親の処理」 の順で実行される。親 → 子 にしたいなら子 tick の先頭で super を呼ぶ
- 重い処理を tick で書く → 同時に数百個のオブジェクトが存在することもあるから、 1 個あたりの tick コストには気を配ること。寿命カウンタで早めに削除するのも大事