-
Notifications
You must be signed in to change notification settings - Fork 6
create object
- 1. 事前に済ませてね
- 2. テンプレートを作成する
- 3. オブジェクトの基本情報の設定
- 4. オブジェクトの処理を記述する
- 5. オブジェクトの召喚 (APIから呼ぶ側)
- 6. 継承 (extends) の仕組み
- 7. オブジェクトの削除
- 8. 実装例の参照
- 9. ハマりポイント
オブジェクトは、一時的なエンティティをクラスベースで管理する仕組みだよ。 射撃体や弾、 一時的な演出マーカー、 ギミック (テレポーター等) を作るのに使うんだ。
神器・モブと違って永続データを持たないことが多くて、 短命なライフサイクル (= 召喚 → tick で動く → 命中や時間切れで削除) を回すために設計されている。 疑似 OOP ・継承の仕組みもあって、 「矢の派生で炎付き矢」 みたいな実装が綺麗に書ける。
- 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 内で動かすこと。 the_nether / the_end のプレイヤーから素朴に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_manager:object/triggers/tickから呼ばれる -
@s= AssetObject タグ付きエンティティ -
tag @s thisで「自分自身」 タグが付く (selector でtag=thisが使える) - OhMyDat スロットが自動で解決され、
storage oh_my_dat: _[-4][-4][-4][-4][-4][-4][-4][-4].ObjectField(8 段の_[-4]ネスト先) がstorage 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 リセット推奨。
オブジェクトの実装は数百個あるから、 似た挙動のものを参考にすると早いよ。
| ID | 名前 | 用途・特徴 |
|---|---|---|
| 1001 | abstract_projectile | 射撃体の抽象基底クラス (IsAbstract:true) |
| 1009 | arrow | 矢 (シンプルな射撃体、 1001 を継承) |
| 1010 | fire_magic | 火の玉 |
| 1022 | shaking_bullet | 揺れる弾 |
| 1027 | rain_area | 範囲エフェクト |
| 1044 | thunder_storm | 雷の演出 |
| 1062 | azure_wave | 波の演出 |
| 2077 | distortion_teleporter | テレポーター |
Asset/data/asset/functions/object/<番号>.<名前>/ で直接読める。
-
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 コストには気を配ること。 寿命カウンタで早めに削除するのも大事