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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
오늘은 외부 모듈을 불러와 클래스를 실행하는 기본 개념에 대해 알아보겠습니다.
얼마전 모듈에 대해 한번 다룬적이 있었는데요.
이 모듈과 클래스 개념은 아주 중요한 거라서 처음 프로그래밍을 접하시는 분들이나 아직 이 부분에 대해 개념이 모호한 분들은 보실만 할 겁니다.

모든일이 그렇듯 반복과 숙달이 필요한 부분인 것 같습니다.

What is a Class?
이 글을 마치면 클래스가 무엇인지 감이 잡히실 겁니다. 여기서 알아야 될 것은 그 클래스들을 이용하는데 어떤 잇점이 있으며 어떻게 이용하는가 입니다. 실제로 편리하게 이용하기 위해서 만들어 진 것이니 무엇이 클래스인가 아는것도 다 사용하려고 하는 것 아니겠습니까?

그러니 일단 시작해 보겠습니다.

객체지향 프로그래밍에서 객체(Object)는 그냥 우리가 일상생활에서 보는 사물이나 동물, 사람 등입니다. (때로는 개념이 될 수도 있겠죠)
그리고 그 객체들은 일정한 행동 양식이 있습니다.
만약에 개라는 객체를 여러분 앱에서 표현하고자 한다면...
개는 뛰고, 짖고, 부비고, 자고, 돌고 그러죠?
만약 고전 오락 갤러그에서 외계인이라는 객체를 보면
옆으로 움직이고, 아래로 내려오고, 미사일을 쏘고, 아군 미사일에 맞으면 폭발하고 그러죠?

이렇게 객체들의 행위를 구현하는 부분을 메소드 또는 함수 라고 합니다.
(자바에서는 메소드라고 하고 루아-코로나-에서는 함수라고 합니다.)

그리고 이 객체와 메소드가 있는 곳이 클래스 입니다.

직접 보시죠.

오늘은 우리랑 친근한 개로 클래스를 만들겠습니다. (개 클래스가 되겠네요.)

-------------------------------------------------
-- dog.lua
-- Example "dog" class for Corona SDK tutorial.
-------------------------------------------------
local dog = {}
local dog_mt = { __index = dog } -- metatable
-------------------------------------------------
-- PRIVATE FUNCTIONS
-------------------------------------------------
local function getDogYears( realYears ) -- local; only visible in this module
return realYears * 7
end
-------------------------------------------------
-- PUBLIC FUNCTIONS
-------------------------------------------------
function dog.new( name, ageInYears ) -- constructor

local newDog = {
name = name or "Unnamed",
age = ageInYears or 2
}

return setmetatable( newDog, dog_mt )
end
-------------------------------------------------
function dog:rollOver()
print( self.name .. " rolled over." )
end
-------------------------------------------------
function dog:sit()
print( self.name .. " sits down in place." )
end
-------------------------------------------------
function dog:bark()
print( self.name .. " says \"woof!\"" )
end
-------------------------------------------------
function dog:printAge()
print( self.name .. " is " .. getDogYears( self.age ) .. " in dog years." )
end
-------------------------------------------------

return dog

처음에 dog이라는 변수가 테이블로 만들어 졌습니다.
테이블로 만든 이유는 개는 한마리가 아니라 여러마리가 있을 수 있잖아요?
도꾸, 메리,  쫑 이렇게...
그렇게 여러마리를 표현하기 위해서 테이블로 만들었습니다.
그리고 메타테이블로 dog_mt 변수를 만들었습니다.

그 다음엔 getDogYears라는 로컬 함수(메소드) 가 있고 realYear 라는 인수를 받습니다.
아까 함수는 어떤 동작을 표현한다고 그랬죠?
이 함수는 인수로 받은 값에 7을 곱하는 동작을 하네요.
개가 직접 하는 동작이 아니라 어떤 로직과 관련된 동작이군요.
이렇게 개념이나 로직과 관련된 행위도 메소드(함수)로 표현됩니다.
로컬로 선언한것은 자바에서 private로 선언한 것과 비슷한데요.
의미는 이 dog.lua라는 클래스 안에서만 이 함수를 call할 수 있다는 겁니다.
외부파일에서는 이 함수를 콜할수 없습니다.

다음은 글로벌 함수인 dog.new 함수가 있습니다. 이 함수는 name과 ageInYears를 인수로 받습니다.
하는 일은 이름과 나이를 세팅하고 이를 메타테이블에 세팅한 값을 반환해 줍니다.
글로벌 함수는 자바에서의 public 과 같은데요. 이건 외부에서도 이 함수를 콜 할 수 있다는 의미입니다.
dog.new함수는 자바에서의 생성자 역할을 하네요. dog란 객체를 생성하는 겁니다.
외부에서 개를 만들 때 (그게 도꾸든 메리든 쫑이든....) 이 함수를 제일 먼저 불러서 객체를 만들어야 한다는 얘기입니다.

다음은 모두 글로벌 함수네요. dog:rollOver,dog:sit,dog:back, dog:printAge 이렇게 네개의 함수가 있습니다.
구르고 앉고 짖는 등 개가 하는 행위를 구현하는 3개의 메소드와 나이를 표시하는 함수 이렇게 4개의 함수(메소드)가 있습니다.

여기서는 터미널에 개가 구른다, 앉는다, 짖는다 같이 문자로 뿌려지는데요.
나중에 게임같은걸 개발 하게 되면 이 부분에 개 이미지를 넣고 애니메이션 기능을 이용해서 구르거나 앉거나 짖는 것을 구현하면 됩니다.

그럼 이 dog 클래스를 어떻게 사용해야 할까요?

main.lua를 보겠습니다.

local dog = require( "dog" )
local dog1 = dog.new( "Yai-Ya", 4 )
local dog2 = dog.new( "Toki", 1 )
    dog1:printAge()
    dog2:printAge()
   
    dog1:rollOver()
    dog2:sit()

보시면 처음에 dog.lua를 require합니다. 이때 .lua는 쓰지않고 파일 이름만 씁니다.

그리고나서 dog1,dog2 이렇게 두마리 강아지를 만듭니다. (두개의 객체를 만들었습니다.)
dog.new로 만들었는데요. 첫번째 개는 이름이 Yai-Ya 고 나이는 4살이네요.
두번째 개는 이름이 Toki이고 나이는 1살이구요.

다음으로 두 개의 나이를 표시해 줍니다.
그리고 첫번째 개 Yai-Ya에게는 구르라고 하고 두번째 개 Toki에게는 앉으라고 합니다.

이것을 실행하면 아래와 같이 됩니다.


보시면
Yai-Ya 28살이고 Toki는 7살이라고 처음에 나오네요.
4살, 1살이라 그랬는데 28살 7살이라고 나온 이유는 dog class에서 printAge()를 보면 나이를 받아서 곱하기 7을 하는 getDogYears( self.age ) 함수를 콜하고 있죠?
그래서 개 나이에 7을 곱해서 나온 겁니다.
아마 개 나이 곱하기 7하면 얼추 사람 나이가 되나 봅니다.

그리고 다음엔 Yai-Ya는 구르고 Toki는 그 자리에 앉는다고 돼 있죠?

모듈과 클래스는 이렇게 이용하시는 겁니다.

처음에 개를 만들고 (이름, 나이) 그리고 그 개에게 짖고,앉고, 구르고 하는 것을 시키는 겁니다.

처음에 메타 테이블을 만들고 생성자 dog.new()에서 이를 return(반환) 했죠? 이것은 새로운 인스턴스를 만드는데 아주 효과적이기 때문입니다. 새로운 인스턴스라 함은 도꾸,메리,쫑 이 각각의 개들의 존재를 구분할 수 있게 해 준다는 겁니다. 이 메타테이블을 이용하지 않으면 개를 한마리 밖에 만들지 못할겁니다. 그것이 도꾸든 메리든 쫑이든....

이제 어느정도 클래스에 대해 감이 잡히셨나요?
처음에 얘기 드렸지만 반복과 숙달이 필요한 부분입니다.

이 글 원본은 아래에 있습니다.
원본을 바탕으로 설명은 그냥 제 방식으로 했습니다.
http://blog.anscamobile.com/2011/09/tutorial-modular-classes-in-corona/

혹시 이 코드가 실행되지 않으시는 분은 댓글 달아 주세요.
정식 등록자가 받을 수 있는 최신 업데이트 된 버전에서만 될 수도 있거든요.
그러니 혹시 실행이 안 되시면 저한테 알려 주세요.



그럼...
반응형

HTML5 두번째 CSS 이해하기 (pseudo-class)

2011. 12. 7. 04:55 | Posted by 솔웅


반응형

오늘은 다시 빈 body 태그서부터 시작하겠습니다.
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title> Dougy's HTML5 </title>
    <link rel="stylesheet" href="main.css">
</head>
<body>
   
</body>
</html>
일단 body 태그 안에 아래 세줄을 채워 넣으세요.
    <p> 1st practice with css</p>
    <p> What is CSS?</p>
    <p> You don't know CSS?</p>

이 상태로 브라우저로 html파일을 불러오세요.

이렇게 나올 겁니다.
이런 연습때 사용했던 캡쳐 화면이네요. 이렇게 나오지는 않구요. 그냥 저 위에 있는 세 문장이 모두 검은 색으로 나올 겁니다.... 미쳐 캡쳐 받아 두질 못했습니다. ;;

이젠 main.css를  만들겁니다.
여러분이 사용하는 에디터로 main.css 파일을 만드세요.
그리고 아래 한줄을 넣어 보세요.
#tuna{color:red;}
이건 tuna라는 id를 가진 태그안의 내용 색을 붉은 색으로 하라는 내용입니다.
main.css를 저장하시고 아까 body안에 있던 내용을 아래와 같이 바꿔보세요.
    <p id="tuna"> 1st practice with css</p>
    <p> What is CSS?</p>
    <p> You don't know CSS?</p>

이렇게 하면 id가 tuna인 첫번째 줄이 빨간색으로 표시 됩니다.

#tuna{color:red;} -> .tuna{color:red'}
<p class="tuna">
이렇게 해도 똑같은 결과가 나옵니다.

첫번째는 id이고 두번째는 class 입니다.
main.css의 내용을 아래와 같이 바뀌면 어떻게 될까요?
p.tuna{color:red'}
이 경우 p 태그안의 클래스가 tuna인 경우만 적용 됩니다.
아래와 같이 해 보세요.
p[name]{color:blue}  -> main.css
    <p id="tuna"> 1st practice with css</p>
    <p name="larry"> What is CSS?</p>
    <p> You don't know CSS?</p>
이러면 두번째 라인만 파란색으로 표시 됩니다.
이 css코드 의미는 name이 있는 태그 내의 내용에 적용하라는 겁니다.

p[name="bucky"]{color:blue}  -> main.css
    <p name="sally"> 1st practice with css</p>
    <p name="larry"> What is CSS?</p>
    <p name="bucky"> You don't know CSS?</p>
이러면 세번째 줄만 이 css가 적용 됩니다. (attribute selector)

이렇게 css를 적용하는 여러 방법이 있습니다.
이 외에도 더 있습니다. 한번 볼까요?

p[name^="bacon"]{color:blue}  -> main.css
    <p name="baconsub"> 1st practice with css</p>
    <p name="mybacon"> What is CSS?</p>
    <p name="omgbacontuna"> You don't know CSS?</p>


p[name$="bacon"]{color:blue}  -> main.css

p[name*="bacon"]{color:blue}  -> main.css


첫번째 ^ 는 name이 bacon으로 시작되는 태그에만 적용합니다.
두번째 $는 name이 bacon으로 끝나는 태그에만 적용합니다.
세번째 * 는 name에 bacon이 들어가는 모든 태그에 적용합니다.

CSS를 제대로 활용하려면 1. 이런 기능이 있다는 것을 알아야 하고 2. 이런 기능을 많이 사용해서 숙달 돼 있어야 합니다. 3. 그래서 웹 화면을 디자인 할 때 CSS의 어떤 기능들을 적용할 지 설계할 수 있어야 합니다.
이 외에도 여러가지 기능들이 있는데요.. 나머지는 각자 Research 해 보세요.

이제 다시 body태그를 비워보겠습니다.

그 안에 아래 내용을 아래와 같이 넣어 보세요.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title> Dougy's HTML5 </title>
    <link rel="stylesheet" href="main.css">
</head>
<body>
<body>
    <div id="mommy">
        <p class="bucky"> tuna and bacon...</p>
        <p class="bucky"> tuna and bacon...</p>
        <p class="bucky"> tuna and bacon...</p>
        <p class="bucky"> tuna and bacon...</p>
        <p class="bucky"> tuna and bacon...</p>
        <p class="bucky"> tuna and bacon...</p>
    </div>
</body>
</html>

main.css를 아래와 같이 고쳐 보세요.
p:nth-child(3){color:green;}

이 css는 p 태그의 3번째 child에 내용을 적용하라는 의미입니다.
보시는 대로 세번째 줄만 녹색이 됐습니다.
p:nth-child(odd){color:green;} 이렇게 고치면 홀수 번째 줄만 녹색이 됩니다.
p:nth-child(even){color:red;} 이것까지 추가해 보세요.


이 기능은 아주 유용하겠죠?

다음 강좌에서도 계속 CSS에 대해 알아 보겠습니다. 6
반응형

HTML5 시작하기

2011. 12. 7. 03:32 | Posted by 솔웅


반응형
HTML5 공부 첫번째 시간입니다.

우선 HTML5를 하려면 기본적으로 가지고 있어야 할 지식이 있습니다.
우선 HTML 하고 CSS 그리고 JavaScript 에 대해서는 알고 있어야 합니다.

그리고 코딩을 하려면 에디터 프로그램을 사용해야 합니다.
윈도우에서는 NotePad++, Acroedit, UltraEdit, EditPlus 등등이 있고 그냥 윈도우에 기본적으로 깔려있는 메모장(NotePad)를 사용해도 됩니다.
맥에서는 Xcode도 되겠고 TextEdit도 되구요 그리고 NotePad++ 같이 맥용으로 따로 나왔으면 그걸 사용하셔도 됩니다.
그리고 HTML5를 지원하는 브라우저가 있어야 합니다. 크롬,화이어폭스,사파리,인터넷 익스플로러 등의 브라우저 최신버전이 있어야 합니다.

일단 이런 지식들과 도구들은 다 갖추고 있는 것으로 하고 HTML5를 공부해 보겠습니다.

이론적인 부분들은 많이 건드리지 않고 곧바로 코딩을 하고 눈으로 확인해보고 하는 식으로 할겁니다.

아주 기본적인 틀이 되는 코드는 아래와 같습니다.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title> Dougy's HTML5 </title>
    <link rel="stylesheet" href="main.css">
</head>

<body>

</body>
   
</html>

첫째줄은 아주 중요한 부분으로 HTML5를 사용하겠다는 표시 입니다.
두번째 html 시작하면서 언어를 영어로 했습니다. 한국에서 개발할 때는 한국어로 해 주셔야 겠죠?

그리고 title은 브라우저에 나타날 페이지 제목이구요. 그 아래에는 main.css라는 css파일을 스타일쉬트로 사용하겠다는 내용입니다.

body태그 안에는 아직 아무것도 없습니다.
이 코드를 실행하면 아래와 같이 나옵니다.

윗 부분 tab에 Dougy's HTML5 라고 title에 있는 내용이 있습니다.
그리고 나머지는 모두 빈 공간입니다.

아직까지 이 문서가 HTML5로서 다른 HTML(XHTML)과 다른 부분은 맨 첫줄 하나 입니다. 나머지는 전부 일반 HTML과 같습니다.

홈페이지를 보면 대개 윗쪽에 회사 로고 등이 있는 header가 있습니다
그리고 그 아래에 메뉴 버튼들이 있구요. (navigation)
왼쪽에는 그 메뉴의 서브 메뉴들이 있구.
가운데 넓은 공간에 주요 내용들이 들어갑니다.

그리고 맨 밑에는 footer가 있어서 copyright 부분이 들어가구요.

우선 이 일반적인 패턴을 따라서 HTML5로 화면을 하나 만들어 보겠습니다.

body 태그 안에 아래 내용을 넣어 보세요.

    <header>
        <h1> Welcome to Dougy's HTML5. </h1>
    </header>
   
    <nav>
        <li> Home </li>
        <li> Tutorials </li>
        <li> Podcast</li>
    </nav>
   
    <section>
       
    </section>
   
    <aside>
        <h4> News </h4>
        DDanzi guys have visited Zuccotti Park Yesterday.
    </aside>
   
    <footer>
        Copyright Bucky thenewboston.
    </footer>
   
자 이 코드를 넣고 저장한 다음 브라우저로 불러오면 아래와 같이 나옵니다.


 <section> 태그 안에 아무런 내용을 넣지 않았을 겁니다.
이 부분을 채우겠습니다.

<body> 태그 안에 header,nav,section,aside,footer 레이아웃을 넣었듯이 각 레이아웃 안에 또 레이아웃을 넣을 수 있습니다.

이 섹션 안에는 여러 기사를 표한할 수 있도록 큰제목, 작은 제목, 내용, footer 형식의 레이아웃들로 채워 넣겠습니다.

        <article>
            <header>
                <hgroup>
                    <h1> DDanzi in NY</h1>
                    <h2> come to Zuccotti Park with Pizza</h2>
                </hgroup>
            </header>
            <p> DDanzi guys have visited in Zuccotti park yesterday to encourage the occupier of Occupy Wall St. Protesters.</p>
            <footer>
                <p> -- written by Dougy </p>
            </footer>
        </article>

첫번째 기사는 이렇게 채워 넣겠습니다.
header가 있고 이 header는 큰 제목과 작은 제목 두개가 있습니다.
이 두 제목들은 hgroup 태그로 묶겠습니다.
그리고 기사 내용이 들어가구요.
누가 기사를 썼는지 가 들어갈 footer가 있습니다.
이게 section태그에 들어갈 레이아웃입니다.

기사를 하나 더 넣겠습니다. 위 코드를 그대로 복사해서 그 아래에 붙여 넣으세요.

        <article>
            <header>
                <hgroup>
                    <h1> Title of Article 2</h1>
                    <h2> Subtitle for Article!</h2>
                </hgroup>
            </header>
            <p> This is the 2nd article. </p>
            <footer>
                <p> -- written by Dougy </p>
            </footer>
        </article>

똑 같은 형식에 그 내용들만 바뀌었습니다.

이것을 화면으로 보면 아래와 같습니다.


자 여기까지 간단하게 HTML5 구조 맛보기를 했습니다.


다음시간에는 CSS로 제대로 생각했던 Layout 을 브라우저에 표현하는 방법을 배울겁니다.


반응형


반응형
모바일 애플리케이션으로 E-Book을 구현하거나 하다 보면 책장 넘기는 효과를 주면 훨씬 더 실감나는 E-Book 앱을 만들 수 있습니다.

오늘은 이 책장 넘기는 효과 주는 방법에 대해 공부하겠습니다.
오늘 소개하는 코드는 아주 기본적인 기능만 있습니다.

이 코드에다 여러분이 여러 효과를 주시면 더욱 더 그럴싸한 e-Book을 만들 수 있을 겁니다.

페이지 넘김 효과를 주기 위해서는 두가지 방법으로 이 효과를 구현할 수 있습니다.
첫번째는 frame-based animation을 구현하는 겁니다.. 그러기 위해서 스크린 만한 이미지들이 필요합니다.  즉 아이폰, 아이패드에 맞는 이미지들이 따로따로 있어야 합니다. 그것도 폰을 세웠을 때와 눕혔을 때 모두 다 따로따로 있어야 합니다.

두번째는 optical illusion을 통해 하나의 이미지, bitmap mask 그리고 transitions를 통해 구현하는 방법입니다.

두번째 방법이 훨씬 좋겠죠? 오늘 제공될 소스코드에는 이 두번째 방법을 소개해 드릴겁니다.



Step 1. Preliminary Work

페이지 넘김 효과를 사용하기 위해서는 몇개의 이미지들이 필요합니다.

이 두 이미지는 각각 page1.jpg,page2.jpa입니다.
이것 말고 책장 넘기는 효과를 줄 이미지들도 필요합니다.


이제 이미지가 마련 됐으면 코딩을 해 보겠습니다.

-- hide the status bar
display.setStatusBar( display.HiddenStatusBar )

local page1 = display.newImageRect( "page1.jpg", display.contentWidth, display.contentHeight )
page1:setReferencePoint( display.TopleftReferencePoint )
page1.x, page1.y = display.contentWidth*0.5, display.contentHeight*0.5

local page2 = display.newImageRect( "page2.jpg", display.contentWidth, display.contentHeight )
page2.x, page2.y = display.contentWidth*0.5, display.contentHeight*0.5
page2:toBack() -- make sure 2nd page is underneath the first one

local curlPage = display.newImageRect( "curlPage.png", display.contentWidth, display.contentHeight )
curlPage.x, curlPage.y = display.contentWidth*0.5, display.contentHeight*0.5
curlPage.isVisible = false

-- group to hold the page that will be turned (as well as the "curl" page)
local turnGroup = display.newGroup()

이 4개의 이미지를 불러오는 코드 입니다.
두번째 페이지는 첫번째 페이지 밑으로 가게 했습니다. 그리고 curlPage는 inVisible을 false로 했구요.
이 코드만 실행하면 책 겉장만 보일겁니다.

Step 2. Page Curl Functions

다음은 페이지 넘김 효과를 줄 함수들입니다.

-- The following function will turn the page "back"
local function gotoPrevious( curlPage, time )
local time = time or 500

curlPage.isVisible = true
local hideCurl = function()
curlPage.isVisible = false
turnGroup:setMask( nil )
end
transition.to( turnGroup, {maskX=display.contentWidth*0.5+100, time=time } )
transition.to( curlPage, { rotation=45, x=display.contentWidth+(display.contentWidth*0.10), y=display.contentHeight + (display.contentHeight*0.25), time=time, onComplete=hideCurl })
end

-- The following function will turn the page "forward"
local function gotoNext( currentPage, curlPage, time )
-- add "pages" to page turning group
turnGroup:insert( currentPage )
turnGroup:insert( curlPage )

-- mask should match dimensions of content (e.g. content width/height)
local curlMask = graphics.newMask( "mask_320x480.png" )
turnGroup:setMask( curlMask )

-- set initial mask position
turnGroup.maskX = display.contentWidth * 0.5+100
turnGroup.maskY = display.contentHeight * 0.5

-- prepare the page-to-be-turned and the curl image
currentPage:setReferencePoint( display.BottomLeftReferencePoint )
curlPage:setReferencePoint( display.BottomRightReferencePoint )
curlPage.rotation = 45
curlPage.x = display.contentWidth+(display.contentWidth*0.10)
curlPage.y = display.contentHeight + (display.contentHeight*0.25)
curlPage.isVisible = true

-- show pagecurl animation and transition away (next page should already be in position)
local time = time or 500
transition.to( turnGroup, { maskX=-display.contentWidth*0.75, time=time } )
transition.to( curlPage, { rotation=0, x=0, y=display.contentHeight+20, time=time} )
curlPage.yScale = curlPage.y * 0.2
end

소스코드를 좀 살펴 볼까요?

처음에 나오는 함수는 gotoPrevious 함수 입니다.
인수로 curlPage와 time을 받습니다.
그리고 로컬 변수 time에 값을 넣고 curlPage를 보이도록 바꿉니다.
이 함수의 로컬 함수 hideCurl에서 curlPage를 안 보이도록 하고 setMask를 해제하는 로직을 넣어 둡니다.
transition.to로 turnGroup에 움직이는 효과를 주고 또 curlPage도 움직이는 효과를 주고 이 효과가 끝나면 로컬 함수인 hideCurl을 불러와 curlPage를 안 보이도록 하고 setMask를 해제 하도록 합니다.

그 다음은 gotoNext 함수인데요 currentPage,curlPage,time을 인수로 받습니다.
이 함수 내용은 좀 기네요.
turnGroup에 인수로 받은 currentPage와 curlPage를 insert 합니다.

그리고 curlMask 로컬 변수에 graphcs.newMask로 mask_320X480.png를 세팅해 넣습니다.
graphics.newMask 는 http://developer.anscamobile.com/node/5248 API를 참조하세요.
그리고 이 curlMask를 turnGrooup에 insert 합니다.
maskX와 maskY 값을 할당해 주고요 이미지들의 레퍼런스 포인트를 bottomLeft BottomRight 로 주고 curlPage를 45도 회전시키고 이 curlPage의 위치를 설정해 줍니다.
그리고 이 curlPage.isVisible을 true로 세팅해 줍니다.
그 다음 time값을 세팅하고 transition.to로 움직임 효과들을 줍니다.

이렇게 하면 앞장으로 넘기고 뒷장으로 넘기는 효과를 주는 함수까지 완료 했습니다.

다시 간단히 정리하자면요.
gotoNext()
1. page-to-turn으로 insert하고 curl 이미지를 turnGroup에 넣는다.
2. 비트맵 마스크를 turnGroup에 적용한다.
3. 페이지와 curl  이미지의 레퍼런스 포인트를 bottom right으로 한다.
4. curl 이미지를 회전시키고 시작 위치를 잡아준다.
5. transition을 시작한다.

gotoPrevious()
1. curl 이미지를 visible하게 한다.
2. onComplete 리스너를 달아서 transotion이 끝나면 hiding 페이지를 하도록 하고 turnGroup에서 비트맵 마스크를 없앤다.
3. transition 애니메이션을 시작한다.

Step3. Initiate the Page Curl

timer.performWithDelay( 2000, function() gotoNext( page1, curlPage, 500 ); end )
timer.performWithDelay( 5000, function() gotoPrevious( curlPage, 500 ); end )

이 함수들을 실행하기 위해 2초후에 gotoNext함수를 부르고 5초후에 gotoPrevious 함수를 부릅니다.

그러니까 이 소스코드로는 손가락으로 책장을 넘기는 효과가 아니라 2초후에 책장이 넘어가고 5초후에 책장이 다시 넘어오게 될 겁니다.

제대로 구현하려면 여러분들이 touch나 tap 리스너를 달아서 이 책장 넘김 효과를 컨트롤 하셔야 합니다.

이 소스코드에 대한 원문 강좌는 아래 페이지에 있습니다.
http://blog.anscamobile.com/2011/12/how-to-create-a-page-curl-in-corona/

그리고 소스파일은 아래에 있습니다.

그럼 오늘도 즐코딩.....


반응형

WEB APP 시작하기...

2011. 12. 5. 06:24 | Posted by 솔웅


반응형
Corona SDK로 안드로이드,iPhone 용으로 동시에 빌드되는 앱을 만들다 보니까 새로운 기술이 뭐 또 없나 살펴보게 되더라구요.

그래서 찾다가 보니까 HTML 5 로 게임을 만들면 어떤 모바일 OS 던 상관없이 게임만 만들면 모든 스마트폰에서 사용할 수 있을 것 같애요.

그래서 1주일 동안 관련 기술들을 Research 해 봤습니다.

아직 잘은 모르지만 이런 웹 앱을 만들려면 기본적으로 HTML5 에 대한 것은 알아둬야 겠더라구요.

그래서 따로 WEB_APP 카테고리를 만들었습니다.

기본적으로 HTML 5를 다룰거구요. 모바일 앱 기술 중 하나인 Sencha Touch 도 공부할 생각입니다.

또 다시 새로운 기술을 배울 생각을 하니까 흥분되는데요... ^^

그럼 앞으로는 Corona SDK, HTML 5, Sencha Touch 로 이 블로그를 채워 갈께요...


반응형


반응형
1. 아마존 (amazon.com)의 Kindle fire 시뮬레이터 추가 - http://yfrog.com/h4yz7gp

2. 올해의 Best Mobile Application 후보에 Nominate - http://crunchies2011.techcrunch.com/nominate/?NDpDb3JvbmEgU0RL

Nominate your favorite companies, products and people for one of our Crunchie award categories below.  Everyone is invited to submit one nomination per category per day through Tuesday night, December 13th, 2011 at 11:59PM PST. Once you nominate a company in a category, you are able to share your nominations through Twitter and Facebook, or you can embed a badge or link to the nomination.  Top nominees in each category will be notified and become 2011 Crunchies Finalists.

Finalist voting will begin in early January 2012.

For past winners, see the page for 2007, 2008, 2009 and for 2010.

좋아하는 회사, 상품 사람들을 Crunchie award category에서 nominate 해 주세요. 누구나 2011년 12월 13일 목요일 밤까지 하루에 한개 카테고리당 1개씩 submit 할 수 있습니다. 카테고리 안에 한 회사를 nominate했으면 당신의 nomination을 트위터나 페이스북을 통해 당신의 친구들과 share할 수 있습니다. 또는 노미네이션 뱃지나 링크를 embed할 수 있습니다. 각 카테고리의 top nominees들은 2011 Crunchies finalists가 되어 발표 됩니다. 최종 결선은 2012년 1월 초에 있을 겁니다.

지난 우승자들을 보려면 링크를 클릭하세요 .2007, 2008, 2009 and for 2010.

3. HP 가 2주 이내에 새로운 Web OS를 내 놓는 답니다.
http://moconews.net/article/419-yes-hp-may-finally-have-some-news-on-webos-in-the-next-two-weeks/

오늘 제가 접한 새로운 소식들은 이렇습니다.

코로나가 아마존 앱마켓에 특별히 자체 개발한 게임 앱을 올려 놓고 홍보하고 그러더니...
시뮬레이터에 아마존의 Kindle Fire 까지 추가했군요.
코로나와 아마존이 계속 긴밀한 관계를 맺고 있는 것 같습니다.

그리고 Corona SDK 가 올해의 베스트 모바일 앱에 추천해 달라고 홍보 하고 있네요.

작년의 베스트 모바일 앱은 구글 맵이 차지 했었네요.

Best Mobile App 2010
Bump
Chomp
Google Mobile Maps for Android (winner)
Hashable
Instagram (runnerup)


저는 Corona SDK를 베스트 모바일 애플리케이션 후보로 추천하고 트위터와 페이스북에도 쉐어 했습니다. ^^




반응형


반응형
자주 사용하는 기능을 모듈화 하면 나중에 재사용할 때 아주 편하고 개발 기간도 많이 save해 줍니다.
예를 들어 스크린 사방 벽에 wall을 만들고 객체들이 이 벽에 맞고 튀어야 할 때 사방 벽 만드는 부분을 모듈화 한다던지.
아니면 레벨별로 배경화면을 다르게 해야 되는 게임을 개발 할 때 배경화면 설정 부분을 모듈화 한다던지.
그 외 여러가지 자기만의 로직을 모듈화 해 두면 그게 자산이 되고 나중에 개발할 때도 많은 도움이 됩니다.

오늘은 이렇게 자기만의 코드를 모듈화 하는 방법에 대해 알아보겠습니다.


낯익은 사진이죠?
자기가 힘들여서 터득한 know how를 열심히 다른 개발자들고 Share하고 있는 peach입니다.
홈페이지는 http://peachpellen.com/ 입니다. 가셔서 고맙다고 코멘트 남기는 것도 좋을 것 같습니다.

이 앱에는 두가지가 모둘화 돼 있습니다.

첫번째는 background image 를 표시하고 이 배경이미지를 클릭하면 없어지는 함수입니다.
그리고 두번째는 x,y좌표 파라미터를 받아서 peach.png 이미지 파일을 해당 x,y좌표에 display 하는 겁니다.

이 모듈화 된 소스를 보겠습니다. ----- setup.lua -----
-- Makes sure the file can be "seen"
module(..., package.seeall)

-- Set up the background
function background (event)
    -- Display the background
    local background = display.newImage ("bg.png")
        -- The function to remove the background
        function killbackground (event)
            background:removeSelf()
        end
    -- Add the event listener to the background
    background:addEventListener("tap", killbackground)
end

-- Insert the traditional Peach pic, this time using params
function peach (params)
    -- My picture
    local peach = display.newImage ("peach.png")
    -- The X and Y of my pic, defined when the function is called
    peach.x = params.x
    peach.y = params.y  
end

첫번째 부분은 모듈화 하기 위해 지정해 줘야 하는 코로나 SDK의 규칙입니다.
두번째 event를 인수로 받는 background라는 함수입니다.
bg.png를 display하고 여기에 tap 이벤트 리스너를 달아서 tab하면 배경이미지를 없애는 함수 입니다.
세번째 함수는 peach라는 함수로 peach.png를 display하고 x,y좌표를 전달받은 x,y좌표로 설정해 이미지를 그 위치에 그려줍니다.

그러면 이 모듈화된 부분을 어떻게 사용하는지 알아보겠습니다.

-- Hides the status bar
display.setStatusBar (display.HiddenStatusBar)

-- Requires setup.lua
require "setup"

-- Performs our "background" event from setup.lua (Create background, create remove function, add listener)
setup.background()

-- Performs our "peach" event; note the x and y - these are our "params"
setup.peach ({ x = 160, y = 240 })

-- Uncomment the block below to see how useful this type of code is when spawning lots of the same image/object
--[[
setup.peach ({ x = 60, y = 100 })
setup.peach ({ x = 60, y = 400 })
setup.peach ({ x = 260, y = 100 })
setup.peach ({ x = 260, y = 400 })
--]]

--[[
*NOTES*
Like many of my tutorials this is as simple as it gets; it shows how to add an image, add a function to that image and
remove that image all in one function from a seperate Lua file.

There is near limitless potential for using multiple files to keep your code clean and organised however this mini
tutorial is only intented to highlight the basics.

By learning how to use the simple examples shown here you are well on your way to much tidier code; something that
will really come in handy as your projects grow larger and more ambitious.
--]]

실제 코드는 단 세 줄 입니다.
우리의 친구 peach가 아주 자세하게 주석을 달아 줬네요.

우선 setup.lua를 require하구요.
background()함수를 불러옵니다.
그리고 peach함수도 해당 파라미터를 넣어서 불러오구요.

그러면 끝입니다.

이렇게 되면 setup.lua에 있는 함수는 다른 앱을 개발 할 때도 그대로 모듈로 사용할 수 있습니다.

원본 소스코드는 아래 압축파일에 있습니다.


그럼 다음 시간에 뵐께요.
반응형


반응형
오늘은 벽돌 깨기 게임 만들기 마지막회가 될것 같은데요.
어제까지 일단 화면에 표시할 모든 객체들은 다 표시했습니다.
그리고 화면에서는 공만 여기저기 튀면서 움직이고 있습니다.

이제 남은 일은 밑에 있는 paddle을 유저가 좌우로 움직일 수 있도록 해야 하고,
공이 벽돌에 맞으면 벽돌이 없어지게 해야 하고,
공이 bottom Wall에 맞으면 공이 없어지고 새로 시작하도록 해야 합니다.

그럼 우선 첫번째 paddle을 움직이는 것 부터 해 볼까요?

지난 시간 까지 했던 paddle 생성 함수는 아래와 같습니다.
function createPaddle()
    local paddleWidth = 100
    local paddleHeight = 10
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
    physics.addBody(paddle, "static", {friction=0, bounce=1})
end

자 touch 이벤트 리스너를 달겠습니다.
Runtime:addEventListener("touch", movePaddle)

paddle에 달지 않고 Runtime에 달았습니다. 유저가 paddle에 닿았을 때만 움직일 수 있도록 하려면 Runtime을 paddle로 바꾸면 됩니다.
하지만 여기선 유저가 움직일 수 있는 객체가 paddle밖에 없고 화면 전체에서 이 이벤트 리스너를 받는게 더 효과적이기 때문에 Runtime에 이벤트 리스너를 달았습니다.

이 이벤트 리스너는 화면 아무곳이나 touch하면 movePaddle 함수가 실행 되도록 하라는 의미 입니다.
이 이벤트 리스너 앞에 movePaddle 함수를 만듭니다.
그리고 event.x를 paddle.x에 대입하면 이 paddle의 위치가 좌우로 움직입니다.

local movePaddle = function(event)
    paddle.x = event.x
end


자 이제 유저가 paddle을 움직일 수 있습니다.

그 다음은 공이 벽돌에 맞으면 그 벽돌이 없어지도록 할께요.
addBody를 할 때 공은 dynamic으로 설정하고 나머지 객체들은 모두 static으로 설정했습니다.
 이 dynamic으로 설정한 공에 충돌(collision)을 체크하는 로직을 적용하도록 하겠습니다.
function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

지난 시간까지 한 소스코드 입니다.
이제 ball에 collision 이벤트 리스너를 답니다.
ball:addEventListener("collision", ball)

공이 어딘가에 충돌했을 때 ball.collision 함수가 실행 됩니다.
여기서 어딘가는 physics.addBody 가 적용된 객체들을 말합니다.

그럼 ball.collision함수를 만들어 보겠습니다.
    ball.collision = function(self, event)
        if(event.phase == "ended") then
            if(event.other.type == "destructible") then
                event.other:removeSelf()
            end
        end
    end

벽돌을 만들 때 각각의 벽돌에 type을 destructible 이라고 주었었습니다.
여기서 event.other는 충돌의 상대편을 말합니다. event.target은 충돌 당사자를 말합니다. 그러므로 event.other는 벽돌이고 event.target은 ball 이겠죠.
event.other.type이 destructible이면 즉 벽돌이면 event.other:removeSelf() 합니다. 즉 그 벽돌을 없앱니다.
아주 간단하죠?

이제 벽돌 깨기의 주요 기능이 다 구현 됐습니다.

여기서 보너스로 한가지만 더 한다면 공이 bottom wall에 부딪혔을 때 공이 없어지고 새로 시작하도록 하겠습니다.

이것도 공이 collision 이벤트를 일으켰을 때 일어나는 현상이기 때문에 아까 만들었던 ball.collision 함수 안에 아래 코드를 넣습니다.
        if(event.other.type == "bottomWall") then
            self:removeSelf()
            local onTimerComplete = function(event)
                createBall()
            end
            timer.performWithDelay(500, onTimerComplete , 1)
        end

이걸 넣고 실행해 보시면 공이 바닥에 닿으면 없어지고 가운데에서 다시 생성 되는 것을 보실 수 있을 겁니다.

이 경우 collision 이벤트가 발생했을 때 event.other.type이 bottomWall 이면 self:removeSelf()를 해 줍니다. other가 아니라 자신이 없어지는 겁니다.
그리고 timer로 0.5초의 시간을 두고 onTimerComplete 함수를 한번 호출하도록 만듭니다.
이 함수에서는 createBall()을 호출합니다.
그러면 공이 바닥에 부딪혀서 없어지고 0.5초 후에 새 공이 가운데에서 만들어져서 움직이기 시작할 겁니다.

전체 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createWalls()
    createBall()
    createPaddle()
    createBricks()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
   
    ball.collision = function(self, event)
        if(event.phase == "ended") then
            if(event.other.type == "destructible") then
                event.other:removeSelf()
            end
        end
       
        if(event.other.type == "bottomWall") then
            self:removeSelf()
            local onTimerComplete = function(event)
                createBall()
            end
            timer.performWithDelay(500, onTimerComplete , 1)
        end
    end

    ball:addEventListener("collision", ball)
end

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    wall.type = "bottomWall"
end

function createPaddle()
   
    local paddleWidth = 100
    local paddleHeight = 10
   
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
    physics.addBody(paddle, "static", {friction=0, bounce=1})

    local  movePaddle = function(event)
            paddle.x = event.x
    end

    Runtime:addEventListener("touch", movePaddle)
   
end
function createBricks()
    local brickWidth = 40
    local brickHeight = 20
    local numOfRows = 4
    local numOfCols = 6
    local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}
    local row
    local col
    for row = 0, numOfRows - 1 do
        for col = 0, numOfCols - 1 do
            -- Create a brick
            local brick = display.newRect( topLeft.x + (col * brickWidth), topLeft.y + (row * brickHeight), brickWidth, brickHeight )
            brick:setFillColor(math.random(50, 255), math.random(50, 255), math.random(50, 255), 255)
            brick.type = "destructible"
            physics.addBody(brick, "static", {friction=0, bounce = 1})
        end
    end
end

main()

원본 소스는 ball:setLinearVelocity(75, 150) 를 startGame()에 넣고 사용했는데 저는 하다 보니까 그냥 createBall에 넣었네요. 두개 다 똑 같습니다.
다만 나중에 게임에 여러 기능을 추가하다 보면 startGame()을 따로 Call할 일이 많이 생길 수 있는데 그 때는 원본 소스 같이 따로 함수로 관리하는게 더 낫겠죠.

이 소스는 Corona SDK를 만든 회사인 Ansca Mobile에서 제공한 샘플 소스입니다.
아래 유튜브로 가시면 이 샘플 코드에 대한 강좌를 들으실 수 있습니다.

제가 설명했던 것과는 조금 다르게 설명하겠죠?

이것도 들어보시면 도움이 될 거예요.

그럼 다음시간에 뵐께요.
반응형


반응형
어제 했던 소스는 아래와 같습니다.

require ("physics")

function main()
    setUpPhysics()
    createBall()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

main()


정리하자면 공을 만들고 그 공에 physics 엔진을 적용하고 움직이는 것 까지 했습니다.

오늘은 벽을 만들어서 그 벽에 공이 튀게 만들겠습니다.

일단 함수 이름은 createWalls()로 하고 사각형으로 그려보겠습니다.

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
end

벽 두께는 10픽셀로 합니다.

그리고 main()함수에서 이 createWall() 함수를 Call 하세요.


이제 사방에 벽이 생겼습니다.
실행하면 공이 벽을 지나쳐서 갑니다.
저 벽에 공이 튀게 만드려면 이 wall들에 addBody를 해 주면 됩니다.

지금까지의 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createWalls()
    createBall()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    wall.type = "bottomWall"
end

main()

이제 실행하면 공이 계속 벽면에 튀게 됩니다.

여기서 유심히 볼 점은 벽면 모두 변수 이름이 wall입니다. 이 변수를 한번 만들어서 계속 재활용 한 겁니다.
그리고 맨 마지막에 bottom Wall을 만들었고 type을 bottomWall이라고 명명했습니다.
이는 다른 세 벽은 공이 맞고 튀기만 하면 되고 아래 벽엔 맞으면 다른 핸들링을 하기 위해서 이렇게 한 겁니다.

이 부분은 나중에 구현 해 보겠습니다.

이제 아래에 paddle을 한번 만들어 볼까요?
밑에 적당한 위치에 적당한 길이의 사각형을 만들겠습니다.

function createPaddle()
    local paddleWidth = 100
    local paddleHeight = 10
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
end

보시는 대로 왼쪽 오른쪽 길이(Width)는 100픽셀이고 높이는 10픽셀인 사각형을 그리고 이것을 가운데에 위치시킵니다.
실행 시키면 아직까지 paddle에 physics를 적용하지 않았기 때문에 공은 그냥 통과합니다.
여기에 physics를 아래와 같이 적용하세요.
physics.addBody(paddle, "static", {friction=0, bounce=1})

이러면 공이 지나가다가 이 paddle에 맞으면 튀게 됩니다.

여기에 유저가 paddle을 움직일 수 있도록 하는 기능을 다뤄야 하는데요.
이 기능은 다음 강좌에서 하게 될 겁니다.

이번엔 벽돌들을 만들어 볼까요?
createBricks() 함수를 만드세요.

그리고 사각형을 만들께요. Width는 40 Height는 20으로 하겠습니다.
    local brickWidth = 40
    local brickHeight = 20
local brick = display.newRect( 50, 50, brickWidth, brickHeight )
brick:setFillColor(50, 250, 100, 255)

전체 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createWalls()
    createBall()
    createPaddle()
    createBricks()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    wall.type = "bottomWall"
end

function createPaddle()
    local paddleWidth = 100
    local paddleHeight = 10
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
    physics.addBody(paddle, "static", {friction=0, bounce=1})
end

function createBricks()
    local brickWidth = 40
    local brickHeight = 20
    local brick = display.newRect( 50, 50, brickWidth, brickHeight )
    brick:setFillColor(50, 250, 100, 255)
end

main()

이제 벽돌이 하나 생겼습니다.
저 벽돌에 공이 맞았을 때 튀게하려면 지금까지 다른 객체에 했던 식으로 addBody를 하면 됩니다.

그런데 여기서 생각해야 할 점은 벽돌은 1개가 아니라 수십개가 만들어 져야 합니다.
저런식으로 하나하나 각각 위치와 색을 지정해서 벽돌을 만들어도 됩니다.
그런데 그러면 프로그램 답지가 않습니다.

for문을 사용해서 간단하게 벽돌들을 만들겠습니다.

저런 벽돌을 좌우로 6개씩 4줄 총 24개를 만드는 로직을 구현하겠습니다.
아까 벽돌의 두께와 높이는 40,20으로 정했구요.
numOfRows=4, numOfCols = 6 을 추가하겠습니다.

그리고 첫 시작점은 아래와 같이 잡습니다.
local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}

이 벽돌은 처음 1줄 6개를 그리고 그 다음 줄 6개 그리는 식으로 4번 작업을 할 겁니다.
그 로직은 아래와 같습니다.
    local row
    local col
    for row = 0, numOfRows - 1 do
        for col = 0, numOfCols - 1 do
            -- Create a brick
            local brick = display.newRect( topLeft.x + (col * brickWidth), topLeft.y + (row * brickHeight), brickWidth, brickHeight )
            brick:setFillColor(math.random(50, 255), math.random(50, 255), math.random(50, 255), 255)
        end
    end


벽돌색은 Random하게 지정했습니다.
여러분 취향대로 라인별로 색을 지정해도 되고 열 별로 지정해도 되고 마음대로 바꾸셔도 됩니다.

여기에 이 벽돌을 맞고도 공이 튀어나오게 하려면 각 벽돌에 addBody를 하면 됩니다.
그리고 type은 destructible로 명명합니다.
나중에 무딪히면 없애야 되거든요.

벽돌에 addBody를 한 오늘의 최종 소스코드는 아래와 같습니다.

require ("physics")

function main()
    setUpPhysics()
    createWalls()
    createBall()
    createPaddle()
    createBricks()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    wall.type = "bottomWall"
end

function createPaddle()
    local paddleWidth = 100
    local paddleHeight = 10
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
    physics.addBody(paddle, "static", {friction=0, bounce=1})
end

function createBricks()
    local brickWidth = 40
    local brickHeight = 20
    local numOfRows = 4
    local numOfCols = 6
    local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}
    local row
    local col
    for row = 0, numOfRows - 1 do
        for col = 0, numOfCols - 1 do
            -- Create a brick
            local brick = display.newRect( topLeft.x + (col * brickWidth), topLeft.y + (row * brickHeight), brickWidth, brickHeight )
            brick:setFillColor(math.random(50, 255), math.random(50, 255), math.random(50, 255), 255)
            brick.type = "destructible"
            physics.addBody(brick, "static", {friction=0, bounce = 1})
        end
    end
end

main()

이제 공이 벽돌에 부딪히면 벽돌이 없어지고 아래 벽에 부딪히면 게임이 새로 시작하고 paddle을 유저가 좌우로 움직이도록 하는 작업이 남았습니다.

내일은 이 작업에 대해 알아보겠습니다.

반응형


반응형

오늘서 부터 코로나 SDK로 간단한 벽돌깨기 게임을 만들어 보도록 하겠습니다.
몇회 정도 할지는 잘 모르겠습니다. 처음 코로나를 접하시는 분들도 만드실 수 있도록 그리고 프로그래밍 경력이 거의 없으신 분들도 따라올 수 있도록 하나하나 순서대로 코딩하고 화면으로 확인하고 하면서 진행하려고 합니다.
이 강좌는 소스분석 카테고리에 넣을 강좌로 준비했습니다.
벽돌깨기 게임 공개 소스를 분석 하는데, 그냥 공개된 소스만 갖고 분석하는 것 보다 실제 게임을 만드는 순서로 코드를 하나하나 완성해 가면서 해 보려구요.

게임을 완료하게 되면 아래와 같은 화면이 실행 됩니다.


모두 알고 있듯이 저 공은 계속 움직이면서 물체에 부딪히면 튕기게 됩니다.
그리고 공이 벽돌에 맞으면 벽돌은 없어지게 되구요.
바닥에 맞으면 공은 없어지게 됩니다. 다만 아래에 있는 스틱에 맞으면 없어지지 않고 튕겨서 다시 위로 올라가구요.

이 강좌에서는 여기까지만 구현 해 보겠습니다.
이외에 점수 올라가고 공 갯수 제한하고 하는 것은 각자 쉽게 하실 수 있을 겁니다. 이번에 진행되는 강좌를 잘 숙지하시면요...

일단 공이 움직이고 튕기는 것은 코로나 SDK의 physics 엔진을 사용하겠습니다.
그리고 각 객체와 움직임 그리고 이벤트에 대한 핸들링은 함수를 사용해서 구현할 거구요.

일단 여기서 객체들을 그 그룹별로 한번 나눠보죠..
벽, 벽돌들, 공, 공을 튀어내는 stick(paddle)
이렇게 4가지 정도 눈에 보이는 객체 그룹이 있습니다.
그리고 physics엔진을 이용한다고 했구요.
그러면 대충 함수들을 나눠보면
setUpPhysics(),createWalls(),crateBricks(),creatBall(),createPaddle() 이렇게 나눌 수 있습니다.
이 함수들을 만들거구요. 이 함수들은 main()함수에 넣어서 한꺼번에 Call을 할 겁니다. 앱을 많이 만들다 보면 아시겠지만 각 객체별로 함수를 만들고 필요에 따라 이 함수들을 Call하는 함수를 만들어서 구현하도록 디자인 하면 나중에 각 객체들을 콘트롤 하는데 좋습니다.

자 그럼 이렇게 대충 디자인을 하고 개발에 들어갈까요?
제일 먼저 각자 적당한 폴더를 만들고 그 폴더 안에 main.lua파일을 만드세요.
그리고 그 파일 안에 코딩을 시작하겠습니다.

각자 스타일에 따라 다르겠지만 저는 우선 뭔가 눈에 보이는 것 부터 하고 싶네요.
제일 중요한 공부터 만들어 보죠.

일단 createBall() 함수를 만듭니다.
function createBall()

end
이렇게 함수 선언을 하고 닫기 까지 합니다.
그리고 공을 그립니다.
function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

이렇게 하고 실행을 하면 화면에 아무것도 안 나옵니다. 저 함수를 call한 곳이 없기 때문이죠.

앞으로 만드는 함수들은 main()함수에 넣어서 관리를 할 테니까 main()함수를 만들어서 이 createBall()함수를 call 하세요.
function main()
    createBall()
end
그리고 main.lua 맨 아래에서 이 main() 함수를 call 하세요.
function main()
    createBall()
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

main()

자 이러면 화면 한 가운데에 반지름이 10픽셀인 하얀 공이 나올 겁니다.


여기까지 됐구요. 그러면 이제 공을 움직여 보겠습니다.
공을 움직이는 것은 코로나의 physics엔진을 사용하기로 했습니다.
이 물리엔진을 사용하려면 우선 physics를 require해야 합니다.
require ("physics")
그리고 physics를 시작합니다.
physics.start()
Corona DOC 카테고리에 있는 physics강좌를 보시면 아시겠지만 기본적으로 코로나 물리엔진은 디폴트 값으로 (0,9.8)의 중력 값을 가집니다.
벽돌깨기 게임은 중력값이 필요 없으므로 이를 0,0 으로 세팅합니다.
physics.setGravity(0,0)
여기서 physics setUp도 함수로 따로 관리하겠습니다.
require만 빼놓고 나머지 두라인을 setUpPhysics() 함수 안에 넣고 이 함수를 main()함수에서 Call 하겠습니다.
require ("physics")

function main()
    setUpPhysics()
    createBall()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

main()
이제 이 공에 addBody를 하고 움직여 보겠습니다.
createBall()안에 공을 addBody 하는 코드를 아래와 같이 집어 넣습니다.
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})

그리고 실행하면 아무 변화가 없습니다. 여기서 setGraivity값을 0,0에서 0,9.8로 바꿔볼까요?

그러면 공이 아래로 떨어질 겁니다. y 좌표에 9.8의 중력값이 적용 됐기 때문입니다.
이 중력값 적용 대신에 공을 움직일 수 있는 방법은 뭘까요?
setLinearVelocity를 이용하면 됩니다.
다시 중력값을 0,0으로 고치고 createBall() 안에 ball:setLinearVelocity(75, 150) 코드를 추가로 집어 넣습니다.

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

그러면 이 공이 오른쪽 아래 방향으로 움직이게 됩니다.


지금은 공이 화면 밖으로 나가버리고 끝이 납니다.
오늘 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createBall()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
    physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
    ball:setLinearVelocity(75, 150)
end

main()

벽을 만들어 놓고 이 벽에 튕기게 하면 공이 화면안에서 계속 튀면서 다니겠죠?

다음 시간엔 벽을 만들고 이 벽들을 addBody해서 공이 튕기도록 하겠습니다.
벽뿐만 아니라 block과 paddle도 만들어서 이 앱에서 필요한 모든 객체들을 화면에 나타나도록 하겠습니다.

그럼 다음 시간에 뵈요.
반응형