【Roblox】ネットワーク所有権を操る
はじめに
こんにちは、まつさこ です。
Roblox Studioでは、通常 Workspace
に配置したPartを動かしたい場合、サーバースクリプトを使用する必要があります。
そのためプレイヤーのキー入力などで Workspace
内のPartを動かしたい場合、
- LocalScriptでプレイヤー入力を取得
- RemoteEventでサーバースクリプトにデータ送信
- サーバースクリプトでPartを動かす
という方法をとるのが一般的です。
しかしこの方法だと、ネットワーク環境によっては入力と動作に遅延が発生してしまい、プレイヤーの体験を損なってしまいます。
そこで今回は、Partのネットワーク所有権を適切に移譲することで、 ローカル環境での入力操作を遅延なく行うと同時に、プレイヤー間でPartが同期されている状態 を実現します。
実装方法
■ 手順1
まず Workspace
内にPartを配置してください。分かりやすいようにMyPartという名前にしておきます。
シンプルにPartを一つ配置。この後動かすので、Anchoredはfalseにしておきます。
■ 手順2
MyPartを ReplicatedStorage
に移動させます。
ゲームに参加したプレイヤーそれぞれが自分用のMyPartを操作できるように、サーバースクリプトでプレイヤー参加時にMyPartをクローンし、プレイヤーに紐づけるようにします。
CloneMyPart
… ServerScriptServiceにScriptとして作成
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local myPart = ReplicatedStorage:WaitForChild("MyPart")
local Players = game:GetService("Players")
local function CloneMyPart(player)
local clone = myPart:Clone()
clone.Name = "MyPart_"..player.Name
clone.Parent = workspace
end
-- すでにゲームにいるプレイヤーに対して実行
for _, player in pairs(Players:GetPlayers()) do
CloneMyPart(player)
end
-- 新しいプレイヤーが参加した時に実行
Players.PlayerAdded:Connect(CloneMyPart)
MyPart_ユーザー名 という名前のPartが Workspace 内に複製されていることが確認できます。
■ 手順3
ローカルスクリプトで MyPart_ユーザー名 を取得しWASDキーで操作できるようにします。
今回は、 VectorForce
を使って力を加えることで MyPart を動かします。
StarterPlayerScripts
に次のようなコードを作成します。
MyPartMover
local UserInputService = game:GetService("UserInputService")
local playerName = game.Players.LocalPlayer.Name
local myPart = workspace:WaitForChild("MyPart_"..playerName, 10)
-- MyPartにかける力の方向
local inputVector = Vector3.zero
local speed = 500
UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.KeyCode == Enum.KeyCode.W then
inputVector = inputVector + Vector3.new(0, 0, 1)
elseif input.KeyCode == Enum.KeyCode.S then
inputVector = inputVector + Vector3.new(0, 0, -1)
elseif input.KeyCode == Enum.KeyCode.A then
inputVector = inputVector + Vector3.new(1, 0, 0)
elseif input.KeyCode == Enum.KeyCode.D then
inputVector = inputVector + Vector3.new(-1, 0, 0)
end
end)
UserInputService.InputEnded:Connect(function(input, gameProcessedEvent)
if gameProcessedEvent then return end
if input.KeyCode == Enum.KeyCode.W then
inputVector = inputVector - Vector3.new(0, 0, 1)
elseif input.KeyCode == Enum.KeyCode.S then
inputVector = inputVector - Vector3.new(0, 0, -1)
elseif input.KeyCode == Enum.KeyCode.A then
inputVector = inputVector - Vector3.new(1, 0, 0)
elseif input.KeyCode == Enum.KeyCode.D then
inputVector = inputVector - Vector3.new(-1, 0, 0)
end
end)
-- MyPartを動かすためのBodyVelocityを追加
local A = Instance.new("Attachment", myPart)
local vF = Instance.new("VectorForce", myPart)
vF.Attachment0 = A
vF.ApplyAtCenterOfMass = true
vF.RelativeTo = Enum.ActuatorRelativeTo.World
vF.Force = Vector3.new(0, 0, 0) -- 初期速度は0
-- キー入力に応じてMyPartに力を加える
local function UpdateMoveDirection()
vF.Force = inputVector * speed
print(tostring(inputVector * speed))
end
game:GetService("RunService").Heartbeat:Connect(function()
UpdateMoveDirection()
end)
しかしこのままだと、MyPartを動かすことはできません。MyPartのネットワーク所有権がユーザーではなくサーバー側にあるためです。
物理挙動をするPartについて、誰がOwnerであるかをRobloxStudio上で可視化することが出来ます。
File > Studio Settings から、Physics > Are Owners Shown にチェックを入れてください。
自身のアバターは緑色でローカルプレイヤーがOwnerですが、MyPartは白色になっており、サーバーがOwnerであることが分かります。
■ 手順4
サーバースクリプトで対象のPartのネットワーク所有権をプレイヤーに移譲します。
CloneMyPart
スクリプトを次のように編集します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local myPart = ReplicatedStorage:WaitForChild("MyPart")
local Players = game:GetService("Players")
local function CloneMyPart(player)
local clone = myPart:Clone()
clone.Name = "MyPart_"..player.Name
clone.Parent = workspace
-- ネットワーク所有権をプレイヤーに移譲
clone:SetNetworkOwner(player)
end
-- すでにゲームにいるプレイヤーに対して実行
for _, player in pairs(Players:GetPlayers()) do
CloneMyPart(player)
end
-- 新しいプレイヤーが参加した時に実行
Players.PlayerAdded:Connect(CloneMyPart)
すると、MyPartのOwnerカラーが緑になり、WASDキーの入力でプレイヤーアバターと一緒に動くようになりました!
まとめ
今回は、ネットワーク所有権を操作することで、Workspace内のPartをプレイヤー入力で遅延なく操作する方法を紹介しました。
タッチ入力と組み合わせたり、乗り物の移動に応用したりすることで、よりゲームの幅が広がりそうですね!
読んでくださりありがとうございました🤗
Discussion