멀티 터치

# 학습 과정 소개

멀티 터치 동작은 포인터(예: 손가락) 여러 개가 동시에 화면을 터치하는 것을 말합니다. 이번 과정에서는 예제를 통해 멀티 터치 활용 방법을 알아봅시다.

# 멀티 터치

메이플스토리 월드에서는 `ScreenTouch` 계열 이벤트 또는 `Touch` 계열 이벤트를 통해 멀티 터치를 인식하고 월드 플레이에 활용할 수 있습니다.   
아래의 `ScreenTouch` 계열 이벤트는 화면을 터치했을 때 [InputService](/apiReference/Services/InputService)에서 발생합니다.

  * [ScreenTouchEvent](/apiReference/Events/ScreenTouchEvent)
  * [ScreenTouchHoldEvent](/apiReference/Events/ScreenTouchHoldEvent)
  * [ScreenTouchReleaseEvent](/apiReference/Events/ScreenTouchReleaseEvent)   




아래의 `Touch` 계열 이벤트는 엔티티에 [TouchReceiveComponent](/apiReference/Components/TouchReceiveComponent)가 있어야 발생합니다.

  * [TouchEvent](/apiReference/Events/TouchEvent)
  * [TouchHoldEvent](/apiReference/Events/TouchHoldEvent)
  * [TouchReleaseEvent](/apiReference/Events/TouchReleaseEvent)   




멀티 터치를 사용하는 월드를 제작할 때, 위 내용을 참고하여 원하는 용도에 맞는 이벤트를 활용해 봅시다.

## 예제

TouchReceiveComponent를 추가한 엔티티 한 개 또는 여러 개를 터치한 상태로 움직이면 엔티티가 따라서 이동하는 예제를 살펴봅시다.

  1. Preset List - Object에서 원하는 엔티티 2개를 Scene에 배치합니다. 예제에서는 object-44와 object-49를 사용했습니다. [png](1684290735891fcf50ce912fe48cf8999f06b6f04c0b8)   

  2. 본 예제에서는 `TouchEvent`, `TouchHoldEvent`, `TouchReleaseEvent`를 활용할 예정입니다. 이 이벤트들은 엔티티에 TouchReceiveComponent가 있어야 발생합니다. 그러므로 두 엔티티(object-44, object-49)에 TouchReceiveComponent를 추가합니다. [png](1684300809932fceceea870bf4bdf8b179f481124f4f8)   

  3. 새 스크립트 컴포넌트 MultitouchTest를 생성합니다. 이 컴포넌트를 두 엔티티(object-44, object-49)에 추가합니다. [png](16843009914475f72fc6fb811406eac45f2d96ac8d237)   

  4. MultitouchTest 스크립트를 열고 아래와 같이 프로퍼티를 추가합니다. 
         
         @Component
         script SyncIndexTracker extends Component
         property SyncTable index
         property any eventHandler = nil
         end
         



    
    
          
    
    5. 이벤트 핸들러에 `TouchEvent`를 추가합니다.
        터치가 발생하면 `AddHandler()` 함수를 호출하고 **TouchId**를 넘겨주도록 합니다.
        ```lua
    @Component
    script TouchHandlerRegistrar extends Component
        @EventSender("Self")
        handler HandleTouchEvent(TouchEvent event)
        --------------- Native Event Sender Info ----------------
        -- Sender: TouchReceiveComponent
        -- Space: Client
        ---------------------------------------------------------
    
        -- Parameters
        local TouchId = event.TouchId
        local TouchPoint = event.TouchPoint
        ---------------------------------------------------------
        self:AddHandler(TouchId)
        end
    end
    
    
    
      
    
    

  6. `TouchHoldEvent`도 추가합니다. 터치가 유지될 때도 `AddHandler()` 함수를 호출하고 TouchId를 넘겨주도록 합니다. 
         
         @Component
         script HeldTouchManager extends Component
         @EventSender("Self")
         handler HandleTouchHoldEvent(TouchHoldEvent event)
         --------------- Native Event Sender Info ----------------
         -- Sender: TouchReceiveComponent
         -- Space: Client
         ---------------------------------------------------------
         
         -- Parameters
         local TouchId = event.TouchId
         local TouchPoint = event.TouchPoint
         ---------------------------------------------------------
         self:AddHandler(TouchId)
         end
         end
         



    
    
          
    
    7.  `AddHandler()` 함수를 추가합니다.
        매개 변수로 **integer** 타입의 **touchId**를 추가합니다.
        `ScreenTouchHoldEvent`와 `Move()` 함수를 연결합니다.
        나중에 구독 취소를 하기 위해, 연결한 이벤트의 핸들러는 프로퍼티로 가지고 있도록 합니다.
        ```lua
    @Component
    script TouchHoldHandler extends Component
        @ExecSpace("ClientOnly")
        method void AddHandler(integer touchId)
                if self.eventHandler ~= nil then
                    return
                end
    
                table.insert(self.index, touchId)
        --         self.eventHandler = _InputService:ConnectEvent(ScreenTouchHoldEvent, self.Move)  -- [Commented: MLUA requires handler pattern]
        end
    end
    
    
    
      
    
    

  8. `Move()` 함수를 추가합니다. `Move()`는 `ScreenTouchHoldEvent`의 매개변수를 전달 받기 때문에 any 타입의 screenholdEvent를 추가합니다. 유저가 엔티티를 터치한 상태로 움직이면 엔티티가 따라서 이동하도록 합니다. 
         
         @Component
         script DragHandler extends Component
         @ExecSpace("ClientOnly")
         method void Move(any screenholdEvent)
         local touchId = screenholdEvent.TouchId
         local touchPoint = screenholdEvent.TouchPoint
         
         local str_var
         for i =1, #self.index do
             if self.index[i] == touchId then
                 self.Entity.TransformComponent.WorldPosition = _UILogic:ScreenToWorldPosition(touchPoint):ToVector3()
                 break
             end
         end
         end
         end
         



    
    
          
    
    9. `TouchReleaseEvent`도 추가합니다.
        더 이상 터치한 엔티티가 없을 때 `ScreenTouchHoldEvent`에서 가지고 있던 이벤트 핸들러의 구독을 취소합니다.
        ```lua
    @Component
    script HeldTouchManager extends Component
        @EventSender("Self")
        handler HandleTouchReleaseEvent(TouchReleaseEvent event)
                --------------- Native Event Sender Info ----------------
                -- Sender: TouchReceiveComponent
                -- Space: Client
                ---------------------------------------------------------
    
                -- Parameters
                local TouchId = event.TouchId
                local TouchPoint = event.TouchPoint
                ---------------------------------------------------------
                for i =1, #self.index do
                    if self.index[i] == TouchId then
                    table.remove(self.index, i)
                        if #self.index <= 0 then
        --                     _InputService:DisconnectEvent(ScreenTouchHoldEvent, self.eventHandler)  -- [Commented: Use handler pattern instead]
                            self.eventHandler = nil
                        end
                        break
                    end
                end
        end
    end
    
    
    
      
    
    

  10.  [시작] 버튼을 누른 뒤 테스트해 봅시다. PC 환경에서 엔티티를 마우스로 클릭한 상태로 드래그하면 위치를 이동할 수 있습니다. 모바일 기기의 터치 스크린에서 2개의 엔티티를 동시에 터치하고 이동할 수도 있습니다. [gif](16843006146740a5849ed9f2b4aae9ef3d48af36b18d5)