728x90
※ 작성자도 MSW 초보자이므로 코드가 비효율적이거나 기술 구현이 많이 부족합니다!😅
구현 영상
동작 설명
- 게임에 처음 접속하는 플레이어(뉴비)일 경우, 인트로를 실행합니다.
- StartMap에서 IntroMap으로 플레이어 이동시킵니다.
- 플레이어를 자동 이동 시키며, 스토리에 대한 이해를 도울 대사를 대화창을 통해 주인공의 혼잣말 형식으로 보여줍니다.
- 인트로가 끝나면 StartMap으로 다시 이동시킵니다.
- 중간에 Skip 버튼 누를 시 인트로 기능이 중지됩니다.(자동 이동이 멈추고 대화창 꺼지며 StartMap으로 이동하게 됩니다.)
- 뉴비가 아니라면 접속 시 인트로가 실행되지 않습니다.
- 테스트 데이터를 초기화하고 다시 접속하면 뉴비로 인식되어 인트로 실행되는 것을 확인할 수 있습니다.
개선이 필요한 부분
- 자동 이동 시에 player 아바타가 자연스럽게 걸어가는 애니메이션을 하게 만들고 싶은데 실패..
- 대화창에 npc처럼 player Portrait로 쓸만한 이미지가 있으면 좋겠는데 이건 불가능할 듯
대화창을 나타내 줄 InfroUIGroup 추가
이 기능은 MapleStory Worlds-DEVELOPER의 Docs를 참고하여 만들었습니다.
Docs와 다른 점
'데이터 테이블 추가' 부분에서 데이터 테이블의 컬럼을 text 하나로 구성했습니다.
위의 docs와 다르게 인트로 구현 부분은 여러 명의 주체가 대화를 나누는 것이 아닌 주인공 혼잣말이라는 점, 주인공은 마땅히 사용할 수 있는 portrait가 없다는 점에서 name, portrait 컬럼 없이 text 컬럼만 생성했습니다.
이에 따라 데이터 테이블에서 정보를 가져와 대화창에 띄워주는 부분에서 코드 차이가 있습니다.
728x90
DefaultPlayer에 IntroComponent 추가
모든 코드 블록 첫 줄에 해당 코드가 어느 컴포넌트인지 쓰여 있습니다. 꼭 해당 코드가 어느 컴포넌트에 존재하는 코드인지 확인해주세요!
--IntroComponent Property --@ BeginProperty --@ SyncDirection=All string isNP = ""true"" --@ EndProperty --@ BeginProperty --@ SyncDirection=None any introTalkData = "nil" --@ EndProperty --@ BeginProperty --@ SyncDirection=None Entity uiNameEntity = "nil" --@ EndProperty --@ BeginProperty --@ SyncDirection=None Entity uiMessageEntity = "nil" --@ EndProperty --@ BeginProperty --@ SyncDirection=None Entity uiTalkPanel = "nil" --@ EndProperty --@ BeginProperty --@ SyncDirection=None Entity uiPortraitEntity = "nil" --@ EndProperty --@ BeginProperty --@ SyncDirection=None string startMap = """" --@ EndProperty
게임에 처음 접속한 플레이어만 인트로 재생
--IntroComponent --@ BeginMethod --@ MethodExecSpace=ServerOnly void isNewPlayer() { local userId = self.Entity.Name local userDS = _DataStorageService:GetUserDataStorage(userId) --userDS에서 isNewPlayer를 key값으로 가지는 value 가져오기 위한 CallBack 함수 local getCallBack = function(errorcode, key, value) --해당 key 값이 없으면 value에 nil이 들어감(뉴비란 소리이므로 value에 true 넣어줌 if value == nil then value = "true" end if key == "isNewPlayer" then self.isNP = value end end --한 번 접속한 플레이어이므로 isNewPlayer에 false 넣어주기 위한 CallBack 함수 local setCallBack = function(errorcode, key) self.isNP = "false" end userDS:GetAsync("isNewPlayer", getCallBack) --wait을 해주지 않으면 DataStorage를 가져오기 전에 뒤에 코드 실행됨(타이밍 이슈 발생) wait(1) --뉴비면 튜토리얼 실행 if self.isNP == "true" then log("튜토리얼 실행") --튜토리얼 실행 함수 self:playIntro() --DataStorage에 뉴비가 아니라는 데이터 넣어줌 userDS:SetAsync("isNewPlayer", "false", setCallBack) wait(3) end } --@ EndMethod
인트로 재생
--IntroComponent --@ BeginMethod --@ MethodExecSpace=Client void playIntro() { --IntroMap으로 이동(시작맵이 IntroMap이라면 없어도 됨) self:teleportToIntroMap() --wait이 없으면 맵 이동 후 캐릭터가 타일 위에 내려앉기 전에 움직이기 시작함. --(공중부양한 채로 움직이게 됨) wait(1) --대사 데이터 table 불러오기 self.introTalkData = _DataService:GetTable("IntroTalk") --대사창 ui entity들 불러오기 self.uiNameEntity = _EntityService:GetEntityByPath("/ui/IntroTalkGroup/TalkPanel/Name") self.uiMessageEntity = _EntityService:GetEntityByPath("/ui/IntroTalkGroup/TalkPanel/Text") self.uiTalkPanel = _EntityService:GetEntityByPath("/ui/IntroTalkGroup/TalkPanel") self.uiPortraitEntity = _EntityService:GetEntityByPath("/ui/IntroTalkGroup/TalkPanel/Portrait") --플레이어 이름 대사창에 띄우기 local name = _UserService.LocalPlayer.NameTagComponent.Name self.uiNameEntity.TextComponent.Text = name --플레이어가 오른쪽을 보게 함 self.Entity.PlayerControllerComponent.LookDirectionX = 1 --자동이동 self.Entity.IntroAutomaticMovementComponent.Enable = true self.uiTalkPanel.Enable = true --대화창 초상화 띄우는 entity --플레이어의 초상화는 따로 없으므로 enable=false로 해둠 self.uiPortraitEntity.Enable = false --대화를 3개만 지정해두어서 3까지만 for count = 1, 3 do --dataset에 넣어둔 대사 하나씩 불러오기 --GetCall 아님. GetC'e'll임.(주의) local message = self.introTalkData:GetCell(count, 1) --불러온 대사 대화창에 띄우기 self.uiMessageEntity.TextComponent.Text = message --대사 하나당 4초씩 보여주기 wait(4) --대사 끝났으면 if count == 3 then --대화창 끄고 self.uiTalkPanel.Enable = false --자동이동 멈추고 self.Entity.IntroAutomaticMovementComponent.Enable = false --플레이어가 다시 기본으로 왼쪽을 보게 함 self.Entity.PlayerControllerComponent.LookDirectionX = -1 --시작 맵으로 이동 self:teleportToStartMap() end end } --@ EndMethod --@ BeginMethod --@ MethodExecSpace=All void teleportToStartMap() { --처음 시작했던 맵으로 이동 --Vertor3에 이동하고 싶은 좌표 넣기 _TeleportService:TeleportToMapPosition(_UserService.LocalPlayer, Vector3(-6.473167, -0.4881773, 1), self.startMap) } --@ EndMethod --@ BeginMethod --@ MethodExecSpace=All void teleportToIntroMap() { --시작 맵 저장 후, 인트로맵으로 이동 --Vertor3에 이동하고 싶은 좌표 넣기 self.startMap = self.Entity.CurrentMapName _TeleportService:TeleportToMapPosition(_UserService.LocalPlayer, Vector3(-6.618879, -0.5888717, 1), "IntroMap") } --@ EndMethod
DefaultPlayer에 IntroAutomaticMovementComponent 추가
자동 이동
--IntroAutomaticMovementComponent --@ BeginMethod --@ MethodExecSpace=ServerOnly void OnUpdate(number delta) { local deltaX = 1 local pos = self.Entity.TransformComponent.Position pos.x = pos.x + deltaX * delta local deltaPos = Vector2(pos.x, pos.y) self.Entity.MovementComponent:SetPosition(deltaPos) } --@ EndMethod
참고 문서
MapleStory Worlds-DEVELOPER Docs의 엔티티 이동
스킵 버튼 추가

위와 같이 되도록 UI 버튼 생성
UI IntroTalkGroup 부모-자식 관계

스킵 버튼 활성화
--IntroComponent --@ BeginEntityEventHandler --@ Scope=All --@ Target=entity:4a02f0a7-c93c-4547-9a5f-66c0fb53dbf3 --@ EventName=ButtonClickEvent HandleButtonClickEvent { -- Parameters local Entity = event.Entity -------------------------------------------------------- log("Skip") self.uiTalkPanel.Enable = false --자동 이동 멈춤 self.Entity.IntroAutomaticMovementComponent.Enable = false --플레이어가 다시 기본으로 왼쪽 보게 함 self.Entity.PlayerControllerComponent.LookDirectionX = -1 --시작 맵으로 이동 self:teleportToStartMap() } --@ EndEntityEventHandler
728x90