본문 바로가기

로블록스 개발에 필요한 전반적인 내용들

로블록스 개발 - 이벤트 처리하기

로블록스에서는 기본적으로 콜백 처리를 수행하기 위한 방식으로 이벤트를 사용한다. 버튼을 클릭하거나 특별한 일이 게임내에 일어났을 때, 유저가 게임에 접속했을 때 등등에서도 이벤트를 통해 처리된다. 그리고 서버 클라이언트와의 통신에서도 이벤트를 사용하게 된다.

 

이벤트가 일어 날때까지 기다리는 방식과 이벤트를 기다리는 방식과 함수에 이벤트를 연결하는 방식이 있다.

이벤트를 기다리는 방식

Wait() 함수는 해당 이벤트가 일어날 때까지 멈춰버리는 역할을한다. 해당 이벤트가 발생하면 멈춤은 풀리고 다음으로 넘어가게 된다. 방식으로 봤을때, 단 한번만 수행됨을 알 수 있다.

아래 코드는 myPart에 Touched 이벤트가 발생되기를 기다렸다가, 발생했을 때, 출력문이 출력되는 모습을 보여준다.

Wait()함수의 결과 값으로 충돌된 객체가 반환된다.

-- 이벤트가 일어나기를 계속 기다림.
local myPart = game.Workspace.Part
-- "myPart"에 다른 파트가 충돌되기를 계속 기다림.
local otherPart = myPart.Touched:Wait() 
print("Part was touched by: " .. otherPart.Name)

함수에 연결하는 방식

Connect() 함수는 해당 이벤트와 특정 함수를 연결해준다.  함수에 연결되는 이벤트는 이벤트가 발생할 때마다 함수가 호출된다. 아래 코드는 Touched 이벤트가 발생할 때 마다 Touched 이벤트에 연결된 onTouched 함수를 호출한다. 이 번에는 Wait() 함수와 달리 연결된 함수의 파라메타로써 충돌한 객체를 전달해 준다. 거의 모든 이벤트에서 그 해당 이벤트가 발생하게 된 원인 객체를 연결된 함수의 파라메타로 보내준다. 이 경우는 otherPart가 Touched 이벤트의 원인 객체이므로 otherPart가 파라메타가 된다.

local myPart = game.Workspace.Part

-- 이 함수는 myPart 객체의 Touched 이벤트가 발생할때마다 호출된다.
local function onTouched(otherPart)
  print("Part was touched by: " .. otherPart.Name)
end

-- 이벤트를 함수에 연결.
myPart.Touched:Connect(onTouched)

이벤트와 함수의 연결 끊기

이벤트와 연결된 함수는 언젠가는 더 이상 호출할 필요가 없어질 때가 온다. 게임을 끝내게 될때도 그렇고... 아니면 연결된 함수 말고 다른 함수로 교체할 수도 있다. 연결을 끊는 방법은 연결 객체의 Disconnect() 함수를 이용한다.

연결 객체는 Connect() 함수의 반환값으로 오기 때문에 받아 뒀다가 사용하면 된다.

local points = Instance.new("NumberValue")
points.Name = "Points"
points.Value = 0
 
local connection
 
local function onPointsChanged(newPoints)
  print("Points: " .. newPoints)
  if newPoints >= 50 then
    -- 포인트가 50이상이면 더이상 이벤트 함수의 연결 끊기.
    connection:Disconnect()
  end
end

-- 반환된 연결 객체(connection)은 나중에 Disconnection()에 사용된다.
connection = points.Changed:Connect(onPointsChanged)
 
-- Trigger some changes
points.Value = 25 -- Points: 25 가 출력됨
points.Value = 100 -- Points: 100 가 출력됨
points.Value = 0 -- 11줄에서 Disconnect()되어서 더이상 onPointsChanged()에 호출되지 않음. 출력값 없음

Disconnect()함수는 더 이상 이벤트에 연결함수가 필요없을때면 언제든지 사용하면 좋다. 연결된 이벤트와 함수는 게임 리소스를 잡아먹기 때문이다. 하지만, 연결된 이벤트 함수를 계속 신경쓰는 것도 가성비가 떨어지는 작업이다. 왜냐면 결국, 객체가 소멸되면 객체에 연결된 이벤트 함수도 다 끊어지고 사라지기 때문이다. 보통은 특수한 상황에서 특별하게 많은 이벤트 함수를 연결한 객체를 다루게 될 때, 필요한지 여부를 잘 생각해서 끊어주면 좋을 것이다.

이벤트 연결 중첩해서 사용하기

이벤트 연결 함수는 중첩이 가능하다. 대표적인 예로는 게임에 접속한 캐릭터 정보에 접근하기 위한 코드이다. Players 서비스의 PlayerAdded 이벤트에 연결된 함수의 파라메터로 전달된 player객체. 그리고 그 player 객체의 CharacterAdded 이벤트와 연결 함수의 파라메터로 전달된 character 객체를 통해, 접속한 캐릭터 정보에 접근할 수 있다.

-- Player 서비스 불러오기
local Players = game:GetService("Players")
 
local function onPlayerAdded(player)
  -- 이 부분은 PlayerAdded 이벤트를 통해 호출된다.
  local function onCharacterAdded(character)
    -- 이 부분은 CharacterAdded 이벤트를 통해 호출된다.
    print(player.Name .. " spawned in: " .. character:GetFullName())
  end
  -- player 객체의 CharacterAdded 이벤트와 로컬 함수 onCharacterAdded를 연결.
  player.CharacterAdded:Connect(onCharacterAdded)
end

-- Players 서비스 객체의 PlayerAdded 이벤트와 onPlayerAdded 연결.
Players.PlayerAdded:Connect(onPlayerAdded)

내가 커스텀 이벤트를 만들 수 없나?

때때로 게임을 만들다보면, 필요한 이벤트가 객체에 없는 경우가 있을 수 있다. 코드를 통해 설명을 해보자. 아래의 코드는 Red Team이 성과를 달성했을 때, onGoalScored 함수에 연결하는 모습을 보여준다. 성과를 달성했다는 것은 게임내 특정 점수를 얻었을 상황도 될 수 있고 비밀 루트를 찾았을 때 등등, 뭐가 됐든 개발자가 상상하는 상황을 의미한다. 이렇게 미리 정의되지 않은 이벤트는 BindableEvent 객체를 통해 구현된다. BindableEvent 객체에 정의된 Event 라는 이벤트를 통해 함수를 연결해 놓는다. 그리고 개발자가 스스로 이벤트의 발생을 알려줘야 한다.  미리 로블록스 내에 정의된 이벤트가 아니므로 언제 어떻게 이벤트가 발생하는지는 로블록스가 알려 줄수가 없기 때문이다. 이 custum 이벤트의 발생은 BindableEvent 객체의 Fire() 함수를 통해 이루어진다.

즉, 커스텀이벤트와 함수를 연결하기 위해서는 

  1. BindableEvnet 객체를 생성한다.
  2. BindableEvent 객체의 Event와 함수를 연결한다.
  3. BindableEvent 객체의 Fire() 함수를 호출하여 커스텀 이벤트를 발생시킨다.
-- BindableEvnet 객체를 생성한다.
local beGoal = Instance.new("BindableEvent")
 
-- BindableEvnet 객체와 연결될 함수
local function onGoalScored(team)
  team.Score = team.Score + 1
end
 
-- BindableEvent 객체의 Event와 함수를 연결한다.
beGoal.Event:Connect(onGoalScored)
-- 이 코드 블럭은 게임내에서 이벤트를 발생시키고 싶은 코드에 삽입된 것으로 가정함
local Teams = game:GetService("Teams")
local redTeam = Teams["Red Team"]
-- BindableEvent 객체의 Fire() 함수를 호출하여 커스텀 이벤트를 발생시킨다.
beGoal:Fire(redTeam) -- Fire() 함수의 파라메터로 이벤트 발생 원인이 되는 redTeam을 보낸다.

서버 클라이언트간의 통신에서의 이벤트

로블록스에서 클라이언트 서버간의 통신하기 위해서는 RemoteEvent와 RemoteFunction 을 사용한다. 

RemoteEvent를 사용하여 클라이언트 서버간에 어떻게 통신 이루어 지는지에 대한 내용은 아래의 링크를 참고.

2021.04.23 - [로블록스 개발에 필요한 전반적인 내용들] - 로블록스의 클라이언트 서버 통신에 대하여 (1)