공중에서 도약하기

 

도약하는 원리

rigidbodyComponent안에 SetForce라는 함수가 숨겨져있는데 이 함수를 이용하면 rigidbodyComponent를 가진 객체를 원하는 방향으로 힘을 가할 수 있음.(공중에서 leftalt 라는 keydownevent가 발생하면 RigidbodyComponent:SetForce(Vector2(x방향,y방향)로 중력을 조절하면 밑으로 떨어지지 않고 점프를 할 때마다 위로 둥둥 뜨게 할 수 있음.)

 

setforce함수의 위치

해당 ComponentPlayer가 장애물 피하기 맵의 공중에서 LeftAlt키 입력시 해당 방향으로 점프되게끔 하기 위해서 Component를 새로 만들어서 이름을 설정해주었고, Entity Event Handler에서 KeyDownEvent를 눌렀을 때 해당 이벤트가 발생할 때의 상황을 처리해주는 방식으로 중력을 조정함.

 

 

handlekeydownevent사용방법

해당 Entity Event Handler: 에서 ‘+’ 를 누른다음, KeyDownEvent를 눌러 해당 이벤트가 발생할 시 상황은 다음과 같이 처리.

Component의 목적은 공중에서 LeftAlt 키를 누를시 위로 뛰어오르게끔 연출하는 것이므로 위에 Property에서 설정했듯이 Mode = “Avoid_Obstacle” 즉 장애물 피하기 모드일경우에만 해당 처리가 하도록 if문을 통해 만들어주었음. 그 뒤 점프시에 카메라가 바로 따라가줘야 장애물을 보고 피할 수 있으므로_UserService.LocalPlayer.CameraComponent.Damping.x(y) (카메라 반응속도)를 짧게 낮춰 카메라가 플레이어를 빠르게 따라갈 수 있도록 설정해준 코드임.

KeyDownEvent의 parameter로 key가 들어오므로. key == KeyboardKey.LeftAlt를 통해 LeftAlt가 눌릴경우를 확인해주고 _UserService.LocalPlayer.PlayerControllerComponent.LookDirectionX (플레이어가 왼쪽을 바라보면 -1, 오른쪽을 바라보면 +1)이 나오는것을 통해 바라보는 방향의 상단쪽으로 힘을 가해 공중에서 도약하는것처럼 연출해줌.

 

 

떨어지는 장애물 만들기

 

장애물에 중력을 부여하는 원리

"중력"을 부여해여하는데 이 중력을 부여 하려면 중력값을 가지도록 하는 ComponentRigidbodyComponent를 해당 장애물에 추가를 해줘야한다. 또한, 장애물이 그저 중력만 갖고있다면 떨어지다가 Tile과 만나면 그대로 멈추고 아무 동작을 하지 않아야하며 장애물이 바닥에 떨어지고 다시 위로 respawn 되어 떨어지게 만들어야 한다.

따라서 Trap이 떨어지는 Trap_Falling_Component를 만들어 장애물에 추가해주고 위의 내용을 작업해줘야함.

 

장애물 위치에 따라 해당 entity y좌표 설정하기

 

해당 장애물이 특정 y좌표보다 아래로 떨어지게 될 경우 자신이 설정한 바닥의 y좌표보다 조금 높게 설정해준다. (해당 Entity를 다시 위로 옮겨주면 된다. )

Position.y 가 지정한 y좌표보다 더 낮게 진행될 경우 MovementComponent:SetPosition을 통해 올려준다.

이 때 MovementComponent:SetPosition을 사용하기 위해서는 장애물 엔티티에 MovementComponent를 추가해 주어야한다.

 

장애물 구현할때 tip!

 

장애물이 매번 같은 라인에서 같은 주기로 떨어지게 된다면 굉장히 난이도가 쉬워진다.

math.random 함수를 이용해 x좌표를 좌우로 바꾼다.

또 주기를 바꾸기 위해 wait(math.random())을 통해 period 또한 바꿔준다.

그러면 다양한 타이밍에 다양한 장소로 스폰되어 다시 떨어지게 된다.

 

떨어지는 것을 방지하기 위해

1. RigidbodyComponent의 Gravity를 잠시 0으로 바꾼 뒤

2. wait()함수를 통해 랜덤한 시간을 대기하게 하고

3. 다시 Gravity를 적절하게 맞추어 떨어지게끔 연출한다.

 

충돌 기능 구현하기

 

장애물에 맞으면 hp가 감소하고, hp가 0이될시 플레이어 상태를 조정하게 만들어야함.

충돌기능은 triggercomponent가 이미 존재하고 있으므로 이것을 확장시켜 새로운 component인 trap_trigger_component를 제작한다. 

component를 새로 만들었다면 먼저 해당 trap의 데미지를 조정할 수 있도록 propertydamage를 넣어줌. 

작동로직

 

TriggerEvent가 발생→ 해당 TriggerEvent가 발생한 대상이 Player인지 확인 → (맞을 시) 플레이어의 Hp - Trap의 데미지가 0보다 클 때 : HP만 감소, 0보다 작거나 같을 때 : 플레이어 사망 및 5초후 부활 설정

 

TriggerEvent 발생 시 충돌 기능 구현하기

 

Trigger Event 발생시, 대상이 Player인지 확인해준다.

if문을 통해 TriggerBodyEntity의 IDPlayer의 ID와 맞는지 확인

Trigger Event가 발생했을 때, player가 잠깐 장애물과 떨어진 후, 키 입력을 하면 동시에 2번의 Trigger Event가 발생해 Hp가 2배로 차감되는 경우가 생길 수 있음.

 mydesk→  create scripts→ create component Take_Damage_Component 생성.

DefaultPlayer의 Property에 방금 만든 Take_Damage_Component를 추가시키고 Property에 boolean take_damage_period =true  를 통해, 현재 player가 period가 참일 경우에만 Trap과 충돌하여 hp가 깎이도록 구현하기.

Trap_Trigger_Component로 다시 돌아가서

player에게 take_damage_period가 true값을 가지고 현재 플레이어의 hp- trap이 가지고있는 데미지 값이 0보다 작거나 같다면, 플레이어는 사망 상태여야함.

그리고 먼저 장애물에 부딪혔으므로 take_damage_period=false로 바꿔 두번 triiger event가 발생하지 않게 해주기.

그 후에 player의 상태를 죽음(triggerbodyentity.statecomponent:changestate("DEAD")로 만들어주는데 이때 죽은 상태에서 좌우 점프가 가능함으로

그런것이 불가능하게 따로 이렇게 함수를 만들어 실행시켜준다.

 

PlayerDead 함수 만들기

Function: 에 “+”를 눌러 New 를 눌러 새로운 함수 PlayerDead를 만들어준다.

movementcomponent에서 inputspeed와 jumpforce도 0으로 바꿔 움직일수없게 만들어주는 함수

또한 대기시간을 wait(5)를통해 5초 기다리게 하고 다시 플레이어의 상태를 

triggerbodyentity.statecomponent:changestate("IDEL")을 통해 IDEL상태로 만들어주기

다시 플레이어를 시작점으로 보내기위해 triggerbodyentity.movementcomponent:setposition(vector2(3.4,-4))로 시작점으로 보내주고 플레이어의 hp 를 maxhp로 설정

TriggerBodyEntity.Take_Damage_Component.Take_Damage_Period = true 를 통해 Player의 데미지를 받는 주기를 다시 True로 설정해 Trap과 닿으면 Hp가 깎이도록 설정해준다.

또한 inputspeed와 jumpforce,mode가 다 0이거나 nil로 되어있으므로 다시 돌려주는 playerAlive()라는 함수를 실행시켜주는데 이때 이 함수는

InputSpeed,JumpForce,Mode원래대로 바꿔주는 함수

 

장애물과 닿았을때뒤로 밀려나기

⇒ TriggerBodyEntity.RigidbodyComponent:SetForce(Vector2(-1 * _UserService.LocalPlayer.PlayerControllerComponent.LookDirectionX,3)) 의 Vector2의 값을 -1*LookDirectionX 으로 설정

→ 바라보는 방향의 뒤로 힘을 가해주면서 뒤로 밀려나게 된다.

 

포션 기능 구현하기

 

defaultplayer에 PotionTriggerComponent Take_Potion_Component를 추가

 

Potion Entity에 PotionTriggerComponent(ExtendTriggerComponent)를 추가

PotionTriggerComponent(ExtendTriggerComponent)

 

구현 해야 할 사항들

해당 포션과 TriggerEvent 발생 시, heal의 양에 따라 hp를 PlayerComponent.Hp + heal 만큼 증가시켜주기

포션 또한 여러 번 TriggerEvent가 발생할 수 있으므로 장애물과 마찬가지로 period를 적용시켜 일정 시간 내에 다시 TriggerEvent가 발생하는걸 방지해주기

TriggerEvent 발생시 visible과 enablefalse로 바꿔주기

플레이어와 장애물이 닿으면서 TriggerEvent가 발생하면 플레이어가 잠깐 뒤로 밀려나게 되고 다시 생성되는 과정에서 체력 회복이 두 번 되는 경우를 방지하기 위해 period를 도입하기

포션을 먹었을 때 회복 후 hp가 최대치 이상인 경우, 플레이어의 hp 최대치까지만 회복하고, 그렇지 않은 경우, 플레이어의 hp는 heal의 양만큼만 회복하게하기

 

Take_Potion_Component 추가하기

현재 player가 period가 참일 경우에만 Potion과 충돌하여 hp 회복하게하기

 

 

포탈 구현하기

포탈 만드는 방법은 포탈 모델을 이용하여 만들거나 직접 포탈을 만드는 방법 두 가지가 있음.

 

1. 포탈 모델을 이용하여 만드는 방법

Model List에서 Portal을 선택하여 Scene에 배치하기

이 포탈 모델에는 Portal Component가 이미 포함되어 있음

 

2. 직접 포탈을 만드는 방법

엔티티를 배치하기
Add Component를 통해 PortalComponent를 직접 추가해주기
포탈은 2개 이상 만들어야 하므로,. Avoid_Obstacle_Map 안에 portal을 만들고 Success_Map 안에 success_portal을 만들어주기

 

맵 만드는 방법

 

Scene Maker > Create Entity > Create New Map을 통해 다른 맵을 만들 수 있으며, 포탈을 통해 맵을 이동할 수 있음. 위에 나온 방식으로 포탈을 만들어준 후

Portal Component에서 PortalEntityRef을 통해 목적지 포탈을 설정해주면 됨. (기본 값은 none)

success_portal의 PortalEntityRef은 none으로 두면 됨.

이 실습에서는 결승점에 도달하여 오른쪽의 포탈에 가면, 목적지인 Success_Map의 success_portal로 이동됨.

 

 

UI 구현하기

 

HP바 나타나게 하기 & HP바 조정하기

Model List → UIPreset → HP바 를 이용해 간단하게 닉네임와 HP바만 나타나게 할 수 있음.
HP바를 넣어주게 되었을 때 Scene Maker > UIMyInfo > Hp_bar Entity의 Property인 SpriteGUIRendererComponent를 만들어보면 Type이 Sliced로 되어있고, SliderComponent가 있음. 이때 이 Component의 Value값으로 HP바가 움직이는것을 알 수 있음.

SliderComponentValue값을 Hp/MaxHp 비율에 맞게 조정해준다면, Player가 데미지를 입었을때 감소되고, 포션을 먹었을때 증가하게 연출이 가능하게됨.

 

 

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 14  (0) 2022.07.24
MOD project 13  (0) 2022.07.22
MOD project 12 -NEXON  (0) 2022.07.20
MOD project 11 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19

알아두면 유용할 것들

 

Model

모델: 엔티티에 컴포넌트를 추가해 모델화 할 수 있음.

original model: 빈 엔티티에서 컴포넌트들을 추가해 새로운 무언가를 만든 것.

child model: 기존 엔티티에서 상세 컴포넌트만 바뀐 것으로, 기존 엔티티에서 파생된 모델.

 

<부모자식 모델관계>

자식 모델의 기존 엔티티를 부모 모델이라 생각하면 됨. 부모 모델이 자식 모델의 상위 개념임. 

자식모델에서는 자신보다 상위모델인 부모 모델에서 추가한 컴포넌트를 삭제할 수 없음. 반대로 부모 모델에 새로운 어떤 컴포넌트 추가시 자식 모델에도 추가됨.

 

모델과 관련된 기능들

revert: 어떤 기능을 모델 전체에 추가시 사용

apply: 부모 모델에서 추가된 기능을 현재 모델에 추가시 사용.

 

 

동적 spawn: 필드 단위별로 스폰할 몬스터와 스폰할 몬스터의 수를 설정하면, 해당 조건에 맞춰 몬스터가 생성되는 스폰 시스템

(동적 spawn구현시 spawnbymodelid함수 사용)

 

 

엔티티 동적 생성

동적생성?

개발자가 모든 설정을 수동으로 작업해 엔티티를 생성하는 것이 아니라, 알아서 엔티티가 자동으로 생성되도록 하는 것

 

[ball 엔티티의 동적 생성 예시 코드]

TweenLineComponent 설정

 

BallComponent 코드

Start() : TweenLineComponent에서 설정한 Duration을 로컬 변수 duration에 받아 엔티티의 움직임이 시작되고 duration만큼 기다렸다 사라지게 함.

MoveComponent 코드

Spawn() : 스폰할 엔티티의 모델을 가져와 엔티티에 포함된 BallComponent의 Start 함수를 호출함. 이 때 스폰할 엔티티에는 무조건 BallComponent가 포함되어 있어야하고, BallComponent에는 Start 함수가 존재해야함.

HandleKeyDownEvent(KeyDownEvent event) : 키를 조작했을 때의 동작을 설정함.

 

 

 

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 15 - 4주차  (0) 2022.07.27
MOD project 13  (0) 2022.07.22
MOD project 12 -NEXON  (0) 2022.07.20
MOD project 11 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19

UI에디터의 이해

 

게임에서는 UI를 GUI라고 부르기도함. 주로 어떤 행동의 입출력을 담당함.

 

UI의 구성

1.모델리스트: 메이커에서 제공하는 다양한 UI Preset 활용 가능

2.UI 경로 정보: 선택된 UI엔티티의 경로 정보를 얻어오는 기능

3.캔버스: UI엔티티의 배치 및 편집을 작업하는 공간

4.기본 도구: 이미지& 버튼등의 UI엔티티 배치 가능

5.UI Group의 선택,추가,삭제 기능 제공

 

UI엔티티를 통해 UI를 편집하기 위해서는 가장 먼저 조작할 UI엔티티가 필요함.

UI 엔티티를 생성하기 위한 방법은 2가지가 존재함.

 

UI엔티티 생성법

기본 UI모델을 선택해 배치하는 방법

UI Preset을 활용하는 방법

 

기본 UI엔티티

 

기본 UI 엔티티는 기본 도구를 통해 배치할 수 있음.

기본 도구에 추가되어있는 기본 UI 엔티티로는

이미지, 버튼, 스크롤뷰, 텍스트, 입력텍스트의 5가지 요소가 존재합니다.

각 엔티티들은 해당 요소를 포함하는 컴포넌트들을 가지고 있으며,

기본 UI 엔티티간의 조합을 통해 특정 기능을 수행하는 UI 제작이 가능합니다.

 

UI Preset

자주 사용하는 UI들, 스크립트가 포함되어 있습니다.

 

스크립트를 이용한 UI 엔티티 제어

 

UI엔티티를 생성하였다면, UI엔티티에 접근해 엔티티를 제어해야함.

월드에서의 엔티티로의 접근법과 동일.

 

상황과 조건에 따른 UI노출처리

 

UI 엔티티는 화면의 입출력을 담당하는 엔티티여서, 상황과 조건에 따라 UI를 띄우거나 숨길 수 있어야 함

Entity 함수인 setEnable 을 통해 알림 팝업 및 토스트 메시지를 띄우는 기능을 구현할 수 있음.

void ShowToastMessage ()
{
    local toastUIEntity = _EntityService:GetEntityByPath("/ui/.../EntityPath")
    toastUIEntity:SetEnable(true)
}
 
void HideToastMessage ()
{
    local toastUIEntity = _EntityService:GetEntityByPath("/ui/.../EntityPath")
    toastUIEntity:SetEnable(false)
}

함수에 따라 toastUIEntity:SetEnable() 의 boolean 값을 바꿔줌으로써 토스트메시지가 상황에 따라 출력되거나 숨겨지도록 할 수 있음.

 

UI Group활용 방법

 

UI의 효율적인 관리를 위해 UI Group으로 연관 기능이 있는 UI엔티티끼리 묶어 관리함.

 

그룹에 텍스트를 추가하는 방법

UITransformComponent 

UI는 MOD 상에서 가상의 좌표계 역할을 함.

따라서 UI 위치 좌표는 PosX PosY를 통해 설정할 수 있음.

좌표를 기준으로 중앙 또는 상하좌우를 선택할 수 있음

UITransformComponent 배치한 텍스트 박스의 위치와 크기를 설정할 수 있는 컴포넌트

 

SpriteGUIRendererComponent

다양한 속성값을 통해 텍스트박스의 배경색, 배경, 리소스 경로 설정 등

텍스트박스를 예쁘게 꾸며볼 수 있음.

 

텍스트 박스에 이미지 추가하기

 

1. 메이커의 UI 버튼을 눌러 UI 에디터로 이동하여 UIGroup 에서 해당 그룹으로 이동

2. 좌측의 기본도구에서 이미지를 클릭해 이미지 UI를 추가

3. spritrenderercomponent의 imageRUID 프로퍼티의 우측 버튼을 클릭해 spritepicker메뉴 선택

4. 프로퍼티를 조정해 이미지 UI의 크기와 위치를 설정해줍니다.

 

 

 

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 15 - 4주차  (0) 2022.07.27
MOD project 14  (0) 2022.07.24
MOD project 12 -NEXON  (0) 2022.07.20
MOD project 11 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19

컴포넌트의 활용 2

 

1.입력 관련 컴포넌트

 

entity event handler에서 작업하기

keydownevent: 키를 1번 눌렀을때 발생

keyholdevent: 키를 누르는 동안 발생

keyreleaseevent: 키를 길게 눌렀다 뗐을때 발생

keyupevent: 키를 1번 눌렀을때 발생

 

touchevent

screentouchevent: 월드상의 화면을 터치, 또는 클릭했을때 1회 발생하는 이벤트

screentouchholdevent: 월드상의 화면을 터치하고 있는 동안 프레임마다 발생하는 이벤트

screentouchreleaseevent: 터치를 유지하다가 터치를 종료했을 때 1회 발생하는 이벤트

 이벤트를 추가하려는 컴포넌트에 touchreceivecomponent를 추가해 주어야함.

 

skilleffect

 

특정키를 누를때마다 노출되는 작업. 

주로 playeffect() 함수와 playeffectattached()함수가 자주 사용됨.

 

playeffect()함수

PlayEffect (string animationClipRUID, Entity instigator, Vector3 position, number zRotation, Vector3 scale, boolean isLoop = False)

이펙트를 고정된 특정 위치에 원하는 크기로 호출함

animationclipRUID: 호출하려는 이펙트 리소스의 RUID

instigator: 맵 정보를 받아오기 위한 엔티티

position: 이펙트가 호출될 위치 벡터값 입력 파라미터

zrotation: 회전 값

scale: 호출될 이펙트의 크기 벡터값(vector3)

isloop(true:이펙트 무한 재생, false: 이펙트 한번 재생)

 

playeffectattached()함수

PlayEffectAttached (string animationClipRUID, Entity parentEntity, Vector3 localPosition, number localZRotation, Vector3 localScale, boolean isLoop = False)

이펙트 호출, 호출될 이펙트의 부모 엔티티 선정, 부모의 위치를 기준으로 호출될 위치 설정합니다.

 

animationClipRUID : 호출하려는 이펙트 리소스의 RUID

parentEntity : 호출될 이펙트의 부모가 될 엔티티

localPosition : 부모 엔티티의 position 기준, 얼마만큼 떨어진 곳에서 호출할 것인지에 대한 위치 벡터값 (Vector3)

localZRotation : 부모 엔티티의 회전값을 기준, 회전 값 입력

localScale : 호출될 이펙트의 크기 벡터값 (Vector3)

isloop(true: 이펙트 무한 재생, false: 이펙트 한번 재생)

 

cameracomponent

 

기본적으로 카메라는 내 캐릭터를 잡아주고 있으며 cameracomponent는 목적지가 어디인지 보여주고 다시 내 캐릭터로 카메라를 잡아주는 함수임.

 

potal component

 

portal은 출발지와 목적지가반드시 한쌍으로 존재해야하며  기본적으로 포탈은 방향 키 위를 누를 경우 이동할 수 있음.

포탈을 맵에 생성하면 portalcomponent가 자동생성됨. 이후 리프하고싶은 포탈을 지정하면 됨.

스크립트로도 구현 가능.

점프맵을 만들때 유용할거같음.

 

사다리 component

ladder이나 rope가 기본적으로 가지고있는 컴포넌트임.

 

climbableanimation(rope:줄을 타고 오르는 액션, ladder:사다리를 타고 오르는 액션)

ladder,rope는 상하로만 이동이 가능 좌우 이동 불가능

 

ladder이나 rope가 아님에도 이와같은 기술을 구현하고 싶다면 climbablecomponent를 추가해주면됨.

ladder이나 rope가 아닌 엔티티에 climbablecomponent를 구현하면 상하는 물론 좌우로도 이동 가능함.

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 14  (0) 2022.07.24
MOD project 13  (0) 2022.07.22
MOD project 11 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19
MOD project 9 -NEXON  (0) 2022.07.19

컴포넌트의 활용

 

movementcomponent

 

캐릭터의 움직임에 관여하는 컴포넌트

inputspeed: 이동속도를 조절하는 property (x축 기준)

jumpforce: 점프력을 조절하는 property (y축 기준)

 

rigidbodycomponent

 

기본적인 물리 움직임을 조정하는 속성을 가진 컴포넌트

이 component에 어떤 속성을 부여함에 따라 레이어를 무시하고 움직일수도 있고 레이어에 영향을 받아 움직일 수도 있음.

quaterview 속성은 중력에 영향을 받지않고 평면에서 움직이는 것처럼 보이게 함.(quaterviewaccelerationx & quaterviewaccelerationy 으로 설정해야 영향을 줌)

광장같은 맵에서 캐릭터가 공중을 자유자재로 움직이는 모습이 평면에서 움직이는 것처럼 보이게 하는거라 매우 유용할듯.

 

triggercomponent

 

충돌이란 충돌체를 포함하고 있는 엔티티의 충돌 영역이 서로 교차했을때 발생함.

이 컴포넌트는 충돌 효과를 적용하는 컴포넌트로 충돌했을 때 일어나는 효과는 따로 component를 만들어 생성해야함.

 

hitcomponent: 피격의 범위 설정

triggercomponent: 충돌이 일어나는 범위를 설정

collideroffset, boxsize, circleradius: 충돌체의 속성 설정

collideroffset, boxoffset: 충돌체의 위치 설정 (값: vector2,충돌체의 가로,세로 크기 설정)

boxsize: collidertype이 box일때 충돌체의 크기 설정 (값: 충돌체의 반지름 값 입력)

collidertype:충돌체의 형태 선택

  • box:충돌체의 형태- 사각형
  • circle: islegacy가 false일때 사용 가능
  • islegacy: transformcomponent에 영향을 받을지 설정
  • islegacy-true: transformcomponent에 영향을 받지 않음
  • islegacy-false: transformcomponent에 scale과 rotation에 영향을 받음, circle타입의 충돌체 적용 가능

 

충돌이 발생하였을때, 충돌중일때, 충돌되었다가 끝났을때의 3가지 지점으로 액션 이벤트가 나뉨.

triggerenterevent: 엔티티간 처음 충돌이 발생했을때 1회 발생

triggerstayevent: 엔티티가 충돌중이면 프레임마다 발생

triggerleaveevent: 엔티티가 충돌되었다가 충돌이 끝났을때 1회 발생

 

triggerenterevent활용 예시 코드

setforce함수를 이용해 vector2의 방향으로 움직임 설정

self.force를 사용해 직접 force를 지정해줄수있음.

충돌과 관련된 처리를 할때는 꼭 triggercomponent 나 hitcomponent를 추가해줘야함!

 

원하는 이미지 불러오기

 

1.import image 선택하기

2.이미지 불러오기

3.이미지 활용하기

 

workspace-> mydesk-> 마우스 오른쪽 -> import form -> import image에서 이미지 불러오기

 

불러온 이미지 활용하기

 

원하는 이미지를 불러왔으면 work space-> mydesk에서 사용할 이미지 클릭한 뒤 place to scene maker 선택하기

사용할 이미지를 scene에 끌어오면 원하는 이미지 맵에 위치시키기 가능

 

경오에 따라 sprite RUID/image RUID를 변경해 사용 가능!

 

webspritecomponent

 

이 컴포넌트는 웹에있는 이미지를 가져와 표시해주는 컴포넌트임.

url에 이미지의 경로를 적음으로써 웹상의 이미지를 가져올수 있음.

상하좌우반전 및 레이어 설정 색상 변경 등 property의 조정을 통해 컴포넌트 커스텀 가능.

스프라이트의 색상 조정하려면 sproterenderercomponent와 webspritecomponent의 color프로퍼티 조정해야됌.

 

 

youtubeplayerworldcomponent

 

유튜브 영상을 씬 내에서 불러와 재생 할 수도있음

YoutubePlayerGUIComponent : UI 상에서 표시해줄 때 사용

YoutubePlayerWorldComponent : 월드상에 표시할 때 사용

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 13  (0) 2022.07.22
MOD project 12 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19
MOD project 9 -NEXON  (0) 2022.07.19
MOD project 8 -NEXON  (0) 2022.07.19

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

네트워크의 이해

 

MOD에서는 기본적으로 서버-클라이언트 모델을 지원하고 있음.

이때 서버는 클라이언트의 요청을 받는 서버이고 클라이언트는 접속된 각각의 유저임.

 

만약 entity를 생성하게 되면 서버와 클라이언트 모두 entity가 생성이 되는데 서버와 클라이언트 모두 네트워크로 연결이 되어있긴 하지만 다른 객체 이기 때문에 어디서 설정하느냐에 따라서 설정값이 달라질 수 있고 이로인해 동기화(어느 한쪽 값이 달라졌을때 양쪽의 값을 모두 바꾸는 행동을 취하는 것) 문제 발생 가능.

 

서버는 한개이지만 클라이언트는 여러개 일 수 있음. 즉 서버와 클라이언트는 1:n관계임.

서버에서 특정 property값을 바꾸면 그 property를 가지고 있는 클라이언트의 property또한 전부 바뀌는 반면에 클라이언트에서는 독자적 으로 값을 바꿔도 다른 클라이언트나 서버에 영향을 미치지 않음. 이유는 서버와 클라이언트에 저장된 각각의 엔티티는 네트워크로 연결되어있으나 엄연히 다른 엔티티이기 때문임.

 

mod에서는 어느 한쪽이 달라졌을때 다른 한쪽 또한 일일이 바꿔주는 행동을 수행하기 번거롭다고 생각하여 실행제어하는 개념을 도입함.

 

property 실행 제어

 

서버에서는 특정 property값을 바꾸면 그 property를 가지고있는 클라이언트의 property또한 전부 값이 변경된다고했고, 클라이언트에서는 property값을 바꿔도 서버의 property에 영향을 미치지않는다고 했다. 만약 클라이언트에서 변경한 property값들이 서버에도 반영된다면 클라이언트-서버 관계는 1:n의 관계임으로 서버에 과부화가 오게됨. 따라서 동기화는 서버 -> 클라이언트 단방향으로 진행됨.

 

그래서 property는 동기화옵션을 설정할수있게 해줌.

여기서 [sync]를 클릭해서 [none]타입으로 변경할수있는데 [sync]는 동기화가되는 property[none]은 동기화가 되지않는 property임.

 

 

function 실행 제어

 

함수는 호출한 쪽이 서버인지 클라이언트인지에 따라 동작하는 공간이 다릅니다. 따라서 실행 제어를 통해 공간을 활성화 시켜 주어야함.

공간을 활성화하면 해당 function이 특정한 속성을 가지게됨. 이러한 공간활성화로는 5가지 속성이 있음.

 

client:서버가 클라이언트의 함수를 호출하면 서버와 연결된 클라이언트들에게 함수 호출을 요청하고, 연결된 클라이언트들에 있는 함수가 실행됨.

client only: 클라이언트에만 불릴 수 있으며 서버에서는 부를 수 없습니다.

server: 클라이언트 쪽에서 서버의 함수를 호출하면 서버 쪽에 신호를 보내 서버 안에서 함수가 실행되게함.

server only: 서버에만 불릴 수 있고, 클라이언트에서는 부를 수 없음. 대부분의 로직은 서버에서 서버기준으로짜게됨. 즉, 로직은 주로 서버위주의 행위를 많이 하게 됨.

multicast: 서버와 클라이언트 양쪽 모두 실행함.

 

 

MyFirstComponent {
		Property:
		Function:
				void OnBeginPlay()
				{
						log("BEGIN PLAY")
						wait(2)
						self:Server()  -- 1. 서버가 서버 메시지를 뿌립니다.
						self:Client("HAHAHA")  -- 2. 클라이언트에서 메시지를 뿌려달라고 요청 후 바로 다음을 실행합니다.
						self:MultiCast() 
						log("END")
				
				void Client( string arg1 )  -- 3. 클라이언트에 도착하면 클라이언트가 메시지를 받은 순간 요청을 실행합니다.
				{
						log("CLIENT" .. arg1)
				}

				void Server()
				{
						log("SERVER")
				}

				void MultiCast()
				{
						log("MULTICAST")
				}
}

실행 순서

 

서버에서 엔티티를 생성하고 클라이언트에도 엔티티가 생성되기까지 시간이 걸림! 클라이언트에서 엔티티가 생성되는 도중에 서버에서 엔티티의 값을 넣어 전송하면 클라이언트에서 값을 받지 못하는 현상이 발생하는데 이것을 타이밍 이슈라고함.

 

  • 서버가 흐름을 관장하고 클라이언트는 서버에서 받아온 것을 보여줌.
  • 서버에 엔티티가 생성이 됐을때 그 엔티티들이 각 클라이언트 내에도 생성이 됨.
  • 특정 클라이언트 안에서 생성된 엔티티는 그 클라이언트 안에서만 생성됨.

특정 클라이언트 안에서만 생성되는 엔티티의 대표적인 예

  • UI
  • 입력
  • effect - 특정 클라이언트에서만 연출하고 싶을땐 로컬 엔티티 사용.
  • 최적화 - 서버에 엔티티가 너무 많을때 비용 때문에 최적화 시 로컬 엔티티를 사용.

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 11 -NEXON  (0) 2022.07.20
MOD project 10 -NEXON  (0) 2022.07.19
MOD project 8 -NEXON  (0) 2022.07.19
MOD project 7 -NEXON  (0) 2022.07.19
MOD project 6 -NEXON  (0) 2022.07.15

그룹 월드 시작
새로 만들기 버튼> 이어서 만들기 버튼 클릭

메이플 맵 불러오기
Window > maplestory map
원하는 월드 맵 불러오기

만든 모든 맵 확인
Window > maple list

같이 작업하고있는 그룹원 목록 확인
panels > cooperations

저장하기
ctrl+s

협업의 이해
공동 월드에서 작업할 때 한 사람이 작업시작하면 ctrl+s하여 check in 하기 전까지 다른사람이 수정할 수 없음.

편집 권한
Workspace에서 옆 캐릭터를 눌러보면 locked by 편집자로 확인가능.
맵미다 편집자가 다르게 편집할 수 있음
예를들어 맵이 3개면 각자의 맵 맡아서 편집 가능.

그룹장만 가능한것
그룹 내 새로운 월드 생성
시작맵 변경
버전관리(file > revision)

'NEXON_SUPER_HACKATHON' 카테고리의 다른 글

MOD project 10 -NEXON  (0) 2022.07.19
MOD project 9 -NEXON  (0) 2022.07.19
MOD project 7 -NEXON  (0) 2022.07.19
MOD project 6 -NEXON  (0) 2022.07.15
MOD project 5 -NEXON  (0) 2022.07.15

+ Recent posts