ゲームをインタラクティブにすることは、しばしばオブジェクトのプロパティと属性を操作することを意味します:
プロパティはオブジェクトクラスの一部です。たとえば、BasePart.Anchoredプロパティはパーツの物理挙動を制御します。トラックとフィールドのゲームでは、選手が円盤や槍が着地した瞬間にそれをアンカーして、どれだけの距離を移動したかを視覚的に示したい場合があります。
属性は本質的にあなたが定義するカスタムプロパティです。たとえば、Plantリファレンスプロジェクトは、シードの購入価格や鉢が保持できる最大の植物サイズを設定するために属性を使用しています。
レプリケーションの順序
オブジェクトを取得して操作を開始する前に、レプリケーションの順序についての理解が必要です。
Robloxエンジンは、オブジェクトとオブジェクトの変更がサーバーからクライアントにどの順序でレプリケートされるかを保証しないため、Instance:WaitForChild()メソッドは特にWorkspace内のオブジェクトにアクセスする際にクライアントスクリプトで不可欠です。
たとえば、サーバースクリプトがWorkspace内のいくつかのインスタンスのプロパティを変更し、その後RemoteEvent:FireAllClients()を呼び出すと、プロパティの変更はRemoteEvent.OnClientEventが発火する前または後にクライアントにレプリケートされる可能性があります。変更がレプリケートされたと仮定するのではなく、利用可能なメソッドやイベントを使用して変更を検出してください。同じタイプの変更、たとえば2つの属性の変更は、一般的に順番通りに到着します。
クライアントがゲームを最初に起動したとき、レプリケーションとスクリプト実行のいくつかの側面は予測可能です:
クライアントはReplicatedFirstの内容をロードします。この中には、ローディングスクリーン、アセット、スクリプトが含まれます。
LocalScripts(およびScriptsでRunContextがClient)がReplicatedFirstで実行されます。これらのスクリプトは、Instance:WaitForChild()を使用せずにReplicatedFirstから安全にオブジェクトを取得できます:
-- 安全local ReplicatedFirst = game:GetService("ReplicatedFirst")local LoadingScreen = require(ReplicatedFirst.LoadingScreen)これらのスクリプトは他のサービスからオブジェクトを安全に取得することはできません。なぜなら、それらがまだロードされていない可能性があるからです:
-- 安全でないlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage.PickupManager)これらのスクリプト内で他のサービスからオブジェクトを取得するためにWaitForChild()を使用することはできますが、そうするとReplicatedFirstを使用する利点が失われます。
クライアントはゲームの残りの部分をロードし続けます。
完了すると、Loadedイベントが発火し、IsLoaded()がtrueを返します。
Players.[Player].PlayerScripts内のLocalScripts(StarterPlayerScriptsからコピーされる)と、ReplicatedStorage内のクライアントScriptsが実行されます。これらのスクリプトは、ReplicatedStorageから安全にオブジェクトを取得できます。
プレイヤーのCharacterモデルがゲーム内にスポーンします。
Workspace.[Character]内のLocalScripts(StarterCharacterScriptsからコピーされる)が実行されます。
ゲームがインスタンスストリーミング(Workspace.StreamingEnabled)を使用している場合、いくつかまたはほとんどのオブジェクトがワークスペースにロードされていない可能性があるため、ワークスペースオブジェクトにアクセスするためにWaitForChild()を使用することは、さらに重要な安全対策となります。特に、ロードとストリーミング動作の調整に関する追加情報についてはストリームインとモデルごとのストリーミングコントロールを参照してください。
オブジェクトを取得する
オブジェクトのプロパティと属性を変更する最初のステップは、オブジェクトの参照を取得することです。最も簡単な解決策は、スクリプトをExplorer内のオブジェクトの子にして、script.Parentを使ってオブジェクトを参照することです。

local sign = script.Parent
より汎用的な解決策は、Instance:FindFirstChild()やInstance:WaitForChild()のようなメソッドを使用してサービスからオブジェクトを取得することです。

local ReplicatedStorage = game:GetService("ReplicatedStorage")local signsFolder = ReplicatedStorage:WaitForChild("Signs")local sign = signsFolder:WaitForChild("InteractiveSign")
プロパティを変更する
プロパティへのアクセスは簡単で、オブジェクト参照の後に.を使用するだけです — ただし、モデルで作業している場合は、モデル自体ではなく、個々のパーツを選択する必要があるかもしれません。

local ReplicatedStorage = game:GetService("ReplicatedStorage")local chair = ReplicatedStorage:WaitForChild("Chair")chair.LeftArmRest.Size = Vector3.new(10, 1, 10)
属性を作成する
属性はプログラム的に作成できますが、より一般的な解決策は、スタジオユーザーインターフェイスでデフォルト値を持つ属性を作成することです。その後、スクリプトを使用してプレイヤーのアクションに応じてその値を変更できます。

スタジオでの属性の作成に関する情報は、インスタンス属性を参照してください。
属性を設定する
属性の値を変更するには、Instance:SetAttribute()を名前と値で呼び出します。
属性の作成または変更local cabbage = script.Parentcabbage:SetAttribute("Harvestable", true)
属性が既に存在しない場合、このメソッドはそれを作成します。
属性の値を取得する
既存の1つの属性の値を取得するには、インスタンス上でInstance:GetAttribute()を呼び出します。
属性の値を取得local cabbage = script.Parentcabbage:SetAttribute("Harvestable", true)local isHarvestable = cabbage:GetAttribute("Harvestable")print(isHarvestable) --> true
同様に、Instance:GetAttributes()を呼び出すことですべての属性を取得できます。このメソッドはキーと値のペアの辞書を返します。
すべての属性を取得local cabbage = script.Parentlocal cabbageAttributes = cabbage:GetAttributes()print(cabbageAttributes.GrowthRate) --> 2for k, v in cabbageAttributes doprint(k, v)end
属性を削除する
属性を削除するには、その値をnilに設定します。
属性を削除local cabbage = script.Parentcabbage:SetAttribute("GrowthRate", nil)
変更を検出する
プロパティと属性への変更をリッスンする方法はいくつかあります:
- Instance.AttributeChangedイベントは、任意の属性の変更をリッスンし、変更された属性の名前をパラメータとして渡します。
- Instance:GetPropertyChangedSignal()メソッドを使用すると、1つのプロパティの変更をリッスンできますが、パラメータは渡しません。
- Instance:GetAttributeChangedSignal()メソッドを使用すると、1つの属性の変更をリッスンできますが、パラメータは渡しません。
これらのイベントとメソッドが渡すパラメータの情報が最小限であるため、すべては無名関数に適しています。特にInstance:GetPropertyChangedSignal()とInstance:GetAttributeChangedSignal()。無名関数とイベントの操作についての詳細は、イベントを参照してください。
変更をリッスン
local cabbage = script.Parent
-- ローカル関数
local function onAnyPropertyChange(property)
-- 属性の変更を無視
if property ~= "Attributes" then
print(property) --> 名前
print(cabbage[property]) --> キャベツ1
end
end
local function onAnyAttributeChange(attribute)
print(attribute) --> 成長, 成長率
print(cabbage:GetAttribute(attribute)) --> false, 3
end
-- 変更をリッスンし、ローカル関数に接続
cabbage.Changed:Connect(onAnyPropertyChange)
cabbage.AttributeChanged:Connect(onAnyAttributeChange)
-- 変更をリッスンし、無名関数に接続
cabbage:GetPropertyChangedSignal("Name"):Connect(function()
print(cabbage.Name) --> キャベツ1
end)
cabbage:GetAttributeChangedSignal("GrowthRate"):Connect(function()
print(cabbage:GetAttribute("GrowthRate")) --> 3
end)
-- ChangedとGetPropertyChangedSignal()を発火
cabbage.Name = "キャベツ1"
-- ChangedとAttributeChangedを発火
cabbage:SetAttribute("Grow", false)
-- Changed, AttributeChanged、およびGetAttributeChangedSignal()を発火
cabbage:SetAttribute("GrowthRate", 3)