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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

Posted on . Written by


오늘의 튜토리얼은 코로나 Ambassador 이면서 Mobile App Development with Corona: Getting Started.”의 저자인 Brian Burton 의 글입니다. 이글은  Burton’s Media Group에서 발표된 내용입니다.


제가 자주 하는 질문 중 하나가 remote server 에서 어떻게 데이터를 mobile app 으로 전달할 수가 있는가 입니다. (대개 그 데이터는 데이터베이스에 저장되 있겠죠.)

이와 관련해서 가장 좋은 방법을 소개해 드리려고 많이 연구했습니다. 아마 얼마나 많은 방법들을 제가 시도해 봤는지 알려드리려면 시리즈를 연재해야 될 겁니다. 데이터를 가지고 올 수 있는 방법은 아주 많이 있고 또 여러 possibilities 들도 많이 있습니다. 모두 찾아내려면 아마 끝이 안 날 겁니다. 그래서 이것들을 더 찾아내고나서 몇달 후에 얘기하는 것보다 리모트 서버에서 모바일 앱으로 데이터를 전달하는 한가지 방법이라도 우선 소개해 드리는게 좋을 것 같습니다.


The Process


간단하게 하기 위해 표준 3-tier architecture 를 사용할 겁니다.




Remote Database


이 튜토리얼에서는 리모트 서버에 MySQL을 만들어 둘 겁니다. 3개의 필드를 가지고 있는 1개의 테이블을 사용하겠습니다. (id, Movie (title), Year (영화가 릴리즈 된 해)




Logic or Middleware


MySQL 데이트베이스로부터 데이터를 pull 해 오기 위한 middleware 로 PHP를 사용하겠습니다.  그리고 그 데이터를 모바일 디바이스에 return 하기 전에 JSON format 으로 encoding 할 겁니다.


<?php
$host="localhost"; //replace with your hostname
$username="database_example"; //replace with your username
$password="Password"; //replace with your password
$db_name="MyMovies"; //replace with your database
$con=mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name") or die ("cannot select DB");
$sql = "select * from BestMovies"; //replace with your table name
$result = mysql_query($sql);
$json = array();
if(mysql_num_rows($result)){while($row=mysql_fetch_row($result)){
$json[]=$row;
}
}
mysql_close($db_name);
echo json_encode($json);
?>

Client


아래는 remote server 로부터 정보를 가져오고 JSON 형식으로 된 그 정보를 decode 하는 코로나 소스코드 입니다. 이 파일을 local SQLite file로 저장하세요. 그리고 나서 SQLite 의 content 로 화면에 load 하세요. 데이터베이스는 persistent 입니다. 그러니까 이 코드를 여러번 실행해서 remote database를 call 하면 SQLite 데이터베이스에 new data 를 계속 추가할 겁니다.


local sqlite3 = require ("sqlite3")
local myNewData
local json = require ("json")
local decodedData

local SaveData = function ()

  --Save new data to a sqlite file
  --open SQLite database, if it doesn't exist, create database
  local path = system.pathForFile("movies.sqlite", system.DocumentsDirectory)
  db = sqlite3.open( path )
  print(path)
      
  --setup the table if it doesn't exist
  local tablesetup = "CREATE TABLE IF NOT EXISTS mymovies
(id INTEGER PRIMARY KEY, movie, year);"
  db:exec( tablesetup )
  print(tablesetup)
    
  --save data to database
  local counter = 1
  local index = "movie"..counter
  local movie = decodedData[index]
  print(movie)

  while ( movie ~= nil ) do
    local tablefill ="INSERT INTO mymovies
VALUES (NULL,'"
.. movie[2] .. "','" .. movie[3] .."');"
    print(tablefill)
    db:exec( tablefill )
    counter=counter+1
    index = "movie"..counter
    movie = decodedData[index]
  end
 
  --everything is saved to SQLite database; close database
  db:close()
      
  --Load database contents to screen
  --open database
  local path = system.pathForFile("movies.sqlite", system.DocumentsDirectory)
  db = sqlite3.open( path )
  print(path)
        
  --print all the table contents
  local sql = "SELECT * FROM mymovies"
  for row in db:nrows(sql) do
    local text = row.movie.." "..row.year
    local t = display.newText( text, 20, 30 * row.id, native.systemFont, 24 )
    t:setTextColor( 255,255,255 )
  end
  db:close()

end


local function networkListener( event )

  if ( event.isError ) then
    print( "Network error!")
  else
    myNewData = event.response
    print ("From server: "..myNewData)
    decodedData = (json.decode( myNewData))
    SaveData()
  end

end
network.request( "http://www.BurtonsMediaGroup.com/myMovies.php",
"GET", networkListener )


여기까지가 기본적인 튜토리얼 입니다. 유튜브에 좀 더 자세하게 설명한 비디오를 올렸습니다.

보시려면 유튜브를 참조하세요.




반응형

코로나 : New public release 발표

2012. 11. 21. 19:59 | Posted by 솔웅


반응형
Posted on . Written by


지난주 새로운 공개버전 릴리즈에 대해 넌지시 얘기 드렸었습니다. 오늘 latest Corona public release버전이 공개 돼 누구나 다운로드 받아서 사용할 수 있게 됐습니다.


이번 공개 버전에는 수 많은 기능들과 개선 사항들 그리고 에러 수정이 있습니다. 자세한 내용들은  2012.971 release notes 에서 보실 수 있습니다.


모바일 industry 는 holiday season을 앞두고 가을에 새로운 디바이스들을 release 하는 경향이 있습니다. 이번 시즌에는 iPhone 5, Kindle Fire HD7" 와 8.9", Nook HD 와 HD+ 그리고 iPad Mini 등이 있습니다. 정말 많은 device 들이 발표 됐네요!


그래서 저희들은 이번 릴리즈에 이 새로운 device 들과 그에 따라 발표되는 새로운 OS update에 주로 포커스를 맞춰서 작업했습니다. 이번 public release에 앞서 저희들은 실시간으로 daily builds를 통해서 이 작업을 했었습니다. iOS 6 의 GameCenter orientation 버그와 Nook HD compatibility, iOS 6 Beta 용 device builds 등등 이 그것입니다.




또한 많은 분들이 요청하셨던 안드로이드 관련 주요 기능 지원에 대해서도작업을 했구요. 그 중에 두가지만 얘기하자면 map views and notifications 가 있습니다. (예 그리고 remote push 가 곧 지원될 겁니다.) 이와 관련해서 저희들은 모든 안드로이드 flavor들에도 이 기능들이 원활히 작동되도록 만들었습니다. 사실 이 작업이 아주 많은 일을 해야 되는 부분 입니다. 만약 여러분이 Android SDK 를 사용한다면 맵에 대해서는 별도로 3번의 코딩을 해야 합니다. 왜냐하면 구글은 Google Play 를 통한 Android device들에 대해서만 맵을 지원하거든요. (아마존이나 Barnes and noble 앱 스토어용 앱은 별도로 작업해야 합니다.) 하지만 Corona SDK 에서는 한번의 코딩에서 이런 다양한 안드로이드 flavor 들에서 작동이 되도록 만들었습니다.


이쪽 바닥은 아주 빛의 속도로 움직이고 있기 때문에 저희들도 이 속도에 맞춰서 engineering process들을 잡아가고 있습니다. 그래서 모든 변화에 거의 동시간으로 여러분께 해당 기능 지원이 가능한 버전을 선사해 드리고 있습니다. 기존에 계획했던 것들도 시장이 상황이 많이 변하면 재빠르게 거기에 맞춰서 계획을 수정하고 대응해 나가고 있는 상황입니다.





daily builds에서 가장 중요한 부분은 버그를 잡는 부분입니다. 이상한 점이 발견되면 바로 다음번 daily build에서 이 사항들을 수정하고 있습니다. 이것이 저희의 방침입니다. 작년과 비교하면 daily build 의 quality 는 확실히 나아졌고 일관성을 꾸준히 유지해 가고 있습니다.


여러분 모두가 다음번 daily build 에서 함께 했으면 합니다.


다음 daily builds 는 담주 월요일(11/26) 저녁이 될 겁니다.



반응형


반응형
Posted on . Written by


오늘의 guest tutorial 은 Omid Ahoural 의 두번째 글 입니다. ArdentKid 라는 별명으로 불리는 inDie Game Developer 입니다. 지난 2년간 Omid는 코로나를 접해 왔습니다. 그리고 그가 참여한 첫번째 앱인 "Balloon Bazooka" 의 출시를 앞두고 있습니다. 그는 또한 Corona 강좌를 제공하고 있기도 하구요. 그의 블로그 www.ardentkid.com에 가시면 보실 수 있습니다.



Optimizing Transitions


이제 곧 나올 저의 게임 퍼포먼스를 올리기 위해서 game sprite들에 좀 더 효율적인 transition을 사용하기로 했습니다. TimeSpaceMagic 같은 library들을 찾을 수 있었는데요. pause 와 time-warping 관련한 겁니다. 이 라이브러리들은 모두 transition property들인 at Runtime을 calculate 하는데요 작업하는데 꽤 힘든 일 입니다. transition이 항상 같다면 이런 작업은 필요 없겠죠.


그래서 저는 AK-Tween 을 만들었습니다. predetermining transitions 과 그것들을 at Runtime 에 manually 적용하는 겁니다. 다른 것들을 벤치마크해서 다른 Runtime transition 접근법보다 (제가 찾은 가장 efficient 한 방법보다도) 20% 정도 빠르게 동작하도록 만들었습니다. 이 라리브러리의 alpha 버전은 AS3의 GTween을 바탕으로 해서 쉽게 만들 수 있었습니다.  그러니까 이 라이브러리는 그 결과가 코로나의 transition easing 과 비교해도 비슷할 만큼 쉽게 만들었습니다. (아래 iPhone4 테스트 결과를 보세요.)


The Core Idea


“AK-Tween”  의 계산(calculates) 는 table이나 배열에 저장된 값들에 의해 load time (Runtime이 아닌)에 일어납니다. 그리고 그 값들이 필요하면 custom Runtime function을 사용해서 iterate 합니다. 아래에 배열값을 return 하는 tween calculation code 의 일 부분이 있습니다. 한 눈에 보시고 이해하실 수 있도록 간략하게 만들었습니다.


--AKtween.lua
local function tweenCalc( config, anim )

  local time = config.time or 1000
  local ease = config.ease
  local totFrames = 0.06 * time --frames at 60FPS

  local step = 1/totFrames

  if ( ease == "outQuad" ) then

    for i=1,totFrames do
      pos = pos + step
      local index = i +startArr
      local ratio = -pos * (pos-2) arr[index] = from + (ratio * delta)
    end

  elseif ( tween == "inQuad" ) then
    ...

  end

  return arr
end



아래는 이 tween 을 실제로 set up 하는 부분입니다. (예제로 공이 튕기는 것을 구현하겠습니다.)


--CREATE TWEEN FOR BALL BOUNCE
local AKtween = require( "AKtween" )

local ball = display.newImage( "ball.png" )

local bounceTween = AKtween:newTween( {time=400, y=-120, ease="outQuad"} )
--bounceTween.yArr = [-4.79, -4.58, -4.37, -4.16, -3.95 ...
-0.83, -0.625, -0.416, -0.20, 0]
--#bounceTween.yArr = 24

bounceTween:append( {time=400, y=0, "inQuad"} )
--bounceTween.yArr = [-4.79, -4.58, -4.37, ...
-0.416, -0.20, 0, 0.20, 0.416 ... 4.37, 4.58, 4.79]
--#bounceTween.yArr = 48

ball.yBounceArr = bounceTween.yArr --JUST GET THE Y-VALUES,
--bounceTween:apply( ball, "bounce" )
--OR ALLOW AKTWEEN TO HANDLE THE WHOLE ANIMATION
 

이렇게 하면 y=0 to y=-120 까지 볼이 튀어 올라가고 다시 내려올 겁니다. 그 움직임은 quadratic ease를 사용해서 자연스러울 거구요.  시간은 400ms 가 걸릴겁니다. (24 frames at 60 fps). 우리가 한 일은 마지막 줄에 :apply() function을 call 한 것입니다. 그리고 이 tween을 AKtween 에 의해 제대로 컨트롤 되게 하기 위해 ball:playTween(“bounce”)를 사용했습니다. 이것과 똑 같은 일을 할건데요. 라이브러리에서 생성된 y-value array만 사용해 보겠습니다.

그러니까 ball.yBounceArrpredetermined y-values가 저장돼 있는 거죠. Runtime ball:bounce() script를 set up 하기만 하면 됩니다.


function ball:bounce()
local yVals = self.yBounceArr
  local totFrames = #yVals
  local curFrame = 1

  --RUNTIME SCRIPT, OCCURS ON EVERY FRAME
  local function frameCount()
    if ( curFrame <= totFrames ) then
      self:translate( 0, yVals[curFrame] )
      curFrame = curFrame+1
    else
      curFrame = 1
    end
  end

  --SAVE REFERENCE TO RUNTIME FUNCTION, AND BEGIN
  self.bounceFC = frameCount
  Runtime:addEventListener( "enterFrame", frameCount )

end


 


불이 튕기기를 원하면 언제든지 ball:bounce()를 call 합니다. 그러면 frameCount라고
하는 local Runtime script 를 setup 합니다. 이는 frameCount는 각 프레임마다 공에
새로운 y의 위치값을 세팅할 겁니다.

이 reference는 또한 ball.bounceFC에도 저장돼 있습니다. 이 ball.bounceFC
튕기는 것을 pause, resume, or stop할 수 있게 합니다.


function ball:pause()

  if ( self.bounceFC ) then
    Runtime:removeEventListener( "enterFrame", self.bounceFC )
  end
end

function ball:resume()
  if ( self.bounceFC ) then
    Runtime:addEventListener( "enterFrame", self.bounceFC )
  end
end

function ball:stop()
  if ( self.bounceFC ) then
    Runtime:removeEventListener( "enterFrame", self.bounceFC )
    self.bounceFC = nil
  end
end

manual way 는 regular transition 보다 implement 하는데 더 어렵습니다. 하지만
자신만의 animation property들을 사용해서 원하는 결과를 정확히 만들어 낼 수
있는 장점이 있죠.

performance 측면에서도 아주 효율적입니다. 또한 pause-enabled 하구요.
저의 dynamic sprites implementation과 같이 사용하면 게임이 아주 자연스럽게 움직일
겁니다.


Benchmark Results



아래가 이 메소드를 사용한 후의 benchmark result 입니다.
두 매뉴얼과 AKtween play function 들은 아래와 같이 주목할 만한 결과를 보여 줍니다.


요약하자면 우리는 우리의 object들을 transitioning 하기 위해
underlying alternate method를 정의했습니다.
이러한 benchmark는 이 메소드가 아주 효율적이라는 것을 증명했구요.
우리는 그냥 단순히 배열에서 값을 읽어서 이것을 해당 object property 에 적용하는
일만 합니다.

이러한 작업은 AKtween juggler에 object를 pass 함으로서 그 기능을 사용하게 됩니다.
혹은 local runtime script를 추가하거나 제거함으로서 애니메이션을 전체적으로 control
할 수 있습니다.

두 방법 모두 AKtween을 사용하시면 됩니다. 이것이 여러분 앱 개발에 도움이 될 수
있는지 잘 확인해 보세요.




반응형


반응형
Posted on . Written by


Team Corona,


오늘 아침 more funding을 발표 했습니다. 3년전 우리들의 original funding 이 얼마였는지를 생각하면 내년도에는 우리가 무엇을 하고 있을까에 대해 extremely excited 해 집니다.


그 마음으로 Corona가 가는 방향에 대해 여러분과 간략하게 공유하고 싶은 것들이 있습니다.

첫번째로 리더와 follower가 있습니다. 그리고 나중에는 많은 경쟁자들로부터의 많은 attention이 있습니다. 여러분 모두에게 감사드립니다. 코로나는 이제 market leader 입니다. 지금 world 는 지금 우리가 하고 있는 것들을 imitate 하고 있는 동안 우리는 world 가 어디로 가야할 지에 focus를 맞추고 있습니다.


초기에 우리는 여러분들이 앱을 만들 수 있어야 된다고 믿었습니다. 그리고 여러분들은 코로나와 함께 next hit app을 만들 수 있다고 믿었습니다. 그리고 몇년 후인 지금 우리는 indies 부터 studios 까지 그리고 10대들 부터 80대(octogenarians) 까지 모든 개발자들이 사용할 수 있는 유일한 모바일 플랫폼이 됐습니다.



게다가 우리는 끊임없이 개선하고 발전해 나가고 있습니다. platform을 만드는 것은 정말로 어려운 일입니다. 왜냐하면 만드는 것 자체로 끝나는 게 아니거든요. 이것을 재빠르게 adapt 해야 합니다. 예를 들어 iOS 6 가 나왔을 때 GameCenter orientation 같은 애플 버그(Apple bugs)에 저희들은 재빠르게 대처해 나갔습니다. 그리고 iPhone 5 가 나왔을 때 여러분들이 이 새로운 기기에 맞게 어떻게 앱을 만들어야 하는지 대처방법을 제공한 유일한 platform 이었습니다.


저는 한달이 지난 지금에야 우리의 경쟁자들이 이러한 작업을 하기 시작하는 것을 보게 됩니다. 그 동안 industry 는 계속 변해가고 있습니다. 그리고 우리가 유일하게 그것을 따라가고 있습니다. iOS 6.1 Beta 1 이 나왔을 때 저희들이 유일하게 이를 위한 device build 를 가능하도록 했습니다. 애플이 그것을 release 한 바로 다음날에요.


앞으로를 보죠. 저희들은 여러분들에게 선 보일 여러 기능들이 pipeline에 가지고 있습니다. 아래 내용들이 그중 일부분 입니다.

  • New graphics engine: shaders + image filters + augmented reality + full blending modes + more
  • Add-ons: lots more 3rd party services and monetization options
  • Going beyond gaming: from next-generation widgets to web-based technologies


이것 외에도 여러가지 것들이 곧 발표를 기다리고 있습니다. 우리는 higher standard를 지향하고 있습니다. 여러분들께 약속 드립니다. 설익은 빵을 여러분들에게 제공하지 않겠습니다. 온전한 기능들을 그리고 higher standard를 제공해 드리겠습니다. 저희들은 항상 higher 를 aiming 하고 있습니다.


매일 저녁 저는 집으로 가는 길에 Computer History Museum 을 지나갑니다. 그리고 10여년 후에 사람들이 하는 얘기들을 상상합니다. 그 말 중에는 지금 우리들이 하는 일들도 있을 겁니다. 우리 팀과 여러분들이 만들어 나가는 이 일들도 있을 겁니다. 우리는 같이 software 의 pantheon을 만듭니다.


우리는 같이 역사를 만들고 있습니다.


Walter



==== 개인적으로 Corona SDK 를 접한지도 2년이 됩니다. Corona SDK 는 태어난지 3년이 됩니다. Corona SDK 자체로도 편리하고 아주 유용하지만 그것을 만들고 운영해 나가는 조직이 활기차고 젊고 열정적입니다. Walter는 지금 Corona SDK의 CEO 입니다. 그와 그 팀들 그리고 저를 비롯한 수많은 Corona SDK 가 진짜 역사를 만들것을 믿습니다. 저는 지금 회사에서 다른 Web App 프로젝트에 참여를 하고 있어서 Corona SDK 작업은 하고 있지 않지만. 계속 새로 나오는 소식, 새로 나오는 기술들을 제 블로그에 정리하면서 때를 기다리고 있습니다.

그리고 이 정리하고 있는 글들이 관심있는 한국분들에게 조금이라도 도움이 되면 좋겠습니다. ===




반응형


반응형
Posted on . Written by


코로나에서의 안드로이드 notification 에 대해 새로운 소식을 전해 드리기로 했죠. 그리고 안드로이드와 iOS 의 notification 은 완전히 다른 거라서 cross-platform development가 얼마나 어려운 건지를 이 기능이 잘 보여준다고 말씀 드렸구요.



만약 우리가 iOS 플랫폼을 위해서만 개발을 했다면 이런 기능들을 아주 빨리 추가하고 다른 일들도 빨리빨리 진행 해 나갔을 겁니다. 하지만 우리는 Android 도 지원을 하고 있습니다. 그 외에도 desktop app 이나 Corona Simulator 에서 동작할 수 있도록하는 작업도 해야 되구요. 그리고 사실 Mac 과 윈도우에서도 동작하도록 하는 작업도 하고 있습니다.


The ‘I’ in API


이 4개의 OS들 중 안드로이드 부분이 일 진행이 가장 더딥니다. 내부적으로 우리끼리 통하는 룰이 있습니다. 안드로이드 관련 작업은 최소한 5~10배는 더 다른것들보다 소요 된다구요. 거기에는 두가지 원인이 있습니다.


첫번째로 안드로이드에는 mulriple (forked) flavor들이 있습니다. 게다가 standard Android (Google Play) 이외에도 Kindle 과 NOOK 이 있구요 여기에도 각각 자신들의 앱 스토어가 있습니다. 이런 이유 때문에 같은 버전이라도 모든 안드로이드 디바이스들에 맞게 다르게 작업을 해야 하는 부분들이 있습니다. 일례로 OpenGL device driver 가 각 디바이스별로 다른 performance 를 보여주기 때문에 별도로 작업을 해야 했습니다. 여기에 여러 다른 서비스들이 있죠. 예를 들어 maps, in-app purchase, notification 등등이요. 이런 서비스들도 서로 완전히 다릅니다. 이런 서비스들에 어떤 변화가 오면 서로 다른 OS들은 물론 같은 OS라도 서로 다른 device 별로 개발과 테스트를 따로 해야 됩니다.



두번째로는 Android API는 그렇게 충실하지 못합니다. 어떤 경우에는 API 자체에 잘못된 부분도 있지요. 하지만 그것보다도 저는 API design 자체가 충실하지 못합니다. 제 생각에 API 의 I 는 interface 대신 interaction 으로 해야 더 맞다고 생각합니다. 그 이유는 개발자가 이 것들과 interact 해야만 하니까요. iOS API 는 NextStep에서 온 오리지널 MacOS API 가 개선된 걸 겁니다. 그러니까 이 API는 10 수년간 다듬어 진 것이지요. 그리고 오랜 기간동안 다듬어진 것처럼 보이기도 합니다. naming 과 API 의 semantic이 일관성있게 만들어 져 있습니다.



반면에 안드로이드는 새로 만든 API 입니다. 그리고 아주 좋은 API라고 할 수는 없습니다. 우리는 안드로이드 API 중에 awkward한 API를 아주 많이 봤습니다. 그리고 85% 정도만 설명이 돼 있고 15% 부족한 부분도 많이 봤습니다.


예를 들어서 안드로이드에서 multitouch 를 implement 할 때 많은 장애물들을 뛰어 넘고 나서야 각각의 touch들을 identify 할 수 있었습니다. 화면에 손가락이 touch 됐을 때 그 터치 이벤트가 터치되고 move 되고 화면에서 떼어질 때까지 같은 id를 갖고 있어야 합니다. multitouch 에서는 이 부분이 아주 중요하죠. 여러 터치 이벤트 들을 서로 구분해야 하니까요. 하지만 안드로이드의 MotionEvent 에서 이 id 들은 unique 하지가 않습니다. 그래서 저희들은 저희들의 방법을 따로 만들어야 했습니다.




Android notification infrastructure (or lack thereof)


안드로이드를 상대로 일을 할 때 우리만의 방법을 만들어 내야만 하는 경우는 이제 저희들에게는 일반적인 것으로 받아들여 집니다. 그리고 안드로이드의 notification을 만들 때도 마찬가지로 저희 팀은 저희들만의 방법을 만들어서 부족한 부분을 메꾸어 넣어야 했습니다. 우리가 iOS 에서 한 것과 비슷하게 안드로이드에서도 기능하도록 하기 위해서 저희들은 여러 scaffolding 을 만들어야 했습니다.


예를 들어 Corona API 에서는 notification을 schedule 하는 기능이 있습니다. iOS notion 에서는 단 한줄로 이 기능을 사용할 수 있었습니다. 그런데 안드로이드에서는요... 그렇게 쉽지는 않았습니다. 거기에는 schedule notification 기능이 없었습니다. 그래서 저희들이 그 기능을 만들어 넣어야 했지요.


이 부분은 그렇게 큰 문제는 아니었습니다. 정말로 큰 문제는 안드로이드가 자신의 notification을 관리하기 위해 app에 요구하는 것들이었습니다. 즉 앱은 notification work을 만들기 위해 여러 가지로 관리되어야만 합니다. 특히 앱이 background로 돌아갈 때나 강제로 앱이 exit 됐을 때 혹은 phone 이 reboot 될 때 등입니다. None of these come out of the box.


여러분의 앱이 background로 돌아갈 때 (예를 들어 back button을 눌렀을 떄) scheduled notification은 시간이 되면 나타나야 합니다. 여러분이 앱을 강제로 종료했을 때 schedule 된 notification은 나타나지 않을 겁니다. 이게 안드로이드의 limitation 입니다. OS 가 제공해야 되는 기능인데 제공하지 못하고 있는 거죠.


다른 경우는, 여러분이 앱을 강제로 종료했거나 phone을 reboot 했다면 notification은 status bar 가 사라지면서 그 자리에 나타날 겁니다. 왜냐하면 notification은 앱과 연결돼 있고 OS 에서 globally reside 되지 않기 때문이죠. 그래서 우리가 무엇을 했는가 하면 이 notification을 persist 하도록 한 겁니다. 그래서 앱을 relaunch 하면 이 notification들은 status bar 안에 다시 나타나게 됩니다. 메일 앱에서의 기능이랑 비슷한 거죠.


무슨 의미냐 하면 notification이 scheduled 되면 이 notification들은 오직 앱이 foreground 이거나 background 일 경우에만 나타납니다. 그리고 만약 그 앱이 강제 종료 됐거나 phone 이 reboot 됐다면 그 notification은 나타나지 않는 겁니다.


status bar 에 나타나는 notification이 흥미로운 부분입니다. 왜냐하면 애플리케이션은 status bar에 나타나는 자신의 notification을 manage 해야하거든요. 왜냐하면 메일 앱이 하는 것처럼 우리가 그 notification을 persist 했으니까요. 유저가 tap 하게 되면 status bar에 있는 notification을 clear 혹은 remove 시켜야 합니다. 그래야지 persistence data가 제대로 sync'd 되니까요.


그 위에 저희들은 안드로이드에 unique 한 것들을 몇개 추가했습니다. 코로나의 디폴트 notification icon 대신에 여러분의 custom icon을 넣을 수 있도록요. 그리고 iOS notification에 익숙한 분들을 위한 몇가지 기능들도요. 그리고 custom notification sound 같은 것들도...



이런 것들은 모두 나름대로의 trick 을 사용한 겁니다. 하지만 제대로 동작을 하죠. 저희들은 standard Android, Kindle, NOOK 에서 돌아가는 notification system 을 만든 겁니다.


이런 작업들이 안드로이드에 remote push notification 기능을 코로나에서 지원하도록 하기 위해 한 작업들 입니다. Google Play's service (Google Cloud Messaging)들은 standard Android device에서만 제공된다는 것을 유의하세요. 


==== 원문은 저 위의 제목에 달린 링크를 따라 가시면 나옵니다. 이해가 안되게 번역이 됐거나 잘 못 번역이 된 것은 다 제 실력이 모자라기 때문입니다. 필요하시면 저 링크를 클릭해서 원문을 참조하세요. ===

반응형


반응형
Posted on . Written by



정신 없는 한 주 였습니다. 이제 겨우 의자에 엉덩이를 붙여 이 글을 쓸 수 있게 됐네요. 오늘 알려드릴 Electronic Arts and Corona와 관련된 건데요. 이것 말고도 곧 발표될 내용들이 많이 기다리고 있습니다. Electronic Arts and Corona는 그 시작일 뿐이죠.


새로운 기술적인 부분도 많이 진행되고 있습니다. 지금은 새로운 device들의 season 인것 같습니다. Kindle HD, NOOK HD, iPhone 5, iPad Mini 등 많은 새로운 디바이스들이 쏟아져 나오고 있습니다. 그래서 이번에 new public release 를 하려고 합니다.






여기에는 두가지 의미가 담겨 있습니다. 첫번째는 여러 기능들이 유료 사용자만 다운 받을 수 있는 new daily builds 가 아닌 모든 사람들이 다운 받을 수 있는 public 버전에 포함될 거라는 겁니다. 새로운 기능들이 완전히 확정이 되서 발표 된다는 것이죠. 두번째는 그 이후에 나오는 daily builds 들은 이 public 버전의 버그들을 fix 한 내용들이 당분간 적용이 될 겁니다.


추신 : 제 기억이 맞다면 제가 안드로이드와 notification 에 대해 여러분들에게 새로운 소식을 전해드리기로 했었죠? 지난주에...... 곧 알려드리겠습니다. 코로나의 진정한 cross-platform experience 를 보여드리기 위해 이 작업에 만전을 기하고 있으니까요.



반응형


반응형

Posted on

. Written by



오늘 Electronic Arts (EA)사가 Word Smack game을 새로 개발해서 출시했다는 소식을 기쁘게 알려드립니다. 바로 모두가 좋아하는 cross-platform development platform으로 개발을 한 게임입니다. 예 맞습니다. 세계에서 가장 큰 게임 개발사 중의 하나인 EA 사가 코로나로 게임을 개발해서 출시했습니다.




Corona team 은 good guessing game 을 사랑합니다. EA의 Word Smack 는 정말 짱이구요. 두개의 유명한 보드 게임을 합쳐놓은 것 같아요. Mastermind 하고 Scrabble 요. Word Smack 는 2인용 게임이구요. 3라운드에 5 글자의 단어를 맞추는 거예요. 처음 게임을 시작하면 보드에 글자가 보일 겁니다. 그러면 나머지 칸을 여러분이 다른 글자로 채워 넣는 거예요.



너무 쉽게 생각하지 마세요. 만만치 않아요. 고맙게도 Word Smack 은 오른쪽에 살짝 힌트를 제공해 줘요. 만약에 맞는 글자(알파벳)인데 칸을 다른 곳에 넣었다면 이것을 알 수 있게 해주죠. Facebook integration은 친구들끼리 시합을 할 수도 있게 해 줍니다. 그리고 random 하게 상대방을 골라서 게임을 할 수도 있구요. 상대편 보다 단어를 더 빨리 맞추면 되는 겁니다.





word game 을 좋아하는 분들을 위해 power up 기능을 구입할 수도 있습니다. power up 은 word synonym들을 제공합니다. Word Smack 은 바로 오늘 출시 됐습니다. 

App Store에서 지금 당장 free 버전을 다운 받아 보세요.



반응형

새 위젯 사용하기 Part 1

2012. 11. 8. 21:44 | Posted by 솔웅


반응형

Posted on . Written by


만약 여러분이 Corona Indie 나 Pro 의 등록자라면 daily builds 를 다운 받아서 사용하실 수 있으실 겁니다. 그리고 Build 947 에 new widgets 들이 포함된 내용도 전달 받으셨을 겁니다. 이 포함된 widget들은 아래 사항들을 포함하고 있습니다.


  • switch — in the form of a radio button, checkbox, or “on/off” slider.
  • segmented control — a “segmented button” in which each segment responds individually.


이 새 위젯들은 일반적인 특성을 따르고 있습니다. 각 위젯들은 새로운 widget library foundation 을 바탕으로 추가 돼 좀 더 flexible 하고 essentially 합니다.


Patience Please!



이 새 위젯들은 widget library 의 개선해 나가는 것들 중의 일부입니다. 더 많은 widget들이 다음주에 더 새로운 모습으로 소개 될 겁니다. 그 각각에 대해 cover 할 수 있도록 tutorial 을 작성해 드릴겁니다. 지난 widget들과 비교하면 거의 새로운 기반하에서 새롭게 작성되어야 할 정도로 많은 변화가 있었습니다. 여러분들은 아직까지 이전 위젯들을 사용하고 계실 건데요. 이전 위젯들에 대해서는 중요한 버그들에 대한 수정만 해 나갈 것이고 그 기능에 대한 개선이나 변경은 없을 겁니다. 이번주 다음주에 발표할 새로운 위젯들이 기존의 위젯들을 대신해 나가도록 진행할 계획입니다.


이 글은 native iOS visual theme 에 대해 설명드립니다. Android theme 은 다음번 daily build 에서 추가될 겁니다. 물론 굳이 이 주어진 visual theme만 사용할 수 있는 건 아닙니다. 여러분들 나람대로 스타일링해서 위젯들을 customizing 해서 사용하실 수 있습니다.



Getting Started…


새 위젯들을 경험하기 위해 우선 새로운 project 부터 만듭니다.



1. “require” the widget library


Just like with many Corona libraries, you’ll need to “require” the widget library to use widgets:

다른 많은 Corona library들과 같이 widget을 사용하기 위해서는 widget library 를 require 합니다.


local widget = require( "widget" )

2. Copy theme file and assets



모든 widget들은 디폴트로 Lua file 이름에서 theme 정보를 가져옵니다. theme_ios.lua or (coming soon) theme_android.lua 가 그 파일 이름입니다. 이미지 파일들은 이 파일에서 정한 폴더에서 가져오게 됩니다. 위젯들은 custom theme file 을 세팅함으로서 스타일링할 수 있고 이미지 세트들도 생성할 수 있습니다. 이런 부분들은 약간 고급 기술 부분인데요. 나중에 이런 고급 기술 부분에 대해서 따로 다루도록 하겠습니다.


일단 default theme file과 asset folder를 여러분의 main project 디렉토리에 카피해 넣으세요. 이름은 theme_ios.lua and widget_ios가 될 겁니다.  이 파일들은 아래 경로로 가면 찾을 수 있습니다. 또는 이곳에서 다운로드 받으실 수도 있습니다.



CoronaSDK > SampleCode > Interface > WidgetDemo




3. Declare the theme using “setTheme()”


widget library 를 require 한 후 그 다음줄에 theme 을 정의해야 합니다.

아래 예제를 참조하세요. 처음부터 새로 만드실 필요는 없고 샘플로 드린 파일을

수정하셔서 사용하시면 편리하실 겁니다.


widget.setTheme( "theme_ios" )

NOTE:  Do not  append .lua to the reference passed to widget.setTheme().



Widget #1: Switch


첫번쨰로 선보일 새로운 widget 은 switch widget 입니다. 이 위젯은 세가지 종류가 있습니다.
checkbox, radio button, or on/off slider




Event Listener



이 위젯에 유저가 어떤 행위를 했을 때 이를 감지할 basic listener function를 생성하셔야 합니다. 이 섹션에서 사용할 샘플 리스너를 한들어 보죠.

아래 예제를 여러분 파일에 복사해 넣으세요.


local function onSwitchPress( event )
   local switch = event.target --event.target references the switch object
   local response = switch.id.." is on: "..tostring( switch.isOn )
   print( response )
   switch.text:setText( tostring( switch.isOn ) )
end


switch의 현 상태는 .isOn parameter에 의해 참조됩니다. 여러분은 이 프로퍼티를 사용해서 현재의 switch 상태를 파악할 수 있습니다. true 이면 selected 나 on 인 상태이구요. false 이면 off 나 deselected 상태입니다.



Checkbox



checkbox switch widget을 생성하려면 아래와 같이 하세요.


local checkbox = widget.newSwitch
{
   left = 60,
   top = 230,
   style = "checkbox",
   id = "My checkbox widget",
   initialSwitchState = false,
   onPress = onSwitchPress
}

-- Text to show the on/off switch state
checkbox.text = display.newEmbossedText( tostring( checkbox.isOn ), 0, 0, native.systemFontBold, 18 )
checkbox.text.x = checkbox.x
checkbox.text.y = checkbox.y - checkbox.text.contentHeight



보시다시피 실제 widget은 widget.newSwitch command를 사용해서 생성합니다. 그리고 디테일한 내용은 “options” table에 있습니다. 이 예제에서는 아래 프로퍼티들이 콤마로 구분돼 있습니다.


  • left and top (optional) — the left and top position of the switch. You can also position the switch normally by setting its x and y position afterward.
  • style — for this example, set it to checkbox.
  • id (optional) — this property allows you to set a named reference for the widget. This is useful if you want to use the same event listener function for several switches and identify a specific one by its .id property within the listener function.
  • initialSwitchState (optional) — true = on/selected; false = off/deselected.  Default is false.
  • onPress (optional) — listener function called when the switch is touched.



Radio Button


radio button
switch는 checkbox widget 이랑 거의 같은 방식으로 생성합니다. 다른 부분은 style parameter를 radio로 세팅하는 부분입니다. 위에 on-off 를 테스트하기 위해 만들었던 리스너 함수를 복사해서 여기서 사용하시면 됩니다.


local radioButton = widget.newSwitch
{
   left = 150,
   top = 230,
   style = "radio",
   id = "My radio button widget",
   initialSwitchState = false,
   onPress = onSwitchPress
}

-- Text to show the on/off switch state
radioButton.text = display.newEmbossedText( tostring( radioButton.isOn ), 0, 0, native.systemFontBold, 18 )
radioButton.text.x = radioButton.x
radioButton.text.y = radioButton.y - radioButton.text.contentHeight


 


On/Off Switch


on/off switch는 작은 “flick” switch 입니다. 일반 전등 스위치같은 역할을 하죠. 디폴트 switch widget 입니다. 셋업하는 부분은 switch widget 과 비슷한데요. 몇가지 key 가 다르죠. 기본 구조는 아래와 같습니다.


local onOffSwitch = widget.newSwitch
{
   left = 250,
   top = 230,
   id = "My on/off switch widget",
   initialSwitchState = true,
   onRelease = onSwitchPress
}


가장 많이 다른 부분은 event listener function 인데요. onPress parameter가 아닌 onRelease parameter 로 분류 됩니다.  이 경우 touch 가 released 되면 “release” event가 발생합니다.


Widget #2: Segmented Control


segmented control 은  multi-segment 버튼을 쉽게 만들 수 있도록 도와줍니다. 각 segment 별로 on/off 상태가 될 수 있고 그에 따라 관련된 값이 return 됩니다.



Event Listener


switch widget 처럼 segment control 에 대ㅐ 유저의 action 을 report 하기 위해 basic listener function을 생성해야 됩니다.


local function onControlPress( event )
   local target = event.target
   print( "Segment Label is:", target.segmentLabel )
   print( "Segment Number is:", target.segmentNumber )
end

 

이 segmented control 은 리스너에게 두가지 essential 값을 전달합니다. 유저가 touch 한 segment 의  segment labelsegment number 가 그 값들입니다.


Basic Segmented Control


segmented control 은 아주 간단합니다. 아래 예제를 보세요


local segmentedControl = widget.newSegmentedControl
{
   left = 65,
   top = 110,
   segments = { "s1", "s2", "s3", "s4" },
   segmentWidth = 50,
   defaultSegment = 4,
   onPress = onControlPress
}

  
  • left and top (optional) — the left and top position of the control. You can also position the control normally by setting its x and y position afterward.
  • segments — sub-table in which you define the segments; it determines the total count and the label that appears on each. Simply define them as comma-separated strings.
  • segmentWidth (optional) — the pixel width of each segment. Default is 50 pixels.
  • defaultSegment (optional) — this property allows you to set the segment that is “on” when the control is rendered. Specify a number between 1 and the total number of segments. If you don’t specify this property, it defaults to the first segment.
  • onPress (optional) — listener function called when the control is touched.


More to Come!


다른 훌륭한 widgets들이 이어서 선보입니다. 다음주 daily builds 가 릴리즈 될 때 선보일 예정인데요. 다음주 화요일의 Tutorial 을 통해서 그 위젯들에 대한 설명을 드리겠습니다. 그 동안 최신 daily build를 다운 받으시고 위 3개 widget들에 대해 익혀 두세요. daily builds 는 유료 등록하신 분들만 다운받으실 수 있습니다. 코로나의 최신 기술을 그 때 그 때 사용하고 싶으신 분은 지금 유료등록을 해 주세요.










반응형


반응형

오늘은 CoronaLabs 에서 facebook을 통해 알려준 Lua Performance 관련 한 정보를 정리하겠습니다.


있는 곳은 http://trac.caspring.org/wiki/LuaPerformance 입니다.


여기에 정리해 두고 나중에 Corona SDK project 진행할 때 미리 한번 훑어 보고 해야겠네요.



Things you should know about Lua's performance


This wiki is a result of some lua performance tests (the widget is included with ca sandbox).


TEST 1: localize

Code:

local min = math.min

Results:

normal way: 0.719 (158%)
localized: 0.453 (100%)

Conclusion:

  -> Yeah, we should localize all used funtions.


TEST 2: localized class-methods (with only 3 accesses!)

Code1:

  for i=1,1000000 do
    local x = class.test()
    local y = class.test()
    local z = class.test()
  end

Code2:

  for i=1,1000000 do
    local test = class.test
    local x = test()
    local y = test()
    local z = test()
  end

Results:

normal way: 1.203 (102%)
localized: 1.172 (100%)

Conclusion:

  -> No, it isn't faster to localize a class method IN the function call.


TEST 3: unpack a table

Code1:

  for i=1,1000000 do
    local x = min( a[1],a[2],a[3],a[4] )
  end

Code2:

  local unpack = unpack
  for i=1,1000000 do
    local x = min( unpack(a) )
  end

Code3:

  local function unpack4(a)
    return a[1],a[2],a[3],a[4]
  end
  for i=1,1000000 do
    local x = min( unpack4(a) )
  end

Results:

with [ ]: 0.485 (100%)
unpack(): 1.093 (225%)
custom unpack4: 0.641 (131%)

Conclusion:

  -> Don't use unpack() in time critical code!


TEST 4: determine maximum and set it ('>' vs. max)

Code1:

  local max = math.max
  for i=1,1000000 do
     x = max(random(cnt),x)
  end

Code2:

  for i=1,1000000 do
    local r = random(cnt)
    if (r>x) then x = r end
  end

Results:

math.max: 0.437 (156%)
'if > then': 0.282 (100%)

Conclusion:

  -> Don't use math.[max|min]() in time critical code!


TEST 5: nil checks ('if' vs. 'or')

Code1:

  for i=1,1000000 do
    local y,x
    if (random()>0.5) then y=1 end 
    if (y==nil) then x=1 else x=y end
  end

Code2:

  for i=1,1000000 do
    local y
    if (random()>0.5) then y=1 end 
    local x=y or 1
  end

Results:

nil-check: 0.297 (106%)
a=x or y: 0.281 (100%)

Conclusion:

  -> WOW! the or-operator is faster than a nil-check. Use it! :D


TEST 6: 'x2' vs. 'x*x'

Code1:

  for i=1,1000000 do
     local y = x^2
  end

Code2:

  for i=1,1000000 do
     local y = x*x
  end

Results:

x^2: 1.422 (110%)
x*x: 1.297 (100%)


TEST 7: modulus operators (math.mod vs. %)

Code1:

  local fmod = math.fmod
  for i=1,1000000 do
    if (fmod(i,30)<1) then
      local x = 1
    end
  end

Code2:

  for i=1,1000000 do
    if ((i%30)<1) then
      local x = 1
    end
  end

Results:

math.mod: 0.281 (355%)
%: 0.079 (100%)

Conclusion:

  -> Don't use math.fmod() for positive numbers (for negative ones % and fmod() have different results!)!


TEST 8: functions as param for other functions

Code1:

  local func1 = function(a,b,func) 
    return func(a+b) 
  end

  for i=1,1000000 do
    local x = func1(1,2,function(a) return a*2 end)
  end

Code2:

  local func1 = function(a,b,func) 
    return func(a+b) 
  end
  local func2 = function(a) 
    return a*2 
  end

  for i=1,1000000 do
    local x = func1(1,2,func2)
  end

Results:

defined in function param: 3.890 (1144%)
defined as local: 0.344 (100%)

Conclusion:

  -> REALLY, LOCALIZE YOUR FUNCTIONS ALWAYS BEFORE SENDING THEM INTO ANOTHER FUNCTION!!!
     i.e if you use gl.BeginEnd(), gl.CreateList(), ...!!!


TEST 9: for-loops

Code1:

  for i=1,1000000 do
    for j,v in pairs(a) do
      x=v
    end
  end

Code2:

  for i=1,1000000 do
    for j,v in ipairs(a) do
      x=v
    end
  end

Code3:

  for i=1,1000000 do
    for i=1,100 do
      x=a[i]
    end
  end

Code4:

  for i=1,1000000 do
    for i=1,#a do
      x=a[i]
    end
  end

Code5:

  for i=1,1000000 do
    local length = #a
    for i=1,length do
      x=a[i]
    end
  end

Results:

pairs: 3.078 (217%)
ipairs: 3.344 (236%)
for i=1,x do: 1.422 (100%)
for i=1,#atable do 1.422 (100%)
for i=1,atable_length do: 1.562 (110%)

Conclusion:

  -> Don't use pairs() or ipairs()!
     Try to save the table-size somewhere and use "for i=1,x do"!


TEST 10: array access (with [ ]) vs. object access (with .method)

Code1:

  for i=1,1000000 do
    x = a["foo"]
  end

Code2:

  for i=1,1000000 do
    x = a.foo
  end

Results:

atable["foo"]: 1.125 (100%)
atable.foo: 1.141 (101%)


TEST 11: buffered table item access

Code1:

  for i=1,1000000 do
    for n=1,100 do
      a[n].x=a[n].x+1
    end
  end

Code2:

  for i=1,1000000 do
    for n=1,100 do
      local y = a[n]
      y.x=y.x+1
    end
  end

Results:

'a[n].x=a[n].x+1': 1.453 (127%)
'local y=a[n]; y.x=y.x+1': 1.140 (100%)


TEST 12: adding table items (table.insert vs. [ ])

Code1:

  local tinsert = table.insert
  for i=1,1000000 do
    tinsert(a,i)
  end

Code2:

  for i=1,1000000 do
    a[i]=i
  end

Code3:

  for i=1,1000000 do
    a[#a+1]=i
  end

Code4:

  local count = 1
  for i=1,1000000 do
    d[count]=i
    count=count+1
  end

Results:

table.insert: 1.250 (727%)
a[i]: 0.172 (100%)
a[#a+1]=x: 0.453 (263%)
a[count++]=x: 0.203 (118%)

Conclusion:

  -> Don't use table.insert!!!
     Try to save the table-size somewhere and use "a[count+1]=x"!



반응형


반응형
Posted on . Written by


수요일 다시 FAQ 시간 입니다. 오늘은 Lua 와 관련해서 자주 들어오는 질문을 모아봤습니다. basic Lua language 프로그래밍에서 루아 언어만의 특징도 다뤘습니다.


1. Do I need to end Corona code lines with “;”?


아래와 같은 Corona(Lua) 코드를 보셨을 겁니다.


local myRect = display.newRect( 0, 0, 100, 50 );


또 아래와 같은 코드도 보셨을 겁니다.


local myRect = display.newRect( 0, 0, 100, 50 )


두 코드가 다른 것은 맨 마지막에 semicolon (“;”) character가 있느냐 없느냐죠. 많은 languages(JavaScript, C++, ObjectiveC, etc.) 라인의 끝을 가리키는 표시로 semicolon을 요구합니다. 하지만 Lua 는 굳이 semicolon을 넣지 않아도 스스로 알아서 라인의 끝을 인식합니다. 또한 맨 마지막에 semicolon 을 넣어도 상관은 없습니다. 단지 반드시 넣어야 되는 것은 아닙니다.


가끔 한 줄에 여러 statement를 넣을 때가 있죠.


a = 100; b = 200


Lua 에서는 아래 코드도 틀린 구문이 아닙니다.


a = 100 b = 200


2. Can Lua functions return multiple values?


이 기능은 Lua 만의 기능입니다. 바로 함수에서 여러 return 값을 반환할 수 있다는 거죠.

아래 예제를 보세요.


local function testConnection()
    if not noConnection then
        return false, "Connection Failed!"
    else
        return true
    end
end

local result, reason = testConnection()
print( result, reason )


connection이 fail 되면 false를 return 하고 동시에 string 도 return 할 수 있습니다. connection 이 제대로 작동하면 true 만 return 합니다. (reason 의 값은 nil 이 될 겁니다.)


3. Can you assign multiple values to multiple variables?


또한 Lua 에만 있는 편리한 기능이 한번에 여러 변수에 여러 값들을 대입하는 겁니다.


local red, green, blue = 100, 255, 128


이것은 아래 코드와 같습니다.


red = 100
green = 255
blue = 128


둘 중 어느 방법을 사용할 지는 여러분의 선택에 달렸습니다. 둘 다 맞는 거니까요.


4. Are parentheses needed in “if” statements?


몇 몇 language 들에서는 conditional statement 에 parentheses({}) 를 사용해야 합니다.


-- C code
if ( a > b) {
     ...
}


Lua 에서는 optional 입니다. 단지 then 과 end 를 사용해야합니다.


-- Lua code
if a > b then
    ...
end 


5. How do I add Block Comments to my code?


Block 주석은 코드에 어떤 설명을 넣거나 개발을 할 때 유용하게 사용할 수 있습니다.

아래 예제가 있습니다.


--[[
local function testConnection()
 if not noConnection then
 return false, "Connection Failed!"
 else
 return true
 end
end
--]]


이 주석은 “––[[“로 시작해서 ”––]]”로 끝났습니다. 루아에서는 이 주석을 해제하는 간단한 방법을 제공합니다. 주석 시작부분에 - 를 한번 더 넣으면 주석이 해제 되는 겁니다.


---[[
local function testConnection()
 if not noConnection then
 return false, "Connection Failed!"
 else
 return true
 end
end
--]]


위의 코드는 실행 될 겁니다. 왜냐하면 “–––[[“ (three dashes instead of two)를 사용했기 때문이죠.


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


감사합니다.


반응형