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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

Protesters Gather Locally in Response to Zimmerman Aquittal


Created: Sun, 14 Jul 2013 07:54:00 PST

Updated: Sun, 14 Jul 2013 08:02:13 PST





SAN DIEGO - Protesters planned to gather in City Heights and at Balboa Park Sunday night in response to George Zimmerman's acquittal in the shooting death of Florida teen Trayvon Martin last year.


지난해 플로리다에서 10대인 Trayvon Martin 을 총으로 쏴 사망하도록 한 죠지 짐머맨에 대한 무죄선고에 반대하는 시위자들은 일요일 밤 City Heights 와 Balboa Park 에 모이기로 했다.


The "San Diego Stand with Trayvon Martin Rally," began at 5:30 p.m. Highland Park was one of several events planned following the verdict that was announced Saturday.

At 7:30 p.m., "A Time for Healing Candle Vigil for Trayvon Martin" will be held at the Balboa Park fountain off Park Boulevard. The event is hosted by the San Diego NAACP and She is Soul.

오후 5시 30분에 시작된  "San Diego Stand with Trayvon Martin Rally," 는 토요일 발표된 배심원 평결문에 반발해서 계획된 여러 이벤트 중 하나였다. 오후 7시 30분에 "A Time for Healing Candle Vigil for Trayvon Martin"이 Balboa Park 분수대 밖인 Park Boulevard 에서 개최될 예정이다. 이 이벤트는 San Diego NAACP 와 She is Soul 이라는 단체에서 주최한다.



남미계 백인 경찰이 근무중 지시에 따르지 않는 흑인 소년에게 총을 쏴 죽게 만든 일이 작년 플로리다에서 일어났는데요.

지난 토요일 그 경찰이 무죄 평결을 받았습니다.

이에 반발하는 시위가 미국 여러곳에서 벌어지고 있습니다.


예전에 LA 폭동을 유발하는 로드니 킹 사건이 연상되네요.


이곳 샌디에고에서도 시위가 있었다고 하네요.


경찰 입장에서 보면 그 경찰이 이해가 가고 순진한 시민 입장에서 보면 그게 너무한 과잉 진압 인게 맞는 얘기고......


잘 모르겠네요.


한국도 국정원 선거개입에 항의하는 촛불집회가 점점 거세게 저항하고 있다죠?

모두 힘 내시고 이번일은 정말 상식적으로 처리되도록 했으면 좋겠습니다.


반응형


반응형

오늘은 정말 오랜만에 Corona SDK 의 한 샘플 코드를 받아서 공부 좀 해 봤습니다.


animationchain 이라는 소스인데요.


소스는 https://github.com/personalnadir/animation 에 가시면 보실 수 있습니다.


파일을 다운 받아서 실행시켜 보시면 아래와 같은 화면을 보실 겁니다.






화면에 빨간 점이 4개 찍혀 있고 하얀 공이 이 빨간 공들을 찍으면서 움직입니다.

궁금하신 분들은 파일 다운 받아서 직접 실행해 보시면 됩니다.


오늘은 우선  main.lua  파일을 분석해 보죠.


require "animationchain"

local stops={
    {x=20},
    {y=20},
    {x=200,simul=true},
    {y=600},
    {x=display.contentCenterX,y=display.contentCenterY,delete=true}
}

local x,y=display.contentCenterX,display.contentCenterY
for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
    end
end

local c=display.newCircle(display.contentCenterX,display.contentCenterY,20)
animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()


첫번째 줄은 animationchain.lua 라는 파일에 있는 함수를 implement 한다는 얘기 입니다.

오늘은 main.lua 만 다룰거니까 이 animationchain.lua 파일은 신경쓰지 않겠습니다.


다음은 stops 라는 배열에 key,value 형식으로 값들을 집어 넣었습니다.


다음은 x 와 y라는 변수에 화면 중심의 x, y 값을 대입했습니다.


그 다음은 for 문으로 위에 정해 줬던 stops 라는 key,value 쌍으로 돼 있는 배열을 돌면서 원을 만드네요.

화면에 찍힌 4개의 빨간색 점들이 이 for 루프를 돌면서 찍힌 겁니다.


display.newCircle(x,y,10):setFillColor(255,0,0) 는 지름이 10픽셀인 원을 x,y 좌표에 그리는데 그 원의 색은 빨간색 (RGB 에서 R 만 255이기 때문에 빨간색이 됩니다) 으로 그리라는 뜻입니다.

그다음에 또 원을 그리네요 c 라는 변수에 담기는 원을 그리는데요.

20픽셀의 지름을 갖는 원을 그리는데 그 위치는 화면의 중앙이 됩니다.

따로 원의 색을 지정해 주지 않았기 때문에 디폴트인 흰색(255,255,255)이 됩니다.


그 다음은 아까 require 에서 지정한 animationchain 이라는 파일 안에 있는 anim() 이라는 함수를 call 하는 겁니다.


일단 이 부분은 오늘 다루지 않을 부분이구요.


for 문에서 main.lua 의 주요 작업이 다 진행되니 이 for 문을 집중적으로 보겠습니다.

처음에 나오는게 ipairs 함수 입니다.


이 함수는 3개의 값을 return 합니다.

신택스는

for i,v in ipairs(t) do body; end

입니다.


이럴경우 (1,t[1]), (2,t[2]), ..., 이런 값들을 리턴하는데요. 이 루프는 ipairs안에 있는 t 라는 테이블의 마지막에 있는 값까지 도달하면 끝이 납니다.



그럼 main에 있는 for 문을 볼까요?


for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
    end
end


for 문만 보면 stops 에 있는 값들의 갯수 만큼 for  문이 돌겠군요.

그리고 그 값들은 1,stops[1], 2,stops[2] 이런식으로 진행이 됩니다.


다음줄은 x 에 v.x 나 x 를 대입하고 y에는 v.y나 y 를 대입합니다.

그러니까 v.x 가 있으면 그 값을 대입하고 그 값이 없으면 위에 지정한 x 값 즉 화면 중앙의 x 좌표값을 대입하게 됩니다.


그러니 처음 x 값은 stops 의 첫번째 값인 20 이 대입될 겁니다. 그 다음엔 y 값은 없으니까 for 문 바로 위에 지정해 둔 화면 중앙의 y 값이 대입될 거구요.


그리고 그 값을 x,y 값으로 해서 지름 10짜리의 빨간색 원을 그릴겁니다.


그 다음은 다시 for 문 처음으로 가는데 x, 값은 아까 지정된 20이 있을 테고 그 다음은 stops[2] 가 선택이 되니까 y 값으로 20이 지정될 겁니다.


그 다음에 두번째 빨간색 원이 그려질텐데 그 위치는 20,20이 될 겁니다.


다음 for 루프 돌 때는 stops[3] 가 되서 x는 200 이 되겠구 y는 따로 없으니까 바로 전에 지정된 20이 되겠네요.


그런데 if 문에서 v.simul이 아닐 경우에만 원을 그리라고 했으니까 이 원은 그려지지 않을 겁니다.


말로 설명하면 잘 감이 안올 수도 있으니까 눈으로 확인해 보겠습니다.


local stops={
    {x=20},
    {y=20},
    {x=200,simul=true},
    {y=600},
    {x=display.contentCenterX,y=display.contentCenterY,delete=true}
}

local x,y=display.contentCenterX,display.contentCenterY
for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    print (v.x )
    print (v.y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
        print (k ..  " : " .. x .. " , " .. y)
        cord = k .. " : " .. x .. "," .. y;
        display.newText(cord,x+10,y, native.systemFont, 20)
    end
end

local c=display.newCircle(display.contentCenterX,display.contentCenterY,20)


for 문 안에서 x, y 좌표를 console 하고 화면에 찍는 코드를 삽입했습니다.

그러면 결과는 아래와 같습니다.




보시면 첫번째 빨간 원은 20,427 이고 두번째는 20,20 입니다. 그리고 세번째는 200,20 이 될 텐데 if 문에 걸려서 이 세번째 원은 그려지지 않을 겁니다.

네번째는 200,600 이고 다섯번째는 stops 의 마지막 값으로 화면 정중앙에 있는 빨간 원이 그려집니다.



그냥 좌표값을 사용해서 그리면 될 텐데 왜 이렇게 복잡하게 할까요?


일단 이렇게 하면 코드의 양을 줄일 수 있고 빨간원이 그려지는 위치를 stops 배열 안에서 정해주면 되니까 나중에 수정하거나 할 떄 편해 집니다.

가독성이 좋고 maintanance 를 용이하게 해 주는 것이죠.


그리고 모바일은 기계마다 해상도가 다른데 이 stops 좌표를 각 해상도마다 따로 만들어 줘서 기계의 해상도에 따라서 다른 좌표를 사용해서 빨간 원을 그리게 할 때도 편리하게 이용할 수 있습니다.


맨 마지막 줄은 animationchain 파일에 있는 anim()함수를 call 하고 있습니다.

이 때 parameter들이 전달 되는데요.


첫번째 파라미터로 c 즉 하얀 원이 전달 됩니다. 이 c 가 움직일 거니까 이 객체를 파라미터로 전달해야겠죠.

그리고 두번째는 stops[1] 이 전달 됩니다. 이 하얀 공이 첫번째로 갈 목적지가 될 겁니다.


목적지에 도달하면 (whendone) 두번쨰로 c,stops[2] 를 인수로 해서 anim 을 call 하고 이 작업을 c,stops[5] 가 될 때까지 할 겁니다.


그 다음에 onStart()를 붙인 것은 transition이 일어나기 전에 이 onStart() 메소드를 실행하라는 의미입니다. 다음 파일안에 이 onStart 메소드가 있어야 되고 그 메소드 안에서 이벤트 대신 target이 pass 되도록 할 수 있습니다.


잘 이해가 안 되시는 분들은 API를 보시면 도움이 되실 겁니다.


여기서는 onComplete() 다음에 호출 되니까 공이 다 돌면 다음 transition 하기 전에 print 'done' 을 하라는 거네요.


그 다음은 animationchain 에 있는 start() 함수를 호출하는 거구요.


여기까지 main.lua 에 대해 공부해 봤습니다.


다음엔 이 오픈소스의 핵심인 animationchain 파일을 분석해 보겠습니다.


반응형


반응형
Posted on . Written by

 

Building on What’s There

 

이제 여러분의 함수가 API 에 있게 됐고 동작도 잘 되고 있습니다. 이제 코딩을 하면서 그 함수를 call 할 수 있는데요, API 의 새로운 기능을 알게 되는 건 기쁜 일이죠.

이제 기존에 string 라이브러리 함수들 중에 약간 문제 있는 것을 한번 살펴 볼까요. gsub() 함수는 개발자에게 쌈박한 기능을 제공하죠. documentation 페이지를 한번 보세요. 아마 이 함수는 기본적으로 search and replace 기능을 제공하는 함수라는 것을 아실 수 있으실 겁니다.

 

local str = "Hello banana"
print( string.gsub( str, "banana", "Corona user" ) )
--Outputs: Hello Corona user

 

이 함수의 한계는 key/value 를 테이블에 담아서 사용하게끔 기능을 제공하지는 않습니다. 아래처럼 말이죠.

local searchreplace = {
   Hello = "Success",
   banana = "Corona user"
}

 

이 기능을 가능하도록 하려면 테이블 내의 entry들에 대해 iterate 하기 위해 루프롤 돌려야 합니다. 그리고 각 entry 마다 gsub() 함수를 부르면 되죠.

local str = "Hello banana"
for k,v in pairs( searchreplace ) do
   str = string.gsub( str, k, v )
end

print( str )
--Outputs: Success Corona user

pairs() 함수는 searchreplace table에 있는 각각의 인덱스들을 identify 하고 그 이름과 값을 return 하는 함수입니다. Lua table 을 사전처럼 다룰 때 아주 유용하게 사용할 수 있겠죠. 루프 안의 내용들은 생각하지 마시고 이제 string replacement 를 어느곳에서나 사용할 수 있는 훌륭한 함수를 하나 만드신 것만 생각하세요.


이제 함수 안에 루프를 넣어 볼까요.

local function gsubEx( str, searchreplace )
   for k,v in pairs( searchreplace ) do
      str = string.gsub( str, k, v )
   end
   return str
end

이 함수는 string-replaceing 루프를 어느곳에서나 재사용할 수 있도록 해 줍니다.

gsubEx( str, searchreplace )
--Outputs: Success Corona user

아주 쉽죠?

 

Improving What’s There


이제 이것들을 다 같이 함치고 gsub() 함수에 override 해 보죠. 우선 gsub() 함수를 변수에 넣어야 합니다. 아까 보았듯이 Lua 에서는 아래와 같이 함수를 변수에 넣는 것을 지원해 주죠.

local gsub = string.gsub

이렇게 하면 이제 gsub 변수를 사용해서 gsub() 함수를 call 할 수 있게 된 거죠. 이제 함수를 저장했으니 우리가 만든 함수를 이 변수에 replace 해서 gsub 함수를 overwrite 하기만 하면 됩니다. 이 방법은 이미 다뤘었죠. 실제 gsub() 함수가 사용하는 같은 함수 파라미터들을 사용할 겁니다.

string.gsub = function( s, pattern, repl, n )
end


이 단 두 줄로 우리가 한 것은 gsub() 함수의 copy 를 가지게 된 것이구요 그리고 우리가 만든 함수로 이것을 replace 시킨 겁니다. 이제 여기에 마음대로 로직을 넣을 수 있습니다. 아래 로직으로 패턴 파라미터가 string 일 때와 table 일 때를 체크하게 됩니다.

if ( type(pattern) == "string" ) then
   --do something
else
   --do something else
end

string.gsub() documentation을 잠깐 보시면 이 패턴 파라미터가 항상 string 인 것만 보실 수 있을 겁니다.

패턴 파라미터가 string 이면 original 함수를 call 하면 됩니다.


if ( type( pattern ) == "string" ) then
   return gsub( s, pattern, repl, n )  --call the original function and return whatever it returns
else
   --do something else
end

패턴 파라미터가 string 이 아니면 즉 table 이라서 key/value 의 쌍을 이루는 값들이라면 아래와 같이 간단한 루프를 돌립니다. 이 루프는 else 구문 안에 만들어야 겠죠.

else
   --do something else (loop over the keys and replace them in the input string 's')
   for k,v in pairs( pattern ) do
      s = gsub( s, k, v )
   end
   return s
end

우리의 new parameter 이름과 패턴을 사용하기 위해 루프를 살짝 바꿔줬습니다.

 

 


Putting it Together

이제 이것들을 모두 다 합쳐 보죠. 우리가 override 한것과 new gsub() 함수는 아래와 같습니다.

local gsub = string.gsub
string.gsub = function( s, pattern, repl, n )

   if ( type(pattern) == "string" ) then
      return gsub( s, pattern, repl, n )
   else
      for k,v in pairs( pattern ) do
         s = string.gsub( s, k, v )
      end
      return s
   end
end

이 코드의 결과는 string.gsub() 함수가 우리가 만든 로직으로 replace 되게된 겁니다. 우리가 만든 로직은 파라미터가 일반적인 거면 original 함수를 call 하고 테이블이면 우리가 만든 로직을 사용하는 거죠. 짠! 이제 우리는 코로나에 우리만의 라이브러리를 추가했습니다.

print( string.gsub( "Hello banana", { Hello="Success", banana="Corona user" } )
--Outputs: Success Corona user

이렇게 하면 코로나에서 제공되는 어떤 API 라이브러리에도 여러분이 원하는 기능을 추가하실 수 있습니다.

 

Warning!

아마 이것 저것 하고 싶은 것들이 많이 떠오르시죠? 새로운 기능을 추가하실 때는 아래 내용들을 유념하세요.

 original 함수 변수에 저장하는 것을 잊지 마세요.
 함수 내에서 그 함수를 call 하지 마세요. 그러면 무한 루프에 빠지게 됩니다.
 여러분이 만든 함수 내에서 original 함수를 call 하는 조건을 반드시 넣어 주세요.

이건 약간 advanced topic 입니다. 그러니 여러번 직접 해 보시고 이 사용법이 익숙해 지도록 하세요. 직접 production-ready 코드에 넣어서 사용하는 것은 위험합니다. 충분히 테스트 하고 완전 숙지 한 다음에 사용하세요. 여기에는 많은 smoke 와 mirror들이 있습니다. 잘 못 하면 쉽게 좋은 기능을 잃어버릴 수 있습니다.

 


Examples

여기 여러분들이 흥미로워 하실 만한 유용한 내용들 몇개 소개해 드립니다.

1. “math” library — adding a function to calculate length:

--returns the distance between points a and b
math.lengthOf = function( a, b )
   local width, height = b.x-a.x, b.y-a.y
   return ( width*width + height*height ) ^ 0.5  --math.sqrt( width*width + height*height )
end

 

2. “math” library — adding a function to clamp values:

--returns a value clamped between a range
math.clamp = function( val, low, high )
   if ( val < low ) then return low end
   if ( val > high ) then return high end
   return val
end

 

3. print() function — overriding print() to not print when running on a device:

--override print() function to improve performance when running on device
if ( system.getInfo("environment") == "device" ) then
   print = function() end
end

 

4. “math” library — adding a function to calculate nearest multiples:

--rounds up to the nearest multiple
math.nearest = function( number, multiple )
   return math.round( (number / multiple) ) * multiple
end

 

References

    Variable number of arguments: http://www.lua.org/pil/5.2.html
    Lua closures: http://www.lua.org/pil/6.1.html
    First class values: http://www.lua.org/manual/5.2/manual.html
    Functions: http://www.lua.org/pil/6.html
    String trim() function: http://lua-users.org/wiki/StringTrim
    String recipes: http://lua-users.org/wiki/StringRecipes
    Author’s blog: http://springboardpillow.blogspot.co.uk/2012/04/sample-code.html 

반응형