반응형
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | package com.example.memorypower; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.Random; public class MainActivity extends AppCompatActivity { GameView gv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gv = new GameView(this); setContentView(gv); } class GameView extends View { final static int BLANK = 0; final static int PLAY = 1; final static int DELAY = 1500; int status; ArrayList<Shape> arShape = new ArrayList<Shape>(); // 도형들이 들어가는 공간 Random Rnd = new Random(); Activity mParent; myHandler mHandler = new myHandler(); // 생성자 public GameView(Context context) { super(context); // 부모의 클래스를 생성자를 통해 생성해주어야한다. mParent = (Activity) context; status = BLANK; // 처음엔 빈화면처럼 보이도록 mHandler.sendEmptyMessageDelayed(0, DELAY); // 빈메시지를 보내지만 단계별 수행을 위해 핸들러 필요 } public void onDraw(Canvas canvas) { canvas.drawColor(Color.BLACK); // 초기 캔버스는 검정색 if (status == BLANK) { // 지금 실행상태가 아니라면 return return; } for (int idx = 0; idx < arShape.size(); idx++) { Paint Pnt = new Paint(); // 새로운 그림을 그릴 준비 Pnt.setColor(arShape.get(idx).color); // 도형에 맞는 색으로 지정 Rect rt = arShape.get(idx).rt; // 도형 객체 가져오기 switch (arShape.get(idx).what) { // 이 도형이 무엇인지에 따라 그림 그려주기 case Shape.RECT: canvas.drawRect(rt, Pnt); break; case Shape.CIRCLE: canvas.drawCircle(rt.left + rt.width() / 2, rt.top + rt.height() / 2, rt.width() / 2, Pnt); break; case Shape.TRIANGLE: Path path = new Path(); path.moveTo(rt.left + rt.width() / 2, rt.top); path.lineTo(rt.left, rt.bottom); path.lineTo(rt.right, rt.bottom); canvas.drawPath(path, Pnt); break; } } } public boolean onTouchEvent(MotionEvent event) { // 눌렀을 때 if (event.getAction() == MotionEvent.ACTION_DOWN) { // 도형 인덱스 받아오고 int sel = FindShapeIdx((int) event.getX(), (int) event.getY()); // 없으면 true 반환 // 이때 true를 반환해야 이 이벤트가 사용된 것으로 판단되어 다른 곳으로 이벤트 전달이 되지 않는다. if (sel == -1) { return true; } /** *인덱스가 마지막으로 만들어진 도형과 같으면 다시 암전시키고 * invalidate() 콜하면서 onDraw() 재실행 */ if (sel == arShape.size() - 1) { status = BLANK; invalidate(); mHandler.sendEmptyMessageDelayed(0, DELAY); } // 만약 이전 도형 인덱스를 클릭했다면 아래와 같이 알림창 나타낸다. else { new AlertDialog.Builder(getContext()) .setCancelable(false) .setMessage("한번 더 하시겠습니까?") .setTitle("GAME OVER") .setPositiveButton("한번 더", new DialogInterface.OnClickListener() { // 초기화 @Override public void onClick(DialogInterface dialog, int which) { arShape.clear(); status = BLANK; invalidate(); mHandler.sendEmptyMessageDelayed(0, DELAY); } }) .setNegativeButton("종료", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mParent.finish(); } }) .show(); } return true; } return false; } void AddNewShape() { Shape shape = new Shape(); boolean bFindIntersect; // 겹치는 곳 없고, 화면 내에 존재하는 완전한 도형인지 확인하는 플래그 Rect rt = new Rect(); for (; ; ) { int Size = 32 + 16 * Rnd.nextInt(3); // 크기는 32,48,64중 하나 // 위치는 난수로 결정 rt.left = Rnd.nextInt(getWidth()); rt.top = Rnd.nextInt(getHeight()); rt.right = rt.left + Size; rt.bottom = rt.top + Size; // 화면 범위 벗어나면 continue if (rt.right > getWidth() || rt.bottom > getHeight()) { continue; } // 겹치는곳 없다고 가정 bFindIntersect = false; // 지금 내가 만든 도형과 기존 도형이 겹친다면 true for (int idx = 0; idx < arShape.size(); idx++) { if (rt.intersect(arShape.get(idx).rt) == true) { bFindIntersect = true; } } // 만들 수 있는 도형이라면 if (bFindIntersect == false) { break; } } // 도형의 모양과 색상을 선택한다. shape.what = (Rnd.nextInt(3)); switch (Rnd.nextInt(5)) { case 0: shape.color = Color.WHITE; break; case 1: shape.color = Color.RED; break; case 2: shape.color = Color.GREEN; break; case 3: shape.color = Color.BLUE; break; case 4: shape.color = Color.YELLOW; break; } // 도형 push shape.rt = rt; arShape.add(shape); } // 존재하는 도형중에서 하나라도 현재 좌표를 포함한다면 그 도형 인덱스 반환, 없으면 -1 int FindShapeIdx(int x, int y) { for (int idx = 0; idx < arShape.size(); idx++) { if (arShape.get(idx).rt.contains(x, y)) { return idx; } } return -1; } /** * 핸들러 클래스에는 메시지를 핸들하는 과정을 담아내고 있고 * 현재 메시지는 emptyMessage로 오긴하지만 그 메시지가 올때마다 * 아래와 같은 내용을 실행하게 된다. */ public class myHandler extends Handler { public void handleMessage(Message msg) { AddNewShape(); status = PLAY; invalidate(); String title = "MemoryPower - " + arShape.size() + " 단계"; mParent.setTitle(title); } } /** * 익명 이너 클래스를 이용하면 코드가 더 간결해진다. * Handler mHandler = new Handler() { * public void handleMessage(Message msg){ * AddNewShape(); * status = PLAY; * invalidate(); * * String title = "MemoryPower - " + arShape.size() + " 단계"; * mParent.setTitle(title); * } * } */ } // Shape 클래스 선언 class Shape { final static int RECT = 0; final static int CIRCLE = 1; final static int TRIANGLE = 2; int what, color; Rect rt; } } /** * 출처 : 안드로이드 프로그래밍 정복(한빛미디어) */ | cs |
반응형
'Basic > Android' 카테고리의 다른 글
Android Context 개념 및 이해 (2) | 2019.10.12 |
---|---|
Bitmap을 Drawable로 혹은 Drawable을 Bitmap으로 변환 (0) | 2019.10.10 |
Android 스레드와 핸들러를 이용한 UI 관리 (0) | 2019.09.29 |
Gradle tutorial 관련 사이트 (0) | 2019.09.23 |
Android LayoutInflater 개념 및 사용 방법 (4) | 2019.09.23 |