반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
Touch Events

사용자가 스크린을 터치 했을 때 hit 이벤트가 발생합니다. 그리고 이 이벤트는 우선 순위에 따라 스크린에 표시된 object들에 전달 됩니다. 우선순위에 있는 객체가 이 이벤트를 가로채서 사용했다면(handle) 그 이후의 객체들에게는 이 이벤트가 전달 되지 않습니다.
어떤 특정한 객체에 이벤트의 포커스를 맞추고 싶으면 display.getCurrentStage():setFocus(object)를 이용합니다. 지난 번 글에서 한번 설명한 적이 있습니다. 버튼 down시 이후에 일어나는 up은 이 버튼에만 적용되도록 하는 경우에 사용 됩니다.

touch(single touch)
event.name : touch
event.x : 터치된 곳의 x 좌표
event.y : 터치 된 곳의 y 좌표
event.xStart : touch의 began phase 일 때 x 좌표였던 곳
event.yStart : touch의 began phase 일 때 y 좌표였던 곳
event.phase
  : began : 손가락이 스크린에 닿는 순간
  : moved : 손가락이 스크린에 닿은 채로 움직이는 경우 (컴퓨터의 드래그 상태)
  : ended : 손가락이 스크린에서 떼어지는 순간
  : cancelled : system이 touch 이 tracking을 cancel한 시점

touch (multitouch)
여러 손가락이 스크린에 터치 됐을 경우 이 multitouch를 사용해야 합니다.
제가 만든 앱 중에 multi Player ping pong 이라는 앱에 이 기능을 적용했는데요.
1~4인용 게임이라서 여러명이 터치할 경우 이를 반영해야 했습니다.
코로나에서는 MultitouchFingers와 MultitouchButton (interface 폴더 아래) 라는 샘플코드를 제공 합니다.
-- 이 multitouch 와 ui.lua를 동시에 사용할 경우는 최신버전의 ui.lua를 받으셔야 합니다. 초창기 버전에서는 멀티터치 기능 지원에 제한이 있었나 봅니다.
이 코로나 멀티 터치는 NexusOne, HTC Incredible 같은 일부 안드로이드 폰에서 동작이 잘 안 될 수 있다고 합니다. 이건 그 디바이스에서 멀티터치 기능을 지원하지 않기 때문이라고 하는군요. 참고하세요.--
멀티터치는 위에 있는 모든 싱글터치에 있는 프로퍼티들을 다 가지고 있습니다.
그 외에 event.id와 event.time 프로퍼티가 추가로 더 있습니다.
멀티터치는 각 터치들의 구분을 event.id로 합니다. event.time은 터치 당시의 system.getTimer()입니다.

멀티터치 사용법
멀티터치를 사용하시려면 처음에 system.activate("multitouch") 를 해 주시면 됩니다. 이 선언을 하신 후 스크린의 두곳을 터치하면 코로나는 event.id로 이것을 따로 관리하게 됩니다.

싱글 터치에 있었던  Forcus는 stage:setFocus(object[,touchID]) 를 사용 합니다. 이 기능은 각 object에 대해 touchID별로 따로 포커스를 둡니다. 이 기능을 없애려면 stage:setFocus(object,nil)을 해 주시면 됩니다.

Custom Events
object:dispatchEvent(event)
코로나는 custom events를 지원한다고 합니다. 아래 소스를 보세요.
-- Create an object that listens to events
local image = display.newImage( "endinggreen.png" )
 
-- Setup listener
local myListener = function( event )
        print( "Event " .. event.name )
        print( "Target has width: " .. event.target.contentWidth )
end
 
image:addEventListener( "myEventType", myListener )
 
-- Sometime later, create an event and dispatch it
local event = { name="myEventType", target=image }
image:dispatchEvent( event )


보시면 myEventType 이라는 이벤트를 개발자가 직접 만들 수 있습니다.
이 소스는 image에 이벤트를 걸어서 이 이미지가 뜰 때 event.name (myEventType)과 이 이미지의 width가 나오도록 한 소스코드 입니다.

Timer
가끔 특정 함수를 일정한 시간 이후에 호출할 필요가 있습니다.
앱 개발을 하다 보면 일정한 속도로 이미지를 움직이던가 할 때 이 시간을 조절하면서 이용하는게 더 편할 때가 있습니다. 이럴때 timer.performWithDelay를 사용하면 편합니다.

timer.performWithDelay(delay,listener[,iterations])

delay는 밀리세컨드 milliseconds 이구요 listener는 동작될 함수를 넣어 주시면 됩니다. iterations는 반복 횟수로 0이면 앱이 실행되고 있는 한 무한대로 반복 됩니다.

 local function listener( event )
    print( "listener called" )
 end
 
 timer.performWithDelay(1000, listener )

local listener = {}
function listener:timer( event )
   print( "listener called" )
end
 
timer.performWithDelay(1000, listener )

위 두 소스코드는 똑같이 1초마다 listener함수를 불러옵니다. 위에것은 함수 리스너이고 아래것은 테이블 리스너 입니다. 이 Function Listener 와 Table Listener 의 차이점과 장단점은 지난 글에서 다뤘으니까 따로 설명은 하지 않겠습니다.

timer.cancel(timerId)

 local t = {}
 function t:timer( event )
    local count = event.count
    print( "Table listener called " .. count .. " time(s)" )
    if count >= 3 then
        timer.cancel( event.source ) -- after 3rd invocation, cancel timer
    end
 end

 -- Register to call t's timer method an infinite number of times
 timer.performWithDelay( 1000, t, 0 )

위 소스코드는 1초 간격으로 t 를 실행시키는 테이블 함수 입니다. 여기서 event.count가 3보다 크거나 같으면 이 timer를 cancel 하도록 만들었습니다.
timer를 cancel 하는 방법에 대한 예제 소스코드 입니다.

timer.pause(timerId) : 이 기능은 코로나 build version 2011.596 부터 가능합니다.
timer.resume(timerId) 기능도 2011.596 버전부터 사용이 가능합니다.

2 주전 쯤에 다운 받았을 때만 해도 안전한 버전이 591 이었습니다. 위 두 기능을 다운 받으려면 그 이후 버전을 받아야 겠네요.

참고로 안정성이 확인 되지 않은 시험판 버전은 유료 구매자에 한해서 받을 수 있을 겁니다.

지금까지 코로나 SDK 의 이벤트,리스너에 대해 알아 봤습니다.

다음 Codona SDK DOC 공부는 Location and Maps 입니다.

그럼 다음에 뵙겠습니다.
반응형


반응형
오늘은 우선 Function Listener와 Table Listener 에 대해서 알아보는 것으로 시작 하겠습니다.

local myListener = function( event )
        print( "Listener called with event of type " .. event.name )
end
Runtime:addEventListener( "touch", myListener )
Runtime:addEventListener( "enterFrame", myListener )

위 리스너는 function 리스너 입니다.
Runtime으로 시작했으니 Global 리스너네요. 하나는 touch에 걸고 다른 하나는 enterFrame에 리스너를 걸었습니다.
touch를 하면 "Listener called with event of type touch"가 나올것이고 가만히 있으면 touch대신 enterFrame이 계속 찍히게 될 겁니다.

두 이벤트 모두 myListener라는 함수를 호출하죠? 이건 함수 리스너입니다.
가끔 함수 리스너는 이 리스너가 발생할 때 특정 변수를 처리하는데 한계가 있습니다. 이럴 경우 object Listener (table Listener) 를 사용할 수 있습니다.

-- assume MyClass and MyClass:new() already exist
 
function MyClass:enterFrame( event )
        print( "enterFrame called at time: " .. event.time )
end
 
function MyClass:touch( event )
        print( "touch occurred at ("..event.x..","..event.y..")" )
end
 
local myObject = MyClass:new()
 
Runtime:addEventListener( "touch", myObject )
Runtime:addEventListener( "enterFrame", myObject )

object Listener 는 위와 같이 사용합니다.
(이 코드는 이미 MyClass가 생성 돼 있어야 실행 됩니다.)
처음 코드와 같이 Runtime으로 리스너를 달았지만 테이블 리스너를 사용해 MyClass:enterFrame, MyClass:touch 이렇게 특정 이벤트에 함수를 달기 때문에 enterFrame에만 있는 정보들 그리고 touch 에만 있는 정보들 등을 자유롭게 사용할 수 있습니다.

Runtime Events

Runtime Events에 대해 알아 보겠습니다.

enterFrame
이 enterFrame은 Runtime:addEventListener  API를 이용해서 작동시킬 수 있습니다. 각 frameTime마다 불려질 겁니다.

local myListener = function( event )
        print( "Listener called with event of type " .. event.name )
end
Runtime:addEventListener( "enterFrame", myListener )

아래와 같은 프로퍼티가 있습니다.
event.name : enterFrame 이라는 스트링이 반환 됩니다.
event.time : 앱 시작 부터 지금 까지의 시간이 밀리세컨드로 표시 됩니다.

System

앱 실행 중에 전화가 온다든가 하는 이유로 다른 일을 할 동안 앱이 계속 유지 되게 하는데 필요합니다.
아래와 같은 프로퍼티들이 있습니다.
event.name : system 스트링 반환
event.type - 아래와 같은 스트링이 반환됩니다.
 : applicationStart - 앱이 시작될 때 그리고 main.lua에ㅔ 있는 모든 코드가 실행 됐을 때 발생함
 : applicationExit - 유저가 앱을 끝낼때 실행 됨
 : applicationSuspend - 전화가 오거나 오랫동안 사용을 안 해서 화면이 까맣게 될 때 같이 앱이 계속 유지될 필요가 있을 때 발생합니다.
 : applicationResume - 앱이 다시 실행 될 때 발생합니다. 시뮬레이터에서는 시뮬레이터가 백그라운드에 있다가 다시 포그라운드로 올라 올 때 실행 됩니다.

Orientation

지난 시간에 예제를 통해서 봤는데요. 전화기의 방향이 바뀔 때 이벤트들이 발생합니다.
아래와 같은 프로퍼티들이 있습니다.
event.name : orientation
event.type : portrait, landscapeLeft, portraitUpsideDown, landscapeRight, faceUp, faceDown

accelerometer

이것은 전화기를 기울이는 대로 중력이 작용하도록 할 때 사용합니다.(제 경험상)
아래와 같은 프로퍼티들이 있습니다.
event.name : accelerometer
event.xGravity : x 축 의 중력 관련 가속도 acceleration
event.yGravity : y 축의 중력 관련
event.zGrabity : z 축의 중력 관련
event.xInstant : x 축의 순간 가속도 instantaneous
event.yInstant : y 축의 순간 가속도
event.zInstant : z 축의 순간 가속도
event.isShake : 전화기를 흔들어쓸 때

location (GPS)

GPS 하드웨어에 의해 발생되는 위치 이벤트 입니다.
event.name : location
event.latitude : 위도
event.longitude : 경도
event.altitude : 고도
event.accuracy : 정확도(몇 미터를 기준으로 파악할지 여부)
event.speed : 초당 미터 m/s 로 나타나는 순간 스피드
event.direction : 북쪽부터 시작하는 시계방향으로의 방향
event.time : location event의 UTC timestamp

에러가 났을 경우에는 아래 프로퍼티에 어떤 값이 할당 됩니다.
event.errorMessage : error description. 에러가 났을 때에만 나옵니다.
event.errorCode : 에러 메세지

heading (compass)

안드로이드에서는 event.magnetic 만 지원되고 event.geographic은 지원 되지 않습니다.
event.name : heading
event.geographic : geographic 북극을 기준으로 시계방향으로의 heading 방향
event.magnetic : magnetic 북극을 기준으로 시계방향으로의 heading 방향

memoryWarning

iOS에서만 지원되는 메모리 사용 관련 이벤트. 거의 5초 이내에 shut down 될 정도의 상황에서 발생.

local function handleLowMemory( event )
  print( "memory warning received!" )
end
 
Runtime:addEventListener( "memoryWarning", handleLowMemory )

Targeted Event

어떠한 단일 Target에 이벤트를 보냄

completion
오디오, 비디오 부분에서  예제로 다뤘었는데요. 오디오나 비디오가 완전히 끝났을 때 발생하는 이벤트 입니다.
event.name : completion

timer
event.name : timer
event.sorce : 타이머에 등록된 값
event.count : 타이머가 실행 된 횟수
event.time : 앱이 시작된 이후부터 지금까지의 시간

urlRequest

native.webPopup() 함수와 함께 등록되는 이벤트 입니다.
event.name : urlRequest
event.url : absolute URL
event.errorMessage : 에러 메세지 유저의 언어 세팅에 따라 표시 됨
event.errorCode : 에러 메세지 유저의 언어 세팅에 관계 없이 표시 됨

오늘은 빨리 작업할 일이 있어서 여기까지 밖에 정리하지 못하겠네요.
다음 시간에 Touch Events, Multi Touch Events 그리고 Timer에 대해 알아 보겠습니다.

감사합니다.

반응형


반응형
오늘 다룰 이슈는 코로나에서의 이벤트와 리스너 입니다.
이벤트, 리스너는 어떤 행위(이벤트) 가 일어났을 때 이를 감지(리스너) 하고 이에 대해 특정 행위를 하도록 하는 상호 작용 효과를 내는데 꼭 필요한 기능입니다.

글로벌 이벤트(Global Events)
어떤 이벤트 들은 광범위하게 적용 되는 겁니다. 예를 들어 enterFrame, system, orientatin등이 있습니다. 이미지,버튼,텍스트 같이 특정 객체(object)에 한정된 이벤트가 아니라 프로그램 전체적으로 영향이 있는 글로벌 이벤트 입니다.

local label = display.newText( "portrait", 0, 0, nil, 30 )
label:setTextColor( 255,255,255 )
label.x = display.stageWidth/2; label.y = display.stageHeight/2
 
local function onOrientationChange( event )
        label.text = event.type   -- change text to reflect current orientation
        -- rotate text so it remains upright
        local newAngle = label.rotation - event.delta
        transition.to( label, { time=150, rotation=newAngle } )
end
 
Runtime:addEventListener( "orientation", onOrientationChange )

위 소스 코드는 orientation 의 변화가 있으면 onOrientationChange 함수를 실행합니다.
핸드폰이 세워저 있으면 portrait 글자가 쓰여지고 옆으로 뉘어져 있으면 글자도 각도를 바꾸고 text도 바뀌는 함수 입니다.


orientationr과 관련된 cases는 상하좌우로 돌릴때랑 faceUp,faceDown 이렇게 6개가 있네요.


Local Events


Hit Events -  user가 스크린을 터치 하면 이 히트 이벤트가 생깁니다. 만약에 이 이벤트를 어떤 특정 객체(object)에 줬다면 이 hit 포인트의 좌표를 그 object가 가로 채서 사용하게 될 겁니다.


이벤트의 전달(전파)와 핸들링 (Propagation/Handling)

이 이벤트들은 특정한 순서에 따른 객체(objects)들을 통해 전파 됩니다. 디폴트로는 이벤트를 받기 위한 display hierarchy에 따른 첫번째 object가 그 이벤트를 갖게 될 겁니다. 쉽게말하면 일반적으로 가장 위에 display된 객체가 우선적으로 이벤트를 가로 채 가게 될 거라는 겁니다. 이 이벤트는 그 이벤트가 핸들(처리) 될 때까지 전파(전달) 될 겁니다. 그러니까 한 위치에 여러개의 객체(object)가 중복 돼 있고 그 위치를 hit 했다면 맨 위의 객체에게 전달 되고 그 객체가 핸들링을 하지 않으면 그 다음객체 또 핸들되지 않으면 그 다음 객체 ... 이런 순으로 이벤트가 각 객체들에 전달되고 맨 마지막에는 스크린 자체 객체(Runtime object)에 전달 될 겁니다.

만약에 겹쳐진 두개의 객체에서 핸들링 하도록 되 있다면 우선순위에 있는 객체에 이벤트가 전달되고 핸들링 되면 이 이벤트의 전달(전파)는 끝이 날 것이기 때문에 우선순위에 밀린 객체는 그 이벤트를 핸들링 할 수 없게 됩니다.


Overriding Propagation with Focus

Focus를 세팅함으로서 특정 오프젝트에 앞으로의 hit 이벤트를 redirect할 수 있습니다. 예를 들어 버튼을 터치 하면 다른 버튼 이미지로 바뀌도록 했을 경우를 상상해 보면, down 하면 이미지가 바뀌고 up 하면 원래 이미지로 돌아와야 되는데 user가 down한 후 up을 하지 않고 버튼 밖으로 나가서 up을 하게 되면 원래 이미지로 돌아오지를 못 합니다. 이 경우 앞으로 일어날 up이벤트를 이 버튼에 포커스를 맞추겠다는 의미로 이 setFocus 를 이용하면 어디에서  up을 하든지 이 버튼의 토글 기능은 제대로 작동 할 겁니다.

function button:touch( event )
        local phase = event.phase
        if "began" == phase then
                -- Subsequent touch events will target button even if they are
                -- outside the stageBounds of button
                display.getCurrentStage():setFocus( self )
        else
        ...
        end
        return true
end


Listener and Event Delivery


리스너는 함수이거나 테이블 객체 일 수 있습니다. 두 경우 모두 event 인수가 리스너에 전달 됩니다. 


함수 리스너(function Listener)

 local function listener( event )
   print("Call #"..event.count )
end
timer.performWithDelay(1000, listener, 5 )


테이블 리스너(Table Listener)

local listener = {}
function listener:timer( event )
   print("Call #"..event.count )
end
 
timer.performWithDelay(1000, listener, 5 )


위 소스코드는 timer 이벤트에서 listener라는 함수를 호출하고 있습니다.

위에것은 함수 리스너이고 아래것은 테이블 리스너 입니다.


Registering for Events


이벤트는 addEventListener라는 메소드를 통해서 등록합니다.  그리고 removeEventListener라는 메소드로 제거합니다.


    •    object:addEventListener( )
    •    object:removeEventListener( )


* Function Listener

local button =  display.newImage("button.png")
 
local function listener(event)
  print(event.name.."occurred")
  return true
end
 
button:addEventListener( "touch", listener )


* Table Listener

local button = display.newImage("button.png")
 
function button:touch(event)
  print(event.name.."occurred")
  return true
end
 
button:addEventListener( "touch", button )


위 두 소스 코드는 버튼 이미지에 이벤트리스너를 단 것입니다. 위에것은 함수 리스너이고 아래 것은 테이블 리스너 입니다.


객체가 아니라 시스템에 add하는 이벤트리스너는 아래와 같이 add합니다.


* Function Listener

local function listener(event)
  print(event.name.."occurred")
end
 
Runtime:addEventListener("enterFrame", listener )


* Table Listener

local listener = {}
 
function listener:enterFrame(event)
  print(event.name.."occurred")
end
 
Runtime:addEventListener("enterFrame", listener )


이제 이벤트 다는 법을 배웠습니다.

그런데 Function Listener와 Table Listener가 나오는데 두개의 차이점과 장단점이 무엇인지 궁금하지 않나요?


두 리스너의 차이점과 장단점에 대해서는 다음 글에서 다루겠습니다.

다음 글에서는 이 외에 이벤트의 종류와 timer에 대해서도 배워보겠습니다.



반응형