몇 개의 스크립트를 만든 후에는 코드를 재사용하기 전에 오래 걸리지 않습니다.위치에 따라 위치 에 따라 ModuleScripts 클라이언트-서버 경계의 다른 쪽이나 경계의 동일한 쪽에서 스크립트 간에 코드를 재사용할 수 있습니다.
스크립트를 넣을 수 있는 곳은 어디든지 스크립트를 넣을 수 있지만, ReplicatedStorage는 인기 있는 위치입니다; 여기에 모듈 스크립트를 저장하면 서버와 클라이언트 사이에서 코드를 재사용할 수 있습니다.
모듈 스크립트의 해부학
Roblox Studio에서 ReplicatedStorage 에 모듈 스크립트를 추가하고 PickupManager로 이름을 바꾸십시오. 각 ModuleScript는 다음 코드로 시작합니다:
local module = {}return module
이 코드는 빈 Luau 테이블을 생성하고 모듈 스크립트가 필요한 모든 스크립트에 반환합니다.
반환 값은 데이터 유형 을 제외하고 nil 외에는 모든 모듈 스크립트가 함수, 테이블 또는 함수 테이블을 반환합니다.반환 값을 생성하려면 모듈 스크립트는 물론 다른 모듈 스크립트를 요구하는 임의의 코드를 실행할 수 있습니다.
다음 예제에서는 getPickupBonus라는 단일 함수가 있는 테이블을 반환합니다. 새 모듈 스크립트에 붙여넣습니다.
-- ReplicatedStorage의 ModuleScript
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- PickupManager 테이블에 getPickupBonus 함수 추가
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
함수를 테이블에 추가하는 것은 엄격히 필요하지 않으며, 함수 자체를 반환할 수도 있지만, 팔로우할 좋은 패턴입니다. 다른 스크립트에서 함수를 호출할 때 이해하기 쉬운 구문을 반환하고 시간이 지남에 모듈 스크립트에 더 많은 함수를 쉽게 추가할 수 있습니다.
모듈 스크립트 요구
모듈 스크립트를 로드하려면 require() 함수를 호출합니다.에서 ReplicatedStorage , 새 스크립트를 추가하고 해당 RunContext 를 Client 로 변경합니다.그런 다음 PickupManager.getPickupBonus 함수를 호출하기 위해 다음 코드를 추가하십시오:
ReplicatedStorage의 클라이언트 스크립트
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- ModuleScript에서 반환된 값 가져오기local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- 모듈 스크립트 함수 호출local bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
스토리지 모듈 스크립트를 ReplicatedStorage 저장하면 서버와 클라이언트 간에 코드를 공유할 수 있어 동일한 코드를 사용하여 스크립트를 요구할 수 있습니다: ServerScriptService :
ServerScriptService의 스크립트
local ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
Global.LuaGlobals.require()``Class.ModuleScript 호출하면 한 번 실행되어 참조로 단일 항목을 반환합니다.다시 호출하면 정확히 동일한 참조가 반환되어 반환된 테이블 또는 을 수정하면 후속 호출에서 해당 수정된 참조가 반환됩니다.모듈 자체는 여러 번 실행되지 않습니다.
위의 예와 같이 클라이언트-서버 경계의 양쪽에서 ModuleScript 가 필요한 경우, ModuleScript 는 각 측면에 대해 고유한 참조를 반환합니다.
패턴
모듈 스크립트에는 코드를 단순화하고 규모와 복잡성이 증가함에 따라 함정을 피하기 위해 사용할 수 있는 몇 가지 일반적인 패턴이 있습니다.
데이터 공유
데이터를 개별 객체와 연결하려면, 그들에게 특성을 할당하거나 Configuration 값 객체(예: StringValue 또는 IntValue)로 폴더를 생성하여 값 객체를 만들 수 있습니다.그러나 수십 개의 개체 또는 데이터 값을 추가하거나 수정하려는 경우 두 접근법 모두 문제가 됩니다.또한 테이블이나 함수를 저장하지 않습니다.
동일한 개체의 여러 복사본에 대해 동일한 데이터를 수정하거나 다른 개체에 대해 동일한 데이터를 재사용하려는 경우 ModuleScripts에 데이터를 저장하십시오.다른 스크립트에서 데이터를 재사용하는 더 쉬운 방법이며 테이블과 함수를 저장할 수 있습니다.
다음 예제 ModuleScript 에서 ReplicatedStorage 에 일반적인 총에 대한 구성 값이 저장됩니다.
ReplicatedStorage의 ModuleScript
local GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
사용자 지정 이벤트
사용자 지정 이벤트는 스크립트가 서로 통신할 수 있게 하지만, 개별 BindableEvent 개체에 대한 참조를 추적해야 하므로 코드가 복잡해질 수 있습니다.
ModuleScripts를 사용하여 BindableEvents를 저장하고 ModuleScript의 메서드에 직접 연결되는 사용자 지정 이벤트 처리기를 제공할 수 있습니다.
다음 에서 스위치가 상태를 변경할 때 실행되는 사용자 지정 이벤트가 있습니다:
ReplicatedStorage의 ModuleScript
local Switch = {}
-- 스위치가 변경될 때 모든 스크립트가 수신할 수 있도록 바인딩 생성하기
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
다음 클라이언트 스크립트는 ReplicatedStorage 에서 발생하는 Switch.Changed 이벤트에 호출할 함수를 연결합니다.
ReplicatedStorage의 스크립트
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Switch state is now", newState)
end
-- 몇 번 뒤집기 테스트
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
캡슐화
캡슐화는 복잡성을 숨기기 위해 개체 또는 스크립트 논리 주위에 추상화 레이어를 만드는 방법입니다.코드를 간소화하기 위해 ModuleScripts를 사용하여 Roblox 개체를 사용자 지정 Luau 함수로 캡슐화할 수 있습니다.
예를 들어, 캡슐화를 사용하여 다음을 수행할 수 있습니다.
- 단일 RemoteEvent 개체로 교차 네트워크 통신을 간소화합니다.
- 오류 처리 코드를 DataStoreService와 같은 민감한 서비스에 감싼다.
- Roblox 개체 기능을 제어하거나 확장하기 위한 사용자 지정 메서드를 정의합니다.
게임에 네트워킹을 구현하기 위해 수십 개의 개별 RemoteEvent 개체를 추적하는 것은 어렵습니다.이 문제를 단순화하기 위해 단일 ModuleScript를 캡슐화하기 위해 RemoteEvent을 사용할 수 있습니다.고유한 id 인수를 포함하여 단일 RemoteEvent 만 사용하면서 여전히 다른 네트워크 메시지를 보낼 수 있습니다.
아래 예제에서 ModuleScript라는 이름의 NetworkManagerClient 메서드는 이 추가 RemoteEvent:FireServer() 인수를 포함하기 위해 id 메서드를 캡슐화합니다.또한, 이 ModuleScript 는 RemoteEvent 개체 자체를 참조하므로 코드의 다른 부분에서 참조할 필요가 없습니다.네트워크 메시지를 보내기 위해 이 ModuleScript 만 요구하고 코드베이스의 나머지에 있는 RemoteEvent 개체를 처리할 필요가 없습니다.
다음 에서 클라이언트 스크립트에 전송할 네트워크 메시지를 보낼 수 있는 캡슐화된 함수를 제공합니다.
네트워크 모듈
-- NetworkManagerClient라는 이름의 ReplicatedFirst 내 ModuleScript
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- 원격 개체의 FireServer 함수 캡슐화
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
다음 ModuleScript 에서 ServerScriptService 는 모든 스크립트가 특정 ID에 연결하도록 BindableEvents 을 사용합니다.클라이언트가 네트워크 메시지를 보낼 때, 지정된 ID와 연결된 각 BindableEvent가 발생합니다.
-- NetworkManagerServer라는 이름의 ServerScriptService 내 ModuleScript
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- 새로운 BindableEvent를 id에 연결
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- 연결 중
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- 받은 원격 이벤트의 ID와 일치하는 모든 바인딩 가능한 이벤트 찾기
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
다음 LocalScript 는 선택적인 RequestA 인수로 ID Hello 메시지를 보냅니다.
-- ReplicatedFirst의 LocalScriptlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
다음 Script 는 네트워크 메시지 ID RequestA 에 연결하고 요청을 받을 때 추가 매개변수와 함께 문을 출력합니다.
-- ServerScriptService의 스크립트
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Received RequestA from", player, ...)
end)