Event
는 객체와 객체 간에 주고 받는 형식이다. MSW에서도 이벤트가 많이 사용되어 MSW에서는 Entity Event System
을 제공한다. Entity Event System
은 MSW에서 이벤트 시스템을 쉽게 활용할 수 있도록 기본적으로 제공하는 API이다.
Event
: 로직 상에서 사건의 발생을 의미 ( Event의 종류의 식별 정보, 추가 정보 소유 )Handler
: 해당 Event를 받았을 때 처리하는 행동의 주체Sender
: 해당 이벤트를 발송하는 객체LogEvent
는 우리가 이름 붙이는 Event
로, Log
간의 이벤트를 집어넣는데 사용될 예정이다.
Event
를 생성하는 과정이다.
각 엔티티들은 컴포넌트들을 포함하고 있다. 엔티티 이벤트 시스템은 다음과 같이 동작한다.
가장 먼저 컴포넌트는 각 엔티티를 중계자로 사용할 수 있으며, 각 컴포넌트는 엔티티를 통해 핸들러를 등록한다. ( 이벤트 발생 역시 엔티티를 통해 가능하다. )
Sender
역시 엔티티를 통해 이벤트를 발생하는 것이 가능하며, 이 때 엔티티는 Handler
들에게 해당 이벤트를 전송하는 역할을 한다.
정리를 해보자면, 어떤 Event
가 왔을 때 이것을 처리하는 부분을 Component
내의 로직에 넣는다.
그리고 이벤트 수신 등록을 Register
, AddListener
등으로 하며, MSW에서는 Entity
에 등록을 하는 구조이다.
Ex) Component1
에서 이벤트 발생 시, Component3
의 이벤트를 실행시키고 싶을 때를 가정한다.
두 Component
간에 연관이 없기 때문에 Component
에서 바로 호출하지 않고 엔티티를 통해 호출하는 구조이다.
Ex) RabbitEntity
쪽으로 이벤트를 쏘면 RabbitComponent
가 수신해서 RabbitComponent
안의 로그 메시지가 출력되는 구조이다.
이를 구현하는 방법은 두 가지 이다.
핸들러 로직이 이루어 지는 방법
- Entity Event Handler 추가
- 핸들러 상단 이벤트 중계자 설정
- 이벤트 처리 로직
HunterComponent
와, 해가 떴을 때 Hp를 감소시키는 VampireComponent
에 대한 예제 코드이다.Property :
[Sync]
boolean isSunrise = false
[Sync]
number Hp = 0
Method :
[server Only]
void OnUpdate (number delta)
{
if self.isSunrise == true then --해가 떴는지 체크한다.
self.Hp = self.Hp + delta --해가 떠 있을 동안 Hp가 증가한다.
log("Hunter Hp : "..self.Hp) --현재 체력을 Console 창에 표시한다.
if self.Hp >= 200 then self.Hp = 200 end --Hp가 200까지 증가했다면 증가를 멈춘다.
end
}
Entity Event Handler :
entity map01 (/maps/map01)
HandlerSunriseEvent(SunriseEvent event)
{
-- Parameters
local isSunrise = event.isSunrise
self.isSunrise = isSunrise
}
Property :
[Sync]
boolean isSunrise = false
[Sync]
number Hp = 0
Method :
[server Only]
void OnUpdate (number delta)
{
if self.isSunrise == true then --해가 떴는지 체크한다.
self.Hp = self.Hp - delta --해가 떠 있을 동안 Hp가 감소한다.
log("Vampire Hp : "..self.Hp) --현재 Hp를 Console 창에 표시한다.
if self.Hp < 0 then self.Hp = 0 end --Hp가 0까지 감소했다면 감소를 멈춘다.
end
}
Entity Event Handler :
Entity map01 (/maps/map01)
HandlerSunriseEvent(SunriseEvent event)
{
-- Parameters
local isSunrise = event.isSunrise
self.isSunrise = isSunrise
}
Property :
[Sync]
boolean isSunrise = false
Method :
[server only]
void OnUpdate (number delta)
{
if self._T.Time == nil then self._T.Time = 0 end
self._T.Time = self._T.Time + delta
if self._T.Time >= 5 then --5초마다 번갈아 해가 뜨고 진다.
self._T.Time = 0
if self.isSunrise == true then
self.isSunrise = false
else
self.isSunrise = true --해가 떠 있는 상태 외에 나머지 상태는 isSunrise가 false이다.
end
log(self.isSunrise)
self:SendEvent(self.isSunrise)
end
}
[server]
void SendEvent (boolean isSunrise)
{
local event = SunriseEvent()
event.isSunrise = isSunrise
self.Entity:SendEvent(event)
self.isSunrise = isSunrise
self._T.Time = 0
}
완성된 컴포넌트를 map에 AddComponent
를 통해 등록시켜준 후 이벤트 호출을 위한 로직을 추가해준다. 실습 강의의 경우 HunterComponent
에 HandleKeyDownEvent
를 추가해주었고, Z 키보드 사용 시 이벤트가 호출되도록 하였다.
Property :
[Sync]
boolean isSunrise = false
Method :
[server only]
void OnUpdate (number delta)
{
if self._T.Time == nil then self._T.Time = 0 end
self._T.Time = self._T.Time + delta
if self._T.Time >= 5 then --5초마다 번갈아 해가 뜨고 진다.
self._T.Time = 0
if self.isSunrise == true then
self.isSunrise = false
else
self.isSunrise = true --해가 떠 있는 상태 외에 나머지 상태는 isSunrise가 false이다.
end
log(self.isSunrise)
self:SendEvent(self.isSunrise)
end
}
[server]
void SendEvent (boolean isSunrise)
{
local event = SunriseEvent()
event.isSunrise = isSunrise
self.Entity:SendEvent(event)
self.isSunrise = isSunrise
self._T.Time = 0
}
_SpawnService
를 제공해준다.SpawnByEntityTemplate
: 배치된 엔티티와 동일한 엔티티를 생성하는, 엔티티를 복제해주는 역할을 수행
--void SpawnByEntityTemplate()
--SpawnByEntityTemplate의 파라미터값들을 설정한다.
local entityTemplate = _EntityService:GetEntityByPath("/maps/map01/object-49_1") -- 맵에 배치한 엔티티를 받아옵니다. 워크스페이스 -> 엔티티 -> 우클릭 -> Copy Entity Path로 패스를 가져올 수 있습니다.
local name = entityTemplate.Name .. "Copy" -- 생성될 엔티티의 이름을 설정한다.
local spawnPosition = Vector3(0,0,0) -- 생성될 때의 위치 좌표를 설정한다.
local spawnedEntity = _SpawnService:SpawnByEntityTemplate(entityTemplate, name, spawnPosition)
--스폰한 엔티티를 변수로 받으면, 해당 엔티티에 대한 후처리를 할 수 있다.
if isvalid(spawnedEntity) == false then log("Spawn Failed") end
SpawnByModelId
: 워크스페이스에 추가된 모델 중 한가지 모델을 지정해 엔티티를 생성해 주는 함수
-- void SpawnByModelId()
--SpawnByModelId의 파라미터값들을 설정한다.
local id = "maplestorymapobject$002be76"
-- 워크스페이스 -> Model 하위에 추가된 모델이 있으며,
-- 모델 -> 우클릭 -> Copy Model ID로 ID를 복사해서 가져올 수 있다.
-- 앞에 "model://"은 제거해준다.
local name = "SpawnedEntity" -- 생성될 엔티티의 이름을 설정한다.
local spawnPosition = Vector3(0,0,0) -- 생성될 때의 위치 좌표를 설정한다.
local parent = _EntityService:GetEntityByPath("/maps/map01") -- 생성될 엔티티의 부모 엔티티이다.
local ownerId = nil -- 엔티티의 소유권을 가질 플레이어의 ID(Name)를 넣어준다. 일반적으로 nil로 설정한다.
local spawnedEntity = _SpawnService:SpawnByModelId(id, name, spawnPosition, parent, ownerId)
--스폰한 엔티티를 변수로 받으면, 해당 엔티티에 대한 후처리를 할 수 있다.
if isvalid(spawnedEntity) == false then log("Spawn Failed") end
_EntityService:Destroy
또는 Entity:Destroy
를 제공해주며, 삭제하고자 하는 엔티티를 위와 같이 지정해 삭제해줄 수 있다.--void OnUpdate(number delta) [server only]
if isvalid(self.SpawnedEntity) == false then return end
if self._T.time == nil then self._T.time = 0 end
self._T.time = self._T.time + delta
if self._T.time >= 3 then
_EntityService:Destroy(self.SpawnedEntity)
end
--void OnUpdate(number delta) [server only]
if isvalid(self.SpawnedEntity) == false then return end
if self._T.time == nil then self._T.time = 0 end
self._T.time = self._T.time + delta
if self._T.time >= 3 then
self.SpawnedEntity:Destroy() --_EntityService:Destroy 대신 Entity:Destroy로 교체.
end
isvalid
를 사용해 유효성을 체크한다.--void OnUpdate(number delta) [server only]
if isvalid(self.SpawnedEntity) == false then return end
if self._T.time == nil then self._T.time = 0 end
self._T.time = self._T.time + delta
if self._T.time >= 3 then
self.SpawnedEntity:Destroy() --_EntityService:Destroy 대신 Entity:Destroy로 교체.
end