반응형

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


반응형