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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

Posted on . Written by


수요일 FAQ 시간이 다시 돌아 왔습니다. 아래 자주 반복되는 질문 5가지가 있습니다. 오늘은 Event Listeners와 Display Objects를 어떻게 remove 하는지에 대해 알아보겠습니다.


1. I’m confused about when I need to call removeEventListener?


대표적인 경우는 Runtime:addEventListener를 사용해서 이벤트 리스너를 생성했다면 Runtime:removeEventListener를 call 하셔야 합니다. 만약 object event listener를 생성했다면 그 object를 remove 할 때 object event listener도 remove 해야 합니다.


--------------------------
-- Runtime Listener
--------------------------

function myFrame( event )
    print( "enterFrame", event.time )
end

Runtime:addEventListener( "enterFrame", myFrame )

-- Some time later ...
Runtime:removeEventListener( "enterFrame", myFrame )

--------------------------
-- Object Listener
--------------------------

local rect = display.newRect(10, 40, 100, 50)

function rect:touch( event )
    if event.phase == "began" then
        print( "Rect touched", event.target )
    end
end

rect:addEventListener( "touch" )

-- Some time later ...
rect:removeSelf()
rect = nil


 



2. I see code using “self”. What is that?


self 는 루아 메소드의 hidden 파라미터 입니다. 함수를 call 할 때 그 object에 접근하기 위해 사용하죠. 아래에 그 예제가 있습니다.


local rect1 = display.newRect(10, 100, 100, 50)
function rect1.touch( self, event )
    if event.phase == "began" then
        print( "Rect1 touched", event.target, self )
    end
end

rect1:addEventListener( "touch" )


local rect2 = display.newRect(10, 160, 100, 50)
function rect2:touch( event )
    if event.phase == "began" then
print( "Rect2 touched", event.target, self )
    end
end

rect2:addEventListener( "touch" )
 

두 예제의 메소드 모두 제대로 작동합니다. 그런데 하나는 "." 를 사용했고
다른 하나는 ":"를 사용했습니다.

콜른(:)을 사용하면 메소드에 hidden self 파라미터를 전달합니다.
그리고 점(.) 을 사용한 것은 이 self를 전달하지 않습니다.
그러니까 점을 사용하면 반드시 첫번째 파라미터로 self를 전달해야 합니다.

코로나는 다른 많은 Display Object API들에 (e.g., object:removeSelf, object:setFillColor, etc.) 이 Lua 기능을 사용하고 있습니다.


이벤트 리스너와 self 를 사용하는 것은 그렇게 유용하지 않을 겁니다. 왜냐하면 대부분의 object listener들은 객체의 handle을 지원하기 위해  event.target 파라미터를 제공하기 때문이죠. 이 파라미터는 self와 같습니다. 여러분이 만든 메소드에는 이 self를 사용할 수 있을 겁니다. 여러 객체에서 같은 메소드를 call 할 때 아주 유용하겠죠.


3. Do I really need to set display objects to nil after I remove them?


그 객체와 관계된 Lua 메모리를  clean up 하기 위해 사용하지 않는 객체에 nil을 할당해야 합니다. display object를 remove 할 때마다 (object:removeSelf) 그 객체의 texture 메모리와 관련된 메소드 그리고 그 객체와 관련된 이벤트 핸들러들은 remove 될 겁니다.  그렇게 되면 그 객체는 일반적인 Lua 테이블로 됩니다. 여기에 nil을 할당함으로서 그 테이블에 대한 reference 까지 remove 하게 됩니다. 그리고 나서 Lua Garbage Collector에 의해 그 테이블이 사용했던 메모리가 free 됩니다.


4. What is the best way to remove display objects from a Display Group?


display group에서 removeSelf 를 하면 그 그룹의 모든 display object들을 remove 할 겁니다. 그 그룹의 각 객체별로 따로따로 removeSelf  할 필요는 없습니다. group에 있는 객체들을 따로 nil 처리할 필요는 없습니다. 그룹 안에 있는 객체가 다른 변수에 의해 reference 된다면 그 variable을 nil로 세팅해야 합니다.


5. How can I tell if a display object was removed?


display object는 table입니다. 그리고 그것과 연관된 texture memory와 메소드들이 있죠. 그러니까 어떤 display object 메소드가 그 object와 아직까지 연관이 돼 있는지 여부를 체크함으로서 해당 display object가 아직까지 존재하는지를 알아 낼 수가 있습니다.


local rect1 = display.newRect(10, 100, 100, 50)
if type( rect1.setFillColor ) == "function" then
print( "rect is still a display object" )
end


위 예제는 rect1 객체에 setFillColor 메소드를 적용할 수 있는지 여부를 체크하고 있습니다.
어떤 객체에 removeSelf 를 call 하면 그 객체로부터 모든 메소드가 removed 된다는 것을 기억해 두세요.

여기까지가 이번주 QNA 내용이었습니다.

즐거운 주말 되세요.



반응형


반응형
Posted on

. Written by


적어도 50만개가 넘는 앱들이 앱스토어와 구글 플레이에 있습니다. 이러한 수많은 앱들 속에서 아주 좋은 앱일지라도 찾지 못하고 넘어가기가 아주 쉽습니다. 이 앱 시장에서는 마케팅할 수 있는 방법이 아주 제한되어 있고 시간에 제약도 있으니까요. 여러분은 앱을 어떻게 알리고 또 필요한 이용자가 다운로드 받을 수 있도록 할 수 있을까요?

화요일 저녁에 저는 샌프란 시스코의 App discovery event에 참가 했었습니다.  Free App A DayTapjoyAppsfire, 그리고 Iddiction 등에서 연사들이 왔었습니다. 거의 12페이지 가까이 열심히 적었는데요. best app 찾는 방법과 배포하는 방법에 대해 정리한 것을 아주 간략하게 정리해서 공유할께요. 이건 특별한 기준에 의한 정리가 아닌 빙산의 일각일 뿐 이겠죠. 여러분만의 앱 홍보나 마케팅 방법이 있으면 공유해 주세요. 저희는 여러분의 소중한 경험을 듣는 것을 듣고 싶습니다.





1.     Get your app localized. 중국어나 일본어, 독일어, 프랑스어 이탈리아어, 러시아어, 포프투갈어, 인도어 등의 현지어를 추가하는 것은 마케팅 전략상 아주 중요한 부분입니다.


2.     Word of mouth = the best form of marketing.  다른 개발자나 출판물, 혹은 개인 등을 통해서 입에서 입으로 광고 되는 것이 마케팅의 가장 좋은 방법입니다.


3.     Assemble a comprehensive press kit. review 싸이트나 Tech 블로그 같은 곳에서 다뤄지도록 하세요. 앱의 개요나 screenshot, 그리고 사용법을 설명하는 비디오나 promo codes 등을 같이 넣어 주세요. 글을 쓰는 사람들은 특종같은 뭔가 구별되는 것들이 있는 글을 선호합니다. 그러니까 앱이 출시 되기 전에 미리 한번 사용해 봐 달라고 (TestFlight) 하는것도 좋은 방법이겠죠.


4.     Skip paying for services if you get featured by Apple.  우선 jackpot을 터트린 것을 축하드립니다. 두번째로 마케팅이나 publishing services 등등 에 낭비하지 마세요.  일반적으로 애플 친화적이고 애플 앱스토어에 올리시면 더 많은 다운로드를 기록 하실 수 있습니다.


5.     Generate buzz by dropping price. 특정기간 앱 가격 할인 행사를 하는 것은 소문을 내고 다운로드를 늘리는 좋은 방법입니다.


6.     Get on Apple’s radar by uploading screenshots to TouchArcade’s forum.   애플 앱 reviewer들은 일반적으로 이 포럼(TouchArcade’s forum)을 체크합니다. 블로거들도 마찬가지구요. 그러니까 이 포럼에 screenshots들을 업로드 하세요.


7.     Build analytics into your app. 이건 여러분 유저에게 actionable intelligence를 얻도록 하는 아주 필수적인 사항입니다. 앱에 analytics를 넣으세요.


8.     Get creative and optimize for less popular keywords.  예를 들어 가장 자주 검색되는 단어들 중 하나는 "free" 입니다. 이 단어로 검색되는 그 수많은 앱들과 경쟁하기를 원하지는 않을 겁니다. 그러니까 창조적이고 앱에 딱 맞고 사용자들의 검색에 잘 걸릴 수 있는 여러분의 홍보 키워드를 만드세요.


9.     Most discovery and distribution happens in the “free” category.  많은 개발자들이 자신들이 만든 앱의 free 버전과 유료 버전 두가지를 만들죠. 보다 홍보가 많이 되도록요. 왜냐하면 free 카테고리에 있는 앱들은 유저들이 더 많이 찾아보거든요.


10.  Combine your marketing channels. Facebook, Twitter, Google+, blog posts 나 여러분의 앱을 홍보할 수 있는 다른 활자화된 홍보수단을 총 동원해서 활용하세요.





반응형


반응형
Posted on . Written by

New Release


오늘 new public release (2012.894) 를 다운로드 할 수 있다는 것을 알리게 되어서 아주 기쁩니다. 이번 release에서는 계속해서 Mac OS X 10.8 에서의 Gatekeeper  기능에 대한 작업을 할 수 있도록 하는 보다 완전한 기능이 있습니다. 이전에는 유저가 인터넷에서 받은 앱을 인스톨 하는 것을 막는 Gatekeeper 의 특정 디폴트 기능이 disable 해야만 했는데 이제는 그러한 제약이 없습니다.

그 외에도 수많은 새로운 기능과 버그 수정 등이 있습니다.

아래 그중 몇가지를 소개해 드리겠습니다.


* display.newSprite에 추가된 Multisprite 지원 기능
* display.captureBounds 를 통해서 스크린 일 부분만 capture 하는 기능
* media.save 를 통해 Photo library 지원하는 기능
* physics Box2D library를 v2.2.1로 업그레이드
* Physics Body에 gravityScale 프로퍼티 추가. joint type에 새로운 프로퍼티들 추가
* Mac Simulator workflow 개선 (zoom level 과 skinless windows 등등을 기억하는 기능)
* developer device build 때 Lua 디버그 정보 제공
* 안드로이드 WebViews


전체 수정되거나 추가된 사항들은 Corona release notes 를 통해서 보실 수 있습니다.


iOS 6 Beta


지난 주 애플과 구글이 OS를 업데이트 한 것과 관련 우리가 경험했던 여러 이슈들과 관련 미래의 OS 업데이트에 대비해 우리들이 어떻게 할 것인지에 대한 정책과 관련해 논의 했었습니다.


그것과 관련해서 한가지 어려운 점 중의 하나는 애플은 악명높으리 만치 비밀주의라는 것입니다. 애플은 모든것이 NDA 하에 있기를 원합니다. 예전에는 이 의미는 최신 iSO 베타 버전에서는 device build가 불가능하다는 것이었습니다.


이 불가능을 가능으로 만드는 방법을 찾은 것 같습니다.


다음주 쯤에 standard build와 iOS 6 Beta build 중에 선택할 수 있는 기능을 선보일 것 같습니다. 그러면 여러분은 iOS6 에 맞게 build 해서 테스트 할 수 있습니다. (아래 그림을 보세요.)



이것을 하려면 애플의 iOS Developer Program에 가입돼 있어야 합니다. 애플의 프로그램 멤버여야 하고 애플의 NDA 에 부합해야 여러분 아이폰이나 아이패드에 최신 iOS 베타 버전을 인스톨 할 수 있으니까요.

다음주 중에 이 기능을 여러분께 선 보이겠습니다.


iPhone 5

아이폰 5 에 대해 수많은 루머와 새어나온 사진들이라고 하는 것들이 떠 돌아 다닙니다. 저희들이 알기로는 iPhone 5 는 9월 중순경에 모습을 드러낼 것 같습니다. 그리고 9월 말에 출시될 것 같구요. 주로 애플은 새로운 아이폰을 만들어 낼 때마다 새로운 iOS 버전을 출시했습니다. 그래서 그 쫌에 iOS 6 도 launch 될 것으로 기대하고 있습니다.


시중에 떠돌아 다니는 루머에 의하면 iPhone 5 의  새로운 스크린 사이즈는 1136×640 이 될 겁니다. 그러면 아이폰 4s 의 960×640 와 비교할 때 width 는 같지만 height 가 더 크게 되는거네요. 그러면 홈 스크린에 더 많은 앱 아이콘을 넣을수도 있겠죠.


만약 사실이라면 우리는 새로운 simulator skin을 추가해야 되겠네요. 그리고 안드로이드 쪽도 마찬가지로 1200X800 같은 새로운 스크린 사이즈에 맞는 시뮬레이터 스킨을 제공해야 합니다. 그것 말고도 다른 스크린 사이즈가 있으면 저희에게 알려 주세요. 저희 리스트에 추가해서 곧 시뮬레이터 스킨을 제공할 수 있도록 할 께요.


여기까지가 이번주 소식이구요. 다음주에 Tom이 돌아오면 계속 해 오던 FAQ가 이어질 겁니다.

감사합니다.




반응형


반응형
Posted on . Written by


external modules 를 require 할 때 정확히 어떤 일이 일어나는지 헛갈릴 때가 있습니다. 더군다나 스토리보드 scene들이나 여러분의 custom module들과 같이 동작을 하는데 에상하지 못했던 결과가 나오면 더 혼동되죠.

오늘은 여러분과 같이 Lua 에서 module들은 정확히 어떻게 작동을 하는지에 대해 몇가지 실습을 해 보고 설명도 덧 붙이겠습니다. 이 글을 읽으시면 모듈 내의 코드가 실행되거나 built-in require() function 을 call 했을 때 어떤 코드가 run 하지 않는지 등에 대해 이해 하실 수 있을 겁니다.





Including External Modules


가장 간단한 형식은 external module이 테이블 같은 어떤 것을 return 하는 Lua 파일인 경우입니다. 외부 모듈이 하나의 function 인 셈이죠.

아래 정말 간단한 모듈이 있습니다. example1.lua 인데요. 터미널에 한 문장을 print 하고 빈 테이블을 return 하는 것입니다.


example1.lua


local t = {}

print( "example1.lua has been loaded." )

return t


이제 main.lua를 볼까요? 여기서 우선 example1.lua를 require 합니다.


main.lua


local ex1 = require "example1"

ex1.testvar = "Hello world"



예상한대로 ex1은 빈 테이블입니다. example1.lua에서 빈 테이블을 return 했으니까요. 그리고 “example1.lua has been loaded.” 라는 문장이 터미널에 쓰여질 겁니다. 그 다음에 위에 보면 ex1 테이블에 어떤 프로퍼티를 할당했습니다.

이 부분을 주목해 보세요. 여기 약간의 트릭이 있습니다. 다른 모듈에서 이 example1.lua를 require 해 봅시다. scene1.lua라는 모듈에서요. 이미 main.lua에서 example1.lua를 require 했었죠. 이제 어떤 일이 일어나는지 볼까요?


scene1.lua (previous main.lua still applies)


-- ...

local examp1 = require "example1"
print( examp1.testvar )

-- ...

scene1.lua에서 example1.lua를 require 하면 “example1.lua has been loaded” 이 터미널에 뿌려지지 않습니다. 그리고  ex1.testvar 값을 print 하면 터미널에 “Hello World” 가 뿌려집니다. (이 의미는 뭐냐하면 testvar 프로퍼티가 존재한다는 것이죠.


여기서 뭘 알 수 있나요?


첫번쨰로 “example1.lua has been loaded” 라는 문장에 터미널에 뿌려지지 않은 이유는 그 모듈이 이미 main.lua에서 로드 됐기 때문이죠. 모듈이 한번 로드 되면 그 안의 코드가 다 실행되게 되죠. 그리고 모듈의 return 값은 package.loaded라고 하는 글로벌 테이블에 저장됩니다.


여러분이 require를 call 하면 첫번째로 이전에 이 모듈이 이미 로드 된 것인지 아닌지 확인하기 위해 package.loaded table 을 살펴 봅니다. 만약에 있으면 외부 모듈을 새로 require 하는 대신 package.loaded 에 저장된 return value를 return 합니다. 이 return 된 value는 copy가 아니라 reference 입니다. 그러니까 여러분의 모듈이 테이블을 return 한다면 미래에 같은 모듈에 대해 require를 call 하면 같은 테이블을 get 하게 될 겁니다.


만약에 package.loaded 안에 그 모듈이 없으면 그 모듈이 로드 될 겁니다. (그 모듈안의 코드들이 실행 되겠죠.) 그리고 그 모듈의 return value가 package.loaded table안에 저장될 겁니다. (미래에 사용하기 위해 저장하는 거겠죠.) 그래서 두번째에서는 “example1.lua has been loaded.” 이 터미널에 뿌려지지 않은 겁니다. require() 가 call 됐을 떄 global package.loaded table 안에 이미 그 모듈이 존재하면 그 모듈을 re-load 하지 않으니까요.


모듈 안에 있는 코드를 두번 실행하도록 하는 방법에는 두가지가 있습니다.

  1. 코드를 모듈 내에서 함수 안에 넣고 그 함수를 부르는 경우
  2. package.loaded table 에서 그 모듈을 remove 한 다음에 다시 require 하는 경우


첫번째 시나리오에 대한 예제입니다.


example2.lua


local t = {}

print( "example2.lua has been loaded." )

t.hello = function()
    print( 'Hello world.' )
end

return t


main.lua


local ex2 = require "example2"
-- Terminal: example 2 has been loaded.

ex2.hello()
-- Terminal: Hello world.


scene1.lua


local examp2 = require "example2"

examp2.hello()
-- Terminal: Hello world.



예제에서 보듯이 example2.lua를 두개의 다른 모듈(main.lua and scene1.lua)에서 require 했습니다. 첫번째 print statement는 오직 한번 보여집니다. 첫번쨰로 그 모듈이 require 됐을 때죠.

두번째 print statement는 hello() 함수 안에 있습니다. 이것은 hello() 함수가 call 될 때마다 실행되겠죠. 그 코드가 한번 이상 실행되기를 원한다면 함수를 table에 attach 해서 모듈 마지막 부분에서 return 되게 하세요. (또는 단지 require 만 했을 떄 print 되지 않도록 할 때도 그렇게 하면 되겠죠.)


Removing from package.loaded


여러분이 모듈을 require 하려면 (예를 들어 example2.lua) require "example2" 라고 해야 되죠.

그러면 example2.lua의 return value 가 package.loaded table 에 저장 될 겁니다.

package.loaded["example2"]

만약 example2.lua에 있는 코드가 다시 execute 될 필요가 있다면 package.loaded table 에서 remove 한 다음에 다시 call 하시면 됩니다.


아래 그 예제가 있습니다.


main.lua


require "example2"
-- Terminal: example2.lua has been loaded.

package.loaded["example2"] = nil

require "example2"
-- Terminal: example2.lua has been loaded.

require "example2"
-- Terminal:


This is Universal

여러분이 만든 모듈이든 아니면 다운로드 된 모듈이든 혹은 built-in 모듈이든 이 모듈들을 다룰 때는 위에 설명드린 대로 외부 모듈들이 작동합니다.

스토리 보드의 scene들을 다룰 때 그 scene이 로드될 떄 스토리보드 리스너 함수안에 있는 코드들이 어떤 것은 실행되고 어떤 것은 실행되지 않는지에 대한것도 궁금하실 겁니다.

거기에 대한 것은 다음 기회에 다루도록 하겠습니다.

반응형


반응형
Posted on . Written by


수요일 FAQ 시간입니다. 이번주는 Mac Simulator와 native text objects들의 displaying fonts에 대한 다섯가지 질문을 다루겠습니다.


1. How can I keep the (Mac) Simulator window from resizing when I relaunch my app?


Daily Build 883에 새로 시작할 때 디바이스 윈도우를 resizing에 대해 Mac 시뮬레이터의 크기를 유지하는 옵션이 들어갔습니다.  Corona Simulator/Preferences… 로 가서  “Automatically scale simulator to fit screen.”의 선택을 해제 하세요.







2. Why does my app start up in a (Mac) Simulator with a window that is larger than my display?


작은 display들에 큰 디바이스 윈도우 (iPad나 iPad Retina 같은) 를 display 할 떄 맥 시뮬레이터는 relaunch 된 이후에 zoom을 하는 경우가 있습니다. 그래서 실제 스크린크기보다도 더 큰 device window가 나오기도 합니다. Zooming out(Cmd-) 는 display back을 합니다. 새로 zoom out된 것을 재 조정했다고 하더라도 다음번에 relaunch 하게 되면 똑 같은 현상이 일어납니다.


build 883 에서 이 부분에 대해 수정했습니다. 스크린에 맞게 조정할 뿐만 아니라 이전에 유저가 zoom 했던 세팅을 기억해서 다음에 relaunch 할 때 시뮬레이터의 위치와 zoom level을 유지하도록 합니다.


또한 Window 메뉴에 center 라는 옵션을 추가했습니다. 이 옵션을 추가하면 현재 display window의 중심에 위치 시키게 됩니다. 만약 여러분이 여러 디스플레이를 사용한다면 아주 유용할 겁니다. display를 바꾸게 되면 화면 밖으로 나가게 되는 경우도 있죠. 이 기능에 대한 hot key 는 Shift Cmd UpArrow 입니다.


맥 시뮬레이터에는 또 다른 기능이 추가 됐는데요. 디바이스의 테두리를 없앨 수 있습니다.

디바이스 창의 테두리를 없애면 더 여유로운 screen 공간을 사용할 수 있고 스크린에 딱 맞는 디바이스 창을 더 수월하게 해 줍니다. 이 기능은 특히 큰 태블릿 디바이스를 display 할 때 유용합니다.

Corona Simulator/Preferences…로 가셔서 “Display device border (takes effect on next simulator relaunch”를 체크하세요. 말씀드렸듯이 바뀐 기능을 적용하려면 시뮬레이터를 재시작(Cmd r) 하시면 됩니다.


3. Why does the Mac Simulator keep crashing on Mountain Lion (10.8) when I relaunch my app a few times?


맥 시뮬레이터에서 약간의 메모리 누수를 찾았는데요. 여러분이 앱을 relaunch 할 때마다 발생하더라구요. 여러분 시스템의 메모리 여유가 별로 없다면 그리고 앱의 relaunch를 자주 하다보면 시뮬레이터가 crash를 일으 킬 수 있습니다. simulator가 close 되면 누수된 메모리가 다시 해제 됩니다. 이 이슈는 Lion (10.7) 에서도 발생하는데요. 10.8 버전에서는 더 많은 메모리를 사용하는데요 그래서 이러한 일들이 10.8 시스템에서 더 많이 보고 됩니다.


좋은 소식은 daily build 883에서 이 에러를 수정했다는 겁니다. 이 버그는 애플의 Image Kit code 내의 internal bug 때문에 일어난다는 원인을 발견했고 이 문제를 해결하기 위해 애플의 기능이 아는 우리의 routine들을 사용하도록 고쳤습니다. (애플에 bug report 도 했습니다.)


조만간에 public release 에서도 이 수정된 사항이 적용되도록 하겠습니다.


4. Why don’t the fonts in native TextFields and TextBoxes scale correctly on different devices?


config.lua 에서 dynamic scaling을 enable 하면 코로나는 모든 vector, 이미지 그리고 native 객체들을 scale 해서 현재 display에 맞게 맞출 겁니다. 이때 scale 하지 않는 것들은 native.newTextFieldnative.newTextBox에서 사용하는 폰트들입니다. 폰트를 scaling 하게 되면 다른 display 객체들의 scaling이 제대로 작동 안할 때도 있습니다. 각 폰트들 마다 차지하는 공간들이 다르기 때문에 이런 일들이 발생하는데요. native 텍스트 필드에서 폰트를 scale 하려면 여러분이 사용하는 폰트가 있는 코드 부분에서 하셔야 합니다.


여러분이 네이티브 텍스트 필드에 14 포인트의 폰트를 지정했다면 그 텍스트는 scaling facor와 관계 없이 모든 디바이스에서 14 포인트로 display 될 겁니다.

이러한 현상은 오직 native text object에만 해당됩니다. display.newText를 사용한 폰트는 bit 이미지로 랜더링 되기 때문에 제대로 scaling 됩니다.


5. Why don’t the fonts in native TextFields and TextBox scale correctly in the Simulator?


시뮬레이터에서도 4번과 비슷한 현상이 발생하는데요. 시뮬레이터는 zoom in, zoom out을 할 수 있고 시뮬레이션 되는 디바이스를 바꿀 수 있습니다. 하지만 native text object의 폰트 사이즈는 언제나 같습니다. 그러니까 14포인트의 폰트는 zoom level 과 관계없이 항상 14 포인트로 보이게 되는 것이죠. 실제 디바이스에서 display.newText로 생성된 텍스트는 제대로 scale 될 겁니다.



여기까지가 오늘의 FAQ 입니다.

유익한 시간이셨기를 바랍니다.



반응형

스토리 보드 기본 사용법

2012. 8. 23. 04:48 | Posted by 솔웅


반응형
Posted on . Written by



스토리보드 API는 아주 강력하고 flexible 하지만 new user들에게는 아주 헛갈리게 한다는 걸 인정해야겠네요. 그리고 Director Class 같은 3rd party scene management library를 사용하다가 스토리보드를 사용하려는 개발자 들도 헛갈릴 겁니다.

오늘은 이 간단한 Storyboard API를 정말 간단하게 사용하고 싶은 분들에게 기본적인 스토리보드 사용법에 대해 안내를 할 까 합니다. 아마 Director Class 만큼이나 간단할 겁니다. 스토리보드에는 많은 유용한 기능이 있지만 이 기능들이 항상 사용되야만 하는 것은 아닙니다. 그러니까 처음부터 이 모든걸 다 이해할 필요는 없습니다.

이 튜토리얼은 스토리보드 API를 빠르고 쉽게 사용할 수 있는 기본적인 기능에 대해서 다루려고 합니다.




Setup


스토리보드 API는 대부분의 다른 3rd party scene management libraries 하고는 약간 다른것들이 있습니다. 특히 화면 전환 부분이 그렇죠. 디폴트로 스토리보드의  scene 들은  화면전환 (scene transiton) 할 때 이전 scene들이 removed or purged 되지 않습니다. 대부분의 third-party scene management libraries 에서는 화면이 전환 될 때마다 이전 화면(scene)이 remove 되죠. Storyboard API에서도 이렇게 할 수가 있는데요. 자동으로 이전 scene들을 remove 하려면 함수가 call 될 때마다 inactive scene들을 purge 되도록 main.lua에 세팅할 수 있습니다.



main.lua


local storyboard = require "storyboard"
storyboard.purgeOnSceneChange = true


완전 간단하죠?


Scene Modules



Director class 에서는 scene 모듈은 new()라는 한개의 함수로 만들어 졌었습니다. 이 함수는 scene이 로딩 될 때마다 call 되게 되죠. 옵션으로 scene이 unload 될 때 call 되는 clean() 함수도 있었습니다. 아래는 Director Class에서 보여지는 scene 코드 입니다.


Director Class Scene


module(..., package.seeall)

-- setup function:
function new() 
    local localGroup = display.newGroup()

    local img = display.newImage( "hello.png" )
    localGroup:insert( img )
   
    return localGroup
end

-- cleanup function:
function clean()
    print( "Called when scene is unloaded." )
end



Storyboard API 를 사용할 때도 비슷한 structure와 로직이 적용될 수 있습니다. (위에 Setup 섹션에서 보실 수 있습니다.). Director Class 에서 위와 같이 사용해서 얻는 기능과 비슷하게 Storyboard API에서도 아래와 같이 코딩을 할 수 있습니다.



Storyboard Scene


local storyboard = require "storyboard"
local scene = storyboard.newScene()

-- setup function:
function scene:createScene( event )
    local img = display.newImage( "image.png" )
    self.view:insert( img )
end
scene:addEventListener( "createScene" )

-- cleanup function:
function scene:destroyScene( event )
    print( "Called when scene is unloaded." )
end
scene:addEventListener( "destroyScene" )

return scene



많이 다르지는 않죠? 코딩은 약간 다르지만 그 로직은 완전히 같습니다. createScene 이벤트 리스너에 모든 scene creation과 로직을 넣으시면 됩니다. 그리고 모든 cleanup 코드는 “destroyScene” event listener 에 넣으시면 되죠.


createScene 리스너는 Director의 new 함수와 비슷한 기능을 합니다. 그리고 destroyScene 리스너는 clean 함수와 하는 기능은 거의 같죠. main.lua 파일에 storyboard.purgeOnSceneChange를 true 로 하는 것을 잊지 마세요. 그렇게 하지 않으면 화면은 전환 할 때마다 destroyScene 이벤트가 자동적으로 dispatch 되지 않을 겁니다.


이제 여러분의 Storyboard API의 scene들을 어떻게 하면 Director 클래스와 비슷하게 셋업할 수 있는지 알게 됐습니다. 이제  storyboard.gotoScene() 를 사용해서 화면 전환을 하시기만 하면 됩니다.


Conclusion

Storyboard API 에 가시면 훨씬 더 많은 기능을 보실 수 있을 겁니다. 그 기능들은 필요하실 때만 가져다가 쓰시면 됩니다. 대부분의 경우 특히 Director Class를 사용하시다가 Storyboard로 전환하시는 분들에게는 이 튜토리얼이면 충분히 쉽게 스토리보드를 이해하시고 사용하실 수 있을겁니다.

반응형


반응형
Posted on . Written by


또 다시 돌아왔습니다. FAQ 시간 입니다. 아래 자주 나오는 질문 5가지가 있습니다. 오늘은 Display object를 Lisener로 pass 하는 방법과 off-line에서 CoronaSDK document에 접근하는 방법에 대해 얘기하겠습니다.



1. How can I access the display object in the “transition.to” listener?

"tween" 이 finish 할 때 call 되는 리스너 함수로 transition.to과 transiditon.from 파라미터가 있습니다. 

리스너에 보내지는 파라미터는 transition에 의해 콘트롤 되는 Display Object(target)의 reference 입니다. 이것은 여러분에게 multiple transition들에 대해 일반적인 리스너를 이용할 수 있도록 해 줍니다.


local square = display.newRect( 0, 0, 100, 100 )
local w,h = display.contentWidth, display.contentHeight


local function listener1( target )
        print( "Transition 1 completed on object: " .. tostring( target ), target.x, target.y )
end


transition.to( square, { time=1500, alpha=0, x=(w-50), y=(h-50), onComplete=listener1 } )



Note 제가 onComplete=listener1()를 사용하지 않고 onComplete=listener1를 사용했죠? 둘 이 다른 점은 onComplete=listener1는 리스너의 함수에 레퍼런스를 passing 한다는 겁니다. onComplete=listener1()는 리스너를 initialization 할 때 call 하죠 그리고 transition (화면전환)이 끝났을 때 call 되는 함수처럼 리스너로부터 return 되는 것을 사용합니다.


2. I need to cancel the “transition” for multiple display objects. Is there an easy way to find the transition ID for each object?


transition을 cancel 하려면 transition.cancel을 call 해야 되요 이때 transition ID로 call 해야 됩니다. 이 transition ID는 transition이 처음 생성될 때 return 됩니다. 이 ID는 어딘가에 저장해 놔야 됩니다. 로컬 변수나 테이블에 저장할 수 있겠죠.


그런데 더 쉬운 그리고 더 편한 방법은 그 객체 자체에 attach 하는 겁니다. 코로나에서는 display object에 custom property들을 추가 할 수 있는 기능을 제공합니다. transitionID라는 custom property를 만들어서 여기에 저장하면 좋습니다.


저는  display의 이름을 저장하는데도 사용합니다. 그러면 디버깅할 때도 편리합니다. (e.g., object.name).

아래 transitionID를 어떻게 저장하는지 보여주는 예제가 있습니다



local square = display.newRect( 0, 0, 100, 100 )
local w,h = display.contentWidth, display.contentHeight


local function listener1( target )
        print( "Transition 1 completed on object: " .. tostring( target ), target.x, target.y )
end


square.transitionID = transition.to( square, { time=3000, alpha=0, x=(w-50), y=(h-50), onComplete=listener1 } )
timer.performWithDelay( 1500, function() transition.cancel( square.transitionID ) end )



위 코드는 transition 이 반쯤 됐을 때 cancel 하는 timer 함수를 추가했습니다. 나머지는 첫번째 예제와 비슷하고 움직이죠. 여기서는 이 transition을 cancel 하기 위해 필요한 ID를 save 하기위해 square.transitionID를 사용했습니다.



3. How can I pass the display object to a function when I’m using “timer.performWithDelay”?


비슷한 질문에 대한 대답을 FAQ #3에서 했었습니다만 어떻게 Display Object를 listener로 pass 하는지에 대해 보여 드리겠습니다.

timer.performWithDelay는 보통 listener의 address(reference)와 함께 call 됩니다. 그러니까 delay가 finish 된 후에 call 될 수가 있죠. 

여기서 함수가 call 됐을 때 pass 되는 display object에 대한 reference를 hold 할 로컬 변수를 생성하기 위해 루아의 closures를 사용할 수 있습니다. 아래 그 예제가 있습니다.



local rect = display.newRect( 0, 0, 100, 100 )


local function timerListener( object )
    return function()
        print( "Rect x,y = ", object.x, object.y )
    end
end


timer.performWithDelay( 1000, timerListener( rect ) )



timerListener “listener”는 함수에 대한 reference 대신에 call 되는 함수 입니다. 이 함수를 call 하는것은 저장된 object 변수에 접근할 수 있는 anonymous 함수의 reference를 return 하도록 합니다. 그 object는 timerListener에 pass 됩니다. 그 시기는 timer가 첫번째로 initialized 될 때이고 return 된 anonymous 함수는 delay time이 종료 된 이후에 call 된 함수처럼 사용 됩니다.

오직 한 객체에 대해서만 리스너를 사용할 거라면 이 방법은 그리 유용하지 않을 겁니다. 이 기능의 장점은 리스너가 많은 객체들을 다룰 때 그 진가가 나타날 겁니다. 그 리스너는 deplay object에만이 아니라 테이블, 스트링 그리고 number에도 적용 됩니다.


4. I’m confused about what parameters are available in event listeners.


리스너에 보내지는 이벤트 파라미터가 무엇인지 이해하시려면 CoronaSDK documentation를 참조하세요.  그리고 리스너에 어떤것이 pass 되는지도 확인하세요. event 정보는 파라미터들의 table 입니다. 이 table을 dump 하는 간단한 예제가 이것을 이해하는데 그리고 디버깅 하는데 도움을 드릴 겁니다. 아래 제가 찾아낸 유용한 디버그 코드가 있습니다. 어떻게 동작하는지 보여주기 위해 touch 리스너를 사용했습니다.



local function touchListener( event )
--- Debug Event parameters printout --------------------------------------------------
print();print( "Listener events:" )
for k,v in pairs( event ) do
print( " " .. tostring( k ) .. "(" .. tostring( v ) .. ")" )
end
--- End of debug Event routine -------------------------------------------------------
return true
end
Runtime:addEventListener( "touch", touchListener )


아래가 스크린을 touch 했을 때 화면에 출력되는 event 파라미터들입니다.


Listener events:
y(66)
x(193)
time(84950.623)
id(userdata: 0x1000df3e0)
phase(began)
yStart(66)
xStart(193)
name(touch)
Listener events:
y(68)
x(193)
time(86388.318)
id(userdata: 0x1000df3e0)
phase(moved)
yStart(66)
xStart(193)
name(touch)
Listener events:
y(68)
x(193)
time(86746.278)
id(userdata: 0x1000df3e0)
phase(ended)
yStart(66)
xStart(193)
name(touch)


5. Sometimes I don’t have an Internet connection. Is there a way to access CoronaSDK documentation off-line?


만약 질문자께서 CoronaSDK subscriber라면 Daily Build page 로 가면 off-line 버전 CoronaSDK API document를 다운 방으실 수 있습니다. CoronaApiDocs file 각 daily build 마다 하나씩 가지고 있습니다. 다운받아서 여러분 컴퓨터에 unzip 하시기만 하면 됩니다. api 폴더를 열고 index.html을 double click을 하세요. 그러면 브라우저에 CoronaAPI document가 열릴겁니다.





여기까지가 오늘의 questions 입니다. 유익한 시간이셨기를 바랍니다.



반응형


반응형
Posted on . Written by



여러분 앱이 너무 많은 메모리를 차지한다면 OS는 low memory warning을 보낼 겁니다. 이 메세지의 의미는 뭔가 하라는 거겠죠. (메모리를 좀 더 풀어 주라던가 하는....) 계속해서 많은 메모리를 차지하고 있으면 OS는 아마 여러분 앱을 강제로 종료 시킬 겁니다. 여러분 앱이 강제로 종료 되면 유저 입장에서 보면 뭔가가 잘 못되서 앱이 끝난 겁니다. 그 앱에 대해 부정적인 이미지를 줄 수 있겠죠.


오늘 다룰 주제에서는 이 low memory warning이 왔을 때 어떻게 대응할 것인가 입니다. 그리고 crash를 방지하기 위해 해야 할 몇가지를 추천해 드릴거구요.


NOTE: Low memory warnings들은 현재 안드로이드 플랫폼에서는 제공하지 않습니다. 그러니까 오늘의 튜토리얼은 대부분 iOS에 포커스를 둔 겁니다. 하지만 예방 방법은 모든 플랫폼에 마찬가지로 적용할 수 있을 겁니다.






Responding to the Warnings


memory warnings에 응답하기 위해서는 memoryWarning 이벤트 리스너를 Runtime object에 추가 해야 합니다. 이 튜토리얼에서는 여러분이 main.lua에서 작업하는 것을 상정하고 얘기를 진행하겠습니다.


Runtime:addEventListener( "memoryWarning", onMemoryWarning )


만약 memoryWarning 이벤트 리스닝을 중지하고 싶으면 아래처럼 이벤트 리스너를 제거하면 됩니다.


Runtime:removeEventListener( "memoryWarning", onMemoryWarning )


만약 main.lua 가 아닌 다른 모듈에서 이 momoryWarning을 적용한다면 그 이벤트 리스너가 앱이 처음 시작할 때 로딩되지 않을 겁니다. 


The Listener


이제 onMemoryWarning 함수에 실제로 무엇을 넣을지는 여러분이 정하실 사항입니다. 왜냐하면 각 앱마다 로직이 다 다르고 그 자세한 사항은 여러분 만이 알 것이기 때문이죠. 

그 작업을 할 때 아래 사항들을 염두에 두시고 하세요.


  • 필요하지 않은 객체들은 가능한 모두 Unload 한다.
  • 필요하지 않은 이벤트 리스너들 특히 enterFrame 리스너 같은 것들은 stop 시킨다.
  • 현재 active 되 있지 않은 scene들은 Parge 하고 remove 시킨다. (try: storyboard.removeAll())
  • 제일 핵심사항은 필요하지 않은 것들은 다 제거한다 입니다.


아래 예제가 있습니다.


local function onMemoryWarning( event )
    audio.dispose( someAudioHandle )
    storyboard.removeAll()
end
Runtime:addEventListener( "memoryWarning", onMemoryWarning )


Preventing Memory Warnings


여러분이 할 수 있는 최선의 방법은 우선 memory warning이 일어나지 않도록 예방하는 겁니다. 정확히 무엇을 해야 된다라고 딱 찝어 내서 얘기할 수는 없습니다. 왜냐하면 여러분이 앱을 개발하는 사람이기 때문입니다. 그래도 몇가지 아이디어는 드릴 수 있습니다.


  • heavy scene으로 전환하기에 앞서 다른 모든 scene들을 purge 시키세요. (혹은 여러분의 scene을 생성할 때 그 이전의 모든 scene들을 purge 시키세요)
    See: storyboard.purgeAll()
  • 다양한 플랫폼과 디바이스에서 작업을 하신다면 프로그램 내에서 그 디바이스가 lower-performance device인지를 체크하세요. 그렇다면 그런 디바이스에는 다른 그래픽 set을 로드하시거나 좀 더 작은 객체들을 로드하도록 하세요.
  • 뭐가 필요하고 뭐가 필요 없는지 판단해서 불필요한 것들은 버리세요.
  • 코드를 한줄 한줄 다시 살펴 보세요. 혹시 어디엔가 메모리 누수현상이 없는지......


여러분들 앱에 맞게 여러분이 할 수 있는 다른 많은 것들이 있을 겁니다. 명심할 것은 memory warning 이 일어나기 전에 가능한 많은 리소스들을 free up 시키자는 겁니다. memoryWarning 이벤트에서는 더 말할 나위가 없겠죠. 그렇게 함으로서 OS 가 여러분 App 을 Kill 하는 것을 막는게 목표입니다.

반응형


반응형
Posted on . Written by


storyboard API를 사용해서 switch between scenes 한다는 말은 딱 들어면 뭔지 알겠죠? 단지 scene이 바뀔 동안에 어떻게 데이터를 관리해야 하는지가 애매할 뿐이죠.

이게 왜 애매하냐 하면 대부분의 스토리보드 scene들이 각 모듈별로 (e.g. scene1.lua, scene2.lua) 관리 되고 이렇게 다른 파일들간에 왔다 갔다 할 때 어떻게 파일들간에 데이터를 공유할 것인지를 다루는게 쉽지는 않기 때문이죠. 특히 scene들이 어느때든지 create 되고 destory 될 수 있기 때문에 더 그렇습니다.

오늘의 튜토리얼에서 저는 scene들 사이에서 데이터를 공유할 수 있는 몇가지 방법을 보여드릴 겁니다. 그리고 여러 scene들의 로딩과 unloading 을 거치면서도 여러분 앱 안에서 singular overall "state"를 관리하는 방법들에 대해서도 보실 수 있을 겁니다.




Parameter Passing


한 scene에서 다른 scene으로 전환하기 위해서 storyboard.gotoScene()을 부를 때 여러분은 파라미터를 보낼 수 있고 이 파라미터는 다음 화면의 createScene, willEnterScene, and enterScene들에서 받을 수 있습니다.

아래 예제에서 우리는 score 변수를 gameplay scene에서 gameover scene으로 pass 할 겁니다.


gameplay.lua


-- ...

storyboard.gotoScene( "gameover", {
    effect = "fade",
    time = 800,
    params = {
        score = 100
    }
})

-- ...


gameover.lua


-- ...

function scene:enterScene( event )
    local score = event.params.score

    print( "You scored: " .. score )
end
scene:addEventListener( "enterScene", scene )

-- ...


Persistent Variables


한 scene에서 다음 scene으로 어떤 데이터를 패스해야 할 때 바로 위에서 보여 준 파라미터 passing 방법이 제일 좋은 방법일 겁니다. 그런데 가끔 전체 앱에서 일관되게 공유되어야 할 데이터가 있을 수 있습니다. 혹은 모든 scene 에서 접근 가능한 데이터가 필요할 때가 있습니다. 이럴 경우에는 파라미터를 pass 하는 방법이 최선의 방법이 아닐 수 있죠.

이런 경우 global 변수를 사용하거나 (그렇게 추천할 문한 방법은 아닙니다.) 혹은 모든 scene에서 access 가능한 스토리보드 객체에 attach 되는 state 테이블을 생성하실 수 있습니다. (모든 scene들은 반드시 storyboard 모듈을 require 합니다.)

아래에 global 변수를 사용하지않고 모든 scene들에서 접근 가능한 score 프로퍼티를 어떻게 사용하는지에 대한 예제가 있습니다.


main.lua


local storyboard = require "storyboard"

storyboard.state = {}
storyboard.state.score = 0

-- ...


gameplay.lua


local storyboard = require "storyboard"

-- ...

storyboard.state.score = storyboard.state.score + 100;
storyboard.gotoScene( "gameover", {
    effect = "fade",
    time = 800
})

-- ...


gameover.lua


local storyboard = require "storyboard"

-- ...

function scene:enterScene( event )
    print( "Your score is: " .. storyboard.state.score );
end
scene:addEventListener( "enterScene", scene )

-- ...


모든 scene들은 require( “storyboard” )를 반드시 해야 됩니다. 그러면 그 scene들은 common object를 share 하게 되는 거죠. main.lua에서 state 테이블을 선언했습니다. 그러면 그 테이블에 원하는 만큼의 변수를 추가할 수 있게 됩니다. 그 변수들은 require( “storyboard” )를 한 모든 모듈에서 접근 가능하게 되는 것이죠. global namespace를 사용해서 소스를 지저분하게 하지 않고서두요.

scene들 사이에 데이터를 공유하는 다른 방법들도 있을 겁니다. 위에 제시한 방법은 저희들이 추천드리는 방법입니다. 여러분들이 사용하시는 multiple modules and scenes 사이에서 데이터를 share 하는 방법은 뭐가 있습니까?

반응형


반응형
Posted on

. Written by


수요일입니다. 수요일의 FAQ 시간이죠. 아래에 자주 질문되는 (FAQ)것들에 대한 답변들이 있습니다.


1. Is CoronSDK 840 (Release) compatible with Mountain Lion?


예 2012.840 버전은 OSX 10.8 (Mountain Lion) 에서 잘 작동합니다. Mac Simulater가 unsigned 인 상황에서는 신뢰할 수 없는 문제가 발생했고 프로그램이 작동하지 않을 거라는 메세지를 보실겁니다. 이럴 때는 앱을 작동시키기 위해서 Gatekeeper 안에 security 세팅을 하셔야 합니다. System Preferences/Security & Privacy/General로 가세요. 그리고 Anywhere 옵션을 클릭하세요.



한번 퍼미션을 세팅해 두고 CoronaSDK가 한번 실행하고 나면 여러분은 다시 돌아가셔서 여러분의 시스템을 보호하기 위해 다시 reset 하실 수 있습니다. 이 이슈가 현재 release 된 버전에 있는 유일한 이슈입니다. 지금 현재 나와있는 daily builds를 사용하시면 이 과정도 필요없고 아무런 문제 없이 사용하실 겁니다.


2. Does CoronaSDK work with the new MacBook Retina?


코로나 SDK는 new retina display 에서 잘 작동을 하지만 low resolution 모드라야 합니다. 이 모드는 현재 daily builds 버전 (2012.865 이후 버전)에서는 세팅돼 있지만 2012.840 버전에서는 여러분이 세팅을 하셔야 합니다.

이 release build 버전을 사용하시고 low resolution으로 모드가 세팅돼 있지 않다면 text가 있어야 할 자리에 black block이 나타나는 것 같은 여러 display 문제들을 보실 수 있을 겁니다.

CoronaSDK에서 이 모드를 세팅하시려면 Finder app을 사용하셔서 CoronaSDK 폴더로 가 주세요. Corona Simulator.app을 마우스 오른쪽 클릭을 하시고 (Corona Terminal 이 아님) Get Info를 선택해 주세요. 그리고 Open in Low Resolution 옵션을 선택해 주시면 됩니다.


3. What build can I use to build for an older iOS (e.g, iOS 3.1.3)?


현재의 release (840) 버전은 iOS 4.3 대 버전만 지원합니다. 그 이유는 애플이 다른 IOS 버전의 지원을 중단했기 때문이죠. 여러분 앱의 최신 CoronaSDK를 필요로 하지 않으면 2012.704b 버전을 다운받아서 사용하세요. 이것은 Daily Build 페이지에 있는데 유료 등록자로 로그인을 해야지 접근 하실 수 있습니다. 이것은 iOS 3.1에서 5.1 버전 까지 지원하는 SDK입니다. 그러니까 iPad Retina 까지 지원되죠. 2012.704a 는 iPad Retina를 지원하지 않습니다.


4. Why don’t I see any errors when I run the Mac Simulator?


시뮬레이터를 돌릴때 터미널에는 에러나 wornings 그리고 print messages들이 보여집니다 윈도우즈에서는 시뮬레이터를 실행하면 터미널이 자동으로 open 됩니다. 맥에서는 Corona Terminal을 따로 오픈해야 합니다. Corona Simulator.app 이 아닙니다. 두 프로그램 모두다 CoronaSDK 폴더에 있습니다. 여러분이 coronaSDK를 인스톨 할 때 그 폴더는 Application 폴더 아래에 위치하게 됐을 겁니다.


여러분이 Corona Terminal을 시작하면 Terminal window가 열리고 Corona Simulator가 시작합니다. Corona Simulator 앱만 running  하는 것은 그냥 앱이 동작하는 것을 보이기만 하고 터미널에 뜨는 정보들이 필요 없는 경우에 유용할 겁니다.


Mac CoronaSDK와 관련된 팁을 하나 알려드리자면 여러분은 여러개의 인스톨 된 CoronaSDK 카피들을 가질 수 있습니다. 시스템에서 코로나가 running 할 때도요. 아마 build 버전 840 과 현재 daily build 버전을 여러분 맥 컴퓨터에 인스톨 할 수 있습니다. 이렇게 하면 여러 버전의 코로나로 테스트 할 수 있겠죠. 새로운 Mac CoronaSDK를 다운로드 받아서 인스톨 할 때마다 저는 CoronaSDK 폴더에 build number를 추가합니다. 그러니까 release build 인 경우에는 CoronaSDK를 CoronaSDK-840 으로 이름을 바꾸죠. 여러분 시스템에서 running 하는 모든 CoronsSDK 들은 같은 preference file들을 공유합니다. 그러니까 최근의 히스토리와 preferences 세팅이 모든 버전에 apply 될 겁니다.


5. What are the keyboard shortcuts for the Simulator?


맥이나 윈도우지 시뮬레이터 모두 다양한 키보드 shortcut들이 있습니다. 여기 제가 찾은 유용한 shortcut들이 있습니다. 윈도우즈에서는 control 키를 누르고 Mac 에서는 command 키를 누르고 아래 키들을 눌러 보세요.


R               Relaunch the simulator with the current project
O               Open an existing project
B               iOS Build window
Shift B         Android Build window
+               Zoom In (makes the "skin" larger)
-               Zoom Out (makes the "skin" smaller)
Left arrow      Rotate the "skin" left
Right arrow     Rotate the "skin" right
Up arrow        Simulate device "shake"
Down arrow      Suspend/Resume simulator



여기까지가 오늘의 질문과 답변들입니다. 유익한 시간이었기를 바랍니다.



반응형