헬로, 안드로이드 5 주차 2D 그래픽배우기 (1) 강대기동서대학교컴퓨터정보공학부
학습목표 2D 그래픽에대해배운다. Color, Paint, Canvas, Path, Drawable 클래스를배운다. 스도쿠의게임시작하기를구현하고, Game 클래스, PuzzleView 클래스를정의한다. 정의된클래스내에서보드를그리고, 숫자를그린다. 숫자입력, 힌트추가, 화면흔들기를구현해본다.
차례 Color 클래스 Paint 클래스 Canvas 클래스 Path 클래스 Drawable 클래스 스도쿠의게임시작하기 Game 클래스 PuzzleView 클래스 보드그리기 숫자그리기 셀렉션정의및업데이트 숫자입력하기 힌트추가하기 화면흔들기
Color 클래스 색 알파 (alpha), 레드 (red), 그린 (green), 블루 (blue) 32 비트정수 알파 투명도 int color = Color.BLUE; // 파란색 color = Color.argb(127,255,0,255); // 반투명보라색 XML 리소스에서색상정의 <resources> <color name="mycolor">#3500ffff</color> </resources> 자바코드내에서사용 color = getresources().getcolor(r.color.mycolor);
Paint 클래스 비트맵, 텍스트, 기하학적모양의그래픽을그리는데필요한스타일과색상정보를가짐 화면에칠을할때필요한색상설정 cpaint.setcolor(color.ltgray);
Canvas 클래스 그림이그려지는표면 Activity > View > Canvas 캔버스에그리려면, View.onDraw() 를오버라이드 public class Graphics extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); } } static public class GraphicsView extends View { public GraphicsView(Context context) { super(context); } @Override protected void ondraw(canvas canvas) { // 사용자의그리기코드가여기에추가됨 } }
Path 클래스 선, 사각형, 커브등벡터그리기명령어를포함 원형경로정의 CW 는시계방향 circle = new Path(); circle.addcircle(150,150,100,direction.cw); 텍스트추가 private static final String QUOTE = 무능으로설명할수있는것을원한탓으로돌리지마라. ; canvas.drawpath(circle, cpaint); canvas.drawtextonpath(quote, circle, 0, 20, cpaint);
Drawable 클래스 비트맵, 단색등과같이화면표시용시각적요소에사용됨 다른그래픽에결합시킬수있으며, 사용자인터페이스위젯 ( 버튼이나뷰의배경 ) 에사용됨 Drawable 의형태 비트맵 (Bitmap) PNG 또는 JPG 이미지 나인패치 (NinePatch) 늘어나는 PNG 이미지 모양 (Shape) 경로에기초한벡터그리기명령어, Scalable Vector Graphics (SVG) 의축소판 레이어 (Layer) Z-order 순서에따라서로덮어그리는하위 drawable 을포함하는컨테이너 상태 (State) 상태 ( 비트마스크 ; bit mask) 에맞는하나의하위 drawable 을보여주는컨테이너 레벨 (Level) 컨테이너 스케일 (Scale) 컨테이너
스도쿠의게임시작하기 이제게임구현자체를보도록하자. startgame() Game 이라는액티비티를위해새인텐트를만들고 extradata 영역에난이도수준숫자를넣고 startactivity() 호출로액티비티시작 /** Start a new game with the given difficulty level */ private void startgame(int i) { Log.d(TAG, "clicked on " + i); Intent intent = new Intent(Sudoku.this, Game.class); intent.putextra(game.key_difficulty, i); startactivity(intent); }
Game 클래스 Sudoku4/src/org/example/sudoku/Sudoku.java 인텐트에서난이도의숫자를가져와이에적합한퍼즐을고름 PuzzleView 클래스인스턴스생성하여뷰의새콘텐츠로설정 (XML 에서하지않고코드에서함 ) calculateusedtiles() 메서드 수도쿠규칙을사용해서각타일에더이상사용될수없는숫자를알아냄 Game 클래스는액티비티이므로 AndroidManifest.xml 에등록해놓음
PuzzleView 클래스 생성자안에서뷰의폭과높이를사용하지말것 onsizechanged() 메서드에서값이정해지면받음 ondraw() 메서드에서 getwidth(), getheight() 메서드사용 생성자안에서 Game 클래스의참조를저장 뷰에서사용자입력이허용되도록옵션설정 onsizechanged() 메서드는안드로이드운영체제가모든것의크기를파악한후호출됨 여기서화면의각타일의크기를계산함
그래픽처리전략 안드로이드운영체제는뷰가수정될때마다 ondraw() 메서드를호출함 화면전체를다시만든다고가정하는것이나, 실은작은부분만다시그림 안드로이드운영체제가부분선택 (clipping) 을대신해줌 다음과같이여러방법을시도해보았음 버튼을각타일에사용해봄 ImageView 클래스의그리드를 XML 안에선언해봄 결국, 전체퍼즐을뷰하나에만들고, 그안에선과숫자를그려넣는방식을선택함 다만, 선택영역 (selection) 을그려야함과키보드와터치이벤트를명시적으로처리해야하는등의결점이있음 가능하다면표준위젯과뷰를사용해보고, 불가피할경우에사용자정의방식을선택하는게좋음
보드그리기 /res/values/colors.xml 에서색상들정의 ondraw() 내에서보드, 숫자, 힌트, 선택영역등을순차적으로그린다 canvas.drawline() 으로보조그리드라인과주그리드라인을그리면됨
숫자그리기 각숫자들이타일에정확히중앙에오도록퍼즐숫자를집어넣음 글자높이를타일높이의 ¾ 로설정하고, 가로세로비율을동일하게맞춤 가로방향은타일의폭을이등분함 세로방향은시작점을약간아래로조정해야함 이를위해 FontMetrics 클래스를사용하여한글자가얼마만큼의세로공간을차지하는지를알아내어, 그것을이등분함 canvas.drawtext() 메서드를사용하여숫자를넣음
입력다루기 아이폰프로그래밍의장점은폰이하나로고정되어있어서, 화면의가로세로크기를계산하여그래픽을처리할필요가없다는것 따라서, 아예애플측에서는직접고정된상수로입력하는것을선호한다는말조차도있음 안드로이드의경우, 폰의크기가다양하고, 넷북일수도있으며, 디패드 ( 키패드 ), 터치스크린, 트랙볼등의입력도있을수있음 따라서, 화면의다양한해상도는물론여러입력장치까지지원해야함
셀렉션정의및업데이트 어떤타일이선택되었는지를보여주는작은커서를만들어본다 커서란단순히마우스커서나커맨드프롬프트커서가아닌, 뭔가초점의대상인것을커서라고부름 이는데이터베이스에서레코드들을가져오는경우나객체지향프로그래밍에서컨테이너를다루는경우에도마찬가지임 선택된타일 사용자가숫자를입력할때, 변경되는타일 ondraw() 메서드에서선택된타일표시 onsizechanged() 에서미리정의된선택영역사각형 (selrect) 을사용하여선택된타일위에알파값이있는색을입힘 (selected)
셀렉션정의및업데이트 onkeydown() 메서드에서선택영역을옮김 이를통해디패드의키이벤트처리 트랙볼의경우? à ontrackballevent() 를오버라이드하면되지만, 만일오버라이드안하면안드로이드는자동으로디패드이벤트로해석함 대부분이런경우가많은데, 예를들어, 대부분의컴퓨터에서바코드리더기를통한입력의경우에도, 드라이버를통해자동으로키보드입력으로해석됨 ondraw() 밖에서는드로잉함수를절대호출할수없음 대신 invalidate() 호출을사용하여다시그려져야됨을알림 ( 더티영역 dirty area) select() 함수에서 invalidate() 는이전선택영역사각형과새로운선택영역사각형에대해두번호출됨 안드로이드의윈도매니저는특정시점에서더티한사각형들을모두합해서 ondraw() 를다시호출함
숫자입력하기 숫자입력을위해 0 부터 9 까지의숫자를다루는 case 문을추가함 0 과스페이스는숫자를지우는것을의미하게함 사용자가디패드를사용하는경우, onkeydown() 을오버라이드하여디패드중앙버튼이나엔터버튼의입력을확인하고키패드창을띄워숫자를고르게함 터치스크린에서는 ontouchevent() 메서드를오버라이드하여동일한키패드를사용자에게보여줌 어떤방식을쓰든타일위의숫자를바꾸려면, setselectedtile() 메서드호출 setselectedtile() 메서드에서는 invalidate() 를호출하되매개변수는없음 즉화면전체를다시그림 이유는새로추가된숫자나새로지워진숫자가사용자에게주어질힌트를변경하게되어다른타일들의배경색이달라질수있기때문임
힌트추가하기 퍼즐을풀어주지는않지만, 사용자를도와주기위해배경색을다르게함 빈타일에들어갈수있는숫자들의경우의수에따라타일배경색을다르게함 만일사용자가실수를저지른경우, 그에따라해당타일에다른배경색을설정함
화면흔들기 사용자가이미사용된숫자를집어넣는것과같은명백한실수를하는경우, 화면을앞뒤로흔들어줌 /res/anim/shake.xml 에정의된 R.anim.shake 리소스를불러와실행해서화면을 1 초에 10 픽셀씩좌우로흔들어줌 이애니메이션의실행횟수와속력, 가속도등은 XML 내에정의된애니메이션인터폴레이터 (interpolator) 에의해조정됨 인터폴레이터 /res/anim/cycle_7.xml
요약 2D 그래픽에대해배웠다. Color, Paint, Canvas, Path, Drawable 클래스를배웠다. 스도쿠의게임시작하기를구현하고, Game 클래스, PuzzleView 클래스를정의해보았다. 정의된클래스내에서보드를그리고, 숫자를그려보았다. 숫자입력, 힌트추가, 화면흔들기를구현하였다.
퀴즈 화면에칠할때필요한색상을설정하려면어떤클래스들을이용해야하는가? 화면에그림이그려지는표면은어떤클래스인가? Path 클래스의역할을설명하라. Drawable 한것들을아는대로열거하라. XML 로콘텐츠를설정하지않고, 코드로설정하는경우의장점은무엇인가? 생성자에서뷰의폭과높이를사용하지말아야할이유는무엇인가? Activity 클래스의 onsizechanged() 메서드에서할수있는일들은무엇인가? 아는대로쓰라. Activity 클래스의 ondraw() 메서드는어떤일을하는가? Canvas 클래스의 drawline() 메서드를설명하라. Canvas 클래스의 drawtext() 메서드를설명하라. FontMetrics 클래스에대해설명하라. Activity 클래스의 onkeydown() 메서드는어떤일을하는가? Activity 클래스의 ontrackballevent() 메서드는어떤일을하는가? invalidate() 메서드에서매개변수가있을때와없을때의차이는무엇인가? 애니메이션인터폴레이터란무엇인가?
연습문제 힌트로들어갈배경색을임의로바꾸어보자 수도쿠프로그램에서화면흔들기를 1 초에 20 픽셀씩좌우로흔드는것을 10 회반복하도록고쳐보자 자신의 Hello Android 프로그램에서화면흔들기를 1 초에 10 픽셀씩좌우로흔드는것을 7 회반복하도록해보자 힌트 : XML 파일에서최상위 Layout 에대해 ID 를부여한뒤, findviewbyid() 로해당 Layout 의 View 참조를가져와멤버변수로저장한다 버튼을타일하나로설정하는방법으로수도쿠화면을구현해보라 ImageView 클래스를통해수도쿠화면을구현해보라
프로젝트아이디어 Nonomino Sudoku 를구현하는프로젝트를고려해보자. Nonomino Sudoku 는다음에소개되어있다. http://www.boldts.net/sudoku/n0/