Event와 컴포넌트 확장
event는 객체와 객체간에 주고 받는 형식. mod에서도 이벤트가 많이 사용됨.
mod에서는 entity event system(mod에서 이벤트 시스템을 쉽게 활용할 수 있도록 기본적으로 제공하는 API)을 제공.
evnet 3가지 구성요소
event: 로직 상에서 사건의 발생을 의미(event의 종류의 식별 정보, 추가 정보 소유)
handler: 해당 event를 받았을때 처리하는 행동의 주체
sender: 해당 이벤트를 발송하는 객체
event 시스템의 장단점
장점
- 다른 component나 기능 단위에서 결합성이 떨어짐.
- 행위에 대한 액션 추가 희망시 행위 수행하는 곳 수정 없이 추가 가능.
- 다른 compoenent의 정보를 필요로 하지 않음.
단점
- 사건 발생 시 전체적 플로우 찾기 어려움( 각각 처리하는 로직으로 인해 실행되는 시점에서 알 수 없음)
- 디버깅이 어려움
- 순차적 행위 수행이 어려움
Log event
우리가 이름 붙이는 event로 log 간의 이벤트를 집어 넣는데 사용될 예정임
event 생성하는 과정
1.LogEvent 객체 생성
2.Logevent에 message property생성
3.myComponent 생성 및 Handler와 function 추가
log로 이벤트를 주고 받는 과정
1.자신이 엔티티 쪽으로 이벤트를 쏨
2.로그 이벤트 받겠다는 핸들러 -> 자신의 엔티티쪽으로 등록
핸들러 등록 구조
각 엔티티들은 컴포넌트들을 포함하고있음.
엔티티 이벤트 시스템은 이와같이 작동함.
컴포넌트는 각 엔티티를 중계자로 사용할 수 있으며, 각 컴포넌트는 엔티티를 통해 핸들러를 등록함.
이벤트 발생 역시 엔티티를 통해 가능
sender역시 엔티티를 통해 이벤트를 발생하는 것이 가능하며 이때 엔티티는 handler들에게 해당 이벤트를 전송하는 연락을 함.
정리
어떤 event가 왔을때 이것을 처리하는 부분을 component내의 로직에 넣음. 그리고 이벤트 수신 등록을 register,addlistener등으로 하며, mod에서는 entity에 등록을 하는 구조.
이벤트를 주고 받을때
- 같은 엔티티에서 이벤트를 주고받을때
예를들어 component1에서 이벤트 발생시, component3의 이벤트를 실행시키고 싶을 때를 가정. 두 component간에는 연관이 없어서 component에서 바로 호출하지않고 엔티티를 통해 호출하는 구조.
1.compoenent1이 특정 타이밍에 의해 엔티티로 발송
2.로그 이벤트를 수신하겠다고 등록한 컴포넌트들에게 이벤트 발송
3.해당 컴포넌트들은 이벤트를 받아서 처리
- 다른 엔티티에서 이벤트를 주고 받을때
예를들어rabbitentity쪽으로 이벤트를 쏘면
rabbitcomponent가 수신해서 rabbitcomponent안의 로그 메시지가 출력되는 구조
1.신호를 보내는 엔티티쪽에서 component들이 이벤트 발송
2.받는 엔티티 쪽에서 신호를 받고 이벤트 수행
이를 구현하는 방법
1 번째 방법
1.rabbitcomponent에서 로그 이벤트 등록
2.mycomponent에서 rabbitentity쪽으로 로그 이벤트 발송 등록
2번째 방법
1.rabbitcomponent에서 로그 메시지 핸들 이벤트와 출력 등록(이때 beerentity로 이벤트 발송 등록 x)
2.beercomponent 에서 등록한 로그 이벤트를 rabbitentity로 보내 로그 출력
이렇게 우리는 분리되어있는 환경에서 통신을 할 수 있게 해주는 것을 event라고 함.
이벤트 처리
이벤트 처리 순서는
1.이벤트를 처리할 컴포넌트, 엔티티 생성
2. 핸들러 로직 추가 (핸들러 로직이 이루어지는 방법: entity event handler추가 -> 핸들러 상단 이벤트 중계자 설정 -> 이벤트 처리 로직)
3. 이벤트 발생 로직 추가
해가떴을때 hp를 증가시키는 huntercomponent
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
}
해가 떴을때 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("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키보드 사용시 이벤트 호출되도록함.
--HandleKeyDownEvent(KeyDownEvent event) [service : InputService]
-- Parameters
local key = event.key
--------------------------------------------------------------------------------
if key == KeyboardKey.Z then --Z 키를 누르면 `일출` 메시지가 Console 창에 나타납니다.
log("일출")
local timeManager = self.Entity.CurrentMap.TimeManager
timeManager:SendEvent(true) --Timemanager Component의 Event가 true가 되도록 이벤트를 발생시킵니다.
end
entity
엔티티 생성
mod에서는 엔티티를 생성할수 있는 함수인 _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
엔티티 삭제
mod에서는 엔티티를 삭제 할 수 있는 함수인 _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
엔티티 유효성 체크
mod에서는 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
local isvalidValue = isvalid(self.SpawnedEntity)
log("삭제 전 : "..tostring(isvalidValue)) -- 콘솔 창에 "삭제 전: true" 출력
self.SpawnedEntity:Destroy()
isvalidValue = isvalid(self.SpawnedEntity)
log("삭제 후 : "..tostring(isvalidValue)) -- 콘솔 창에 "삭제 후: false" 출력
end
'NEXON_SUPER_HACKATHON' 카테고리의 다른 글
MOD project 12 -NEXON (0) | 2022.07.20 |
---|---|
MOD project 11 -NEXON (0) | 2022.07.20 |
MOD project 9 -NEXON (0) | 2022.07.19 |
MOD project 8 -NEXON (0) | 2022.07.19 |
MOD project 7 -NEXON (0) | 2022.07.19 |