]> git.zerfleddert.de Git - FreeShisen/blob - src/org/proofofconcept/shisensho/ShisenShoView.java
1cc1e079b6aacb411404d51460d508a8fcb337b4
[FreeShisen] / src / org / proofofconcept / shisensho / ShisenShoView.java
1 package org.proofofconcept.shisensho;
2
3 import java.util.List;
4 import java.util.Timer;
5 import java.util.TimerTask;
6
7 import android.app.Activity;
8 import android.content.Context;
9 import android.graphics.Bitmap;
10 import android.graphics.BitmapFactory;
11 import android.graphics.Canvas;
12 import android.graphics.Color;
13 import android.graphics.Paint;
14 import android.graphics.Paint.Align;
15 import android.graphics.Paint.Cap;
16 import android.graphics.Paint.Join;
17 import android.graphics.Paint.Style;
18 import android.graphics.Rect;
19 import android.graphics.Typeface;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.view.MenuItem;
23 import android.view.MotionEvent;
24 import android.view.SurfaceHolder;
25 import android.view.SurfaceView;
26
27 class ShisenShoView extends SurfaceView implements SurfaceHolder.Callback {
28
29 private enum StatePlay { UNINITIALIZED, IDLE, SELECTED1, SELECTED2, GAMEOVER };
30 private enum StatePaint { BOARD, SELECTED1, SELECTED2, MATCHED, WIN, LOSE, HINT, TIME };
31
32 private int screenWidth;
33 private int screenHeight;
34 private int tilesetRows;
35 private int tilesetCols;
36 private int tileHeight;
37 private int tileWidth;
38 private Bitmap bg;
39 private Bitmap tile[];
40 private int[] selection1=new int[2];
41 private int[] selection2=new int[2];
42 private List<Point> path=null;
43 private List<Line> pairs=null;
44 private long startTime;
45 private long playTime;
46 private long baseTime;
47 private Timer timer;
48 private Handler timerHandler;
49
50 private boolean timerRegistered=false;
51 private ShisenSho app;
52 private StatePlay cstate;
53 private StatePaint pstate;
54 private Canvas canvas = null;
55 private SurfaceHolder surfaceHolder = null;
56 private String debugMessage = "";
57
58 public ShisenShoView(ShisenSho shishenSho) {
59 super((Context)shishenSho);
60 this.app = shishenSho;
61 cstate = StatePlay.UNINITIALIZED;
62 surfaceHolder = getHolder();
63 surfaceHolder.addCallback(this);
64 }
65
66 private void paint(StatePaint pstate) {
67 this.pstate=pstate;
68 repaint();
69 }
70
71 private void control(StatePlay cstate) {
72 this.cstate=cstate;
73 }
74
75 private void loadTileset() {
76 BitmapFactory.Options ops = new BitmapFactory.Options();
77 ops.inScaled = false;
78 Bitmap tileset = BitmapFactory.decodeResource(getResources(), R.drawable.tileset, ops);
79 tileset.setDensity(Bitmap.DENSITY_NONE);
80
81 // The tile set has 4 rows x 9 columns
82 tilesetRows = 4;
83 tilesetCols = 9;
84 tileWidth = tileset.getWidth()/tilesetCols;
85 tileHeight = tileset.getHeight()/tilesetRows;
86 tile = new Bitmap[tilesetRows*tilesetCols];
87 int k=0;
88 for (int i=0; i<tilesetRows; i++) {
89 for (int j=0; j<tilesetCols; j++) {
90 tile[k] = Bitmap.createBitmap(tileset, j*tileWidth, i*tileHeight, tileWidth, tileHeight, null, false);
91 tile[k].setDensity(Bitmap.DENSITY_NONE);
92 k++;
93 }
94 }
95 tileWidth = tile[0].getWidth();
96 tileHeight = tile[0].getHeight();
97 }
98
99 private void loadBackground() {
100 BitmapFactory.Options ops = new BitmapFactory.Options();
101 ops.inScaled = false;
102 bg = BitmapFactory.decodeResource(getResources(), R.drawable.kshisen_bgnd, ops);
103 bg.setDensity(Bitmap.DENSITY_NONE);
104 }
105
106 private void registerTimer() {
107 if (timer!=null) return; // Already registered
108 timerHandler = new Handler() {
109 public void handleMessage(Message msg) {
110 onUpdateTime();
111 }
112 };
113 timer=new Timer();
114 timer.scheduleAtFixedRate(new TimerTask() {
115 public void run() {
116 timerHandler.sendEmptyMessage(Activity.RESULT_OK);
117 }
118 }, 0, 1000);
119 timerRegistered=true;
120 }
121
122 private void unregisterTimer() {
123 if (timer==null) return; // Already unregistered
124 timer.cancel();
125 timer = null;
126 timerHandler = null;
127 timerRegistered=false;
128 }
129
130 public void pauseTime() {
131 updateTime();
132 baseTime = playTime;
133 startTime = System.currentTimeMillis();
134
135 }
136
137 public void resumeTime() {
138 startTime = System.currentTimeMillis();
139 updateTime();
140 }
141
142 private void updateTime() {
143 if (cstate!=StatePlay.GAMEOVER) {
144 playTime = (System.currentTimeMillis()-startTime)/1000+baseTime;
145 }
146 }
147
148 private void initializeGame() {
149 loadBackground();
150 loadTileset();
151 screenWidth=getWidth();
152 screenHeight=getHeight();
153 //undo.sensitive=false;
154 pstate=StatePaint.BOARD;
155 app.newPlay();
156 control(StatePlay.IDLE);
157 startTime=System.currentTimeMillis();
158 playTime=0;
159 baseTime=0;
160 if (app.timeCounter && !timerRegistered) {
161 registerTimer();
162 }
163 pairs=app.board.getPairs(1);
164 }
165
166 public boolean onOptionsItemSelected(MenuItem item) {
167 // Handle item selection
168 switch (item.getItemId()) {
169 case R.id.hint:
170 this.postDelayed(new Runnable() { public void run() { onHintActivate(); } }, 100);
171 return true;
172 case R.id.undo:
173 this.postDelayed(new Runnable() { public void run() { onUndoActivate(); } }, 100);
174 return true;
175 case R.id.clean:
176 this.postDelayed(new Runnable() { public void run() { reset(); } }, 100);
177 return true;
178 case R.id.options:
179 return true;
180 case R.id.about:
181 return true;
182 default:
183 return false;
184 }
185 }
186
187 public void reset() {
188 control(StatePlay.UNINITIALIZED);
189 paint(StatePaint.BOARD);
190 }
191
192 private void onHintActivate() {
193 if (cstate!=StatePlay.GAMEOVER) {
194 pairs=app.board.getPairs(1);
195 paint(StatePaint.HINT);
196 app.sleep(10);
197 paint(StatePaint.BOARD);
198 control(StatePlay.IDLE);
199 }
200 }
201
202 private void onUndoActivate() {
203 if (app.board.getCanUndo()) {
204 if (cstate==StatePlay.GAMEOVER && app.timeCounter && !timerRegistered) {
205 // Reprogram the time update that had been
206 // deactivated with the game over status
207 registerTimer();
208 }
209 app.board.undo();
210 paint(StatePaint.BOARD);
211 //undo.sensitive=app.board.getCanUndo();
212 control(StatePlay.IDLE);
213 }
214 }
215
216 public void onTimeCounterActivate() {
217 if (app.timeCounter && cstate!=StatePlay.GAMEOVER && !timerRegistered) {
218 // Reprogram the time update that had been
219 // deactivated with the time_counter=false
220 registerTimer();
221 }
222 }
223
224 private void onUpdateTime() {
225 paint(pstate);
226 if (!(app.timeCounter && cstate!=StatePlay.GAMEOVER)) {
227 unregisterTimer();
228 }
229 }
230
231 public void drawMessage(Canvas canvas, int x, int y, boolean centered, String message, String color, float textSize) {
232 Paint paint = new Paint();
233 paint.setColor(Color.parseColor(color));
234 paint.setLinearText(true);
235 paint.setAntiAlias(true);
236 paint.setTextAlign(centered?Align.CENTER:Align.LEFT);
237 paint.setTypeface(Typeface.SANS_SERIF);
238 paint.setFakeBoldText(true);
239 paint.setTextSize(textSize);
240 canvas.drawText(message, x, y, paint);
241 }
242
243 public void repaint() {
244 if (surfaceHolder == null) return;
245 try {
246 if (canvas == null) canvas = surfaceHolder.lockCanvas(null);
247 if (canvas == null) return;
248 if (cstate==StatePlay.UNINITIALIZED) initializeGame();
249 synchronized (surfaceHolder) {
250 doDraw(canvas);
251 }
252 } finally {
253 if (canvas != null) {
254 surfaceHolder.unlockCanvasAndPost(canvas);
255 canvas = null;
256 }
257 }
258 }
259
260 protected void doDraw(Canvas canvas) {
261 try {
262 // Double buffering
263 // Bitmap buffer = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
264 //Canvas cbuffer = new Canvas(buffer);
265 Canvas cbuffer = canvas;
266 if (canvas == null) return;
267
268 //super.onDraw(canvas);
269
270 // Board upper left corner on screen
271 int x0=0;
272 int y0=0;
273
274 if (app!=null && app.board!=null) {
275 x0=(screenWidth-app.board.boardSize[1]*tileWidth)/2;
276 y0=(screenHeight-app.board.boardSize[0]*tileHeight)/2;
277 }
278
279 int red = Color.parseColor("#FF0000");
280 int orange = Color.parseColor("#F0C000");
281 Paint paint = new Paint();
282 paint.setFlags(Paint.ANTI_ALIAS_FLAG);
283
284 // Background & board painting
285 switch (pstate) {
286 case BOARD:
287 case SELECTED1:
288 case SELECTED2:
289 case MATCHED:
290 case WIN:
291 case LOSE:
292 case HINT:
293 case TIME:
294 // Background painting
295 int bgWidth = bg.getWidth();
296 int bgHeight = bg.getHeight();
297 for (int i=0; i<screenHeight/bgHeight+1; i++) {
298 for (int j=0; j<screenWidth/bgWidth+1; j++) {
299 cbuffer.drawBitmap(bg, j*bgWidth, i*bgHeight, paint);
300 }
301 }
302
303 // Board painting
304 // Max visible size: 7x17
305 if (app!=null && app.board!=null) {
306 for (int i=0;i<app.board.boardSize[0];i++) {
307 for (int j=0;j<app.board.boardSize[1];j++) {
308 // Tiles are 56px height, 40px width each
309 char piece=app.board.board[i][j];
310 if (piece!=0) {
311 cbuffer.drawBitmap(tile[piece], x0+j*tileWidth, y0+i*tileHeight, paint);
312 }
313 }
314 }
315 }
316 break;
317 }
318
319 // Red rectangle for selection 1
320 switch (pstate) {
321 case SELECTED1:
322 case SELECTED2:
323 case MATCHED:
324 paint.setColor(red);
325 paint.setStyle(Style.STROKE);
326 paint.setStrokeCap(Cap.ROUND);
327 paint.setStrokeJoin(Join.ROUND);
328 paint.setStrokeWidth(3);
329 cbuffer.drawRect(new Rect(
330 x0+selection1[1]*tileWidth-2,
331 y0+selection1[0]*tileHeight-2,
332 x0+selection1[1]*tileWidth-2+tileWidth+2*2,
333 y0+selection1[0]*tileHeight-2+tileHeight+2*2),
334 paint);
335 break;
336 }
337
338 // Red rectangle for selection 2
339 switch (pstate) {
340 case SELECTED2:
341 case MATCHED:
342 paint.setColor(red);
343 paint.setStyle(Style.STROKE);
344 paint.setStrokeCap(Cap.ROUND);
345 paint.setStrokeJoin(Join.ROUND);
346 paint.setStrokeWidth(3);
347 cbuffer.drawRect(new Rect(
348 x0+selection2[1]*tileWidth-2,
349 y0+selection2[0]*tileHeight-2,
350 x0+selection2[1]*tileWidth-2+tileWidth+2*2,
351 y0+selection2[0]*tileHeight-2+tileHeight+2*2),
352 paint);
353 break;
354 }
355
356 // Matching path
357 switch (pstate) {
358 case MATCHED:
359 paint.setColor(red);
360 paint.setStyle(Style.STROKE);
361 paint.setStrokeCap(Cap.ROUND);
362 paint.setStrokeJoin(Join.ROUND);
363 paint.setStrokeWidth(3);
364
365 if (path!=null) {
366 Point p0=null;
367 for (Point p1 : path) {
368 if (p0!=null) {
369 cbuffer.drawLine(
370 x0+p0.j*tileWidth-2+(tileWidth/2),
371 y0+p0.i*tileHeight-2+(tileHeight/2),
372 x0+p1.j*tileWidth-2+(tileWidth/2),
373 y0+p1.i*tileHeight-2+(tileHeight/2),
374 paint);
375 }
376 p0=p1;
377 }
378 }
379 break;
380 }
381
382 // Orange hint rectangles
383 switch (pstate) {
384 case HINT:
385 if (pairs!=null && pairs.size()>0) {
386 Line pair=pairs.get(0);
387 Point a=pair.a;
388 Point b=pair.b;
389 path=app.board.getPath(a,b);
390 paint.setColor(orange);
391 paint.setStyle(Style.STROKE);
392 paint.setStrokeCap(Cap.ROUND);
393 paint.setStrokeJoin(Join.ROUND);
394 paint.setStrokeWidth(3);
395
396 cbuffer.drawRect(new Rect(
397 x0+a.j*tileWidth-2,
398 y0+a.i*tileHeight-2,
399 x0+a.j*tileWidth-2+tileWidth+2*2,
400 y0+a.i*tileHeight-2+tileHeight+2*2),
401 paint);
402
403 if (path!=null) {
404 Point p0=null;
405 for (Point p1 : path) {
406 if (p0!=null) {
407 cbuffer.drawLine(
408 x0+p0.j*tileWidth-2+(tileWidth/2),
409 y0+p0.i*tileHeight-2+(tileHeight/2),
410 x0+p1.j*tileWidth-2+(tileWidth/2),
411 y0+p1.i*tileHeight-2+(tileHeight/2),
412 paint);
413 }
414 p0=p1;
415 }
416 path=null;
417 }
418
419 cbuffer.drawRect(new Rect(
420 x0+b.j*tileWidth-2,
421 y0+b.i*tileHeight-2,
422 x0+b.j*tileWidth-2+tileWidth+2*2,
423 y0+b.i*tileHeight-2+tileHeight+2*2),
424 paint);
425 }
426 break;
427 }
428
429 // Win & loose notifications
430 switch (pstate) {
431 case WIN:
432 drawMessage(cbuffer, screenWidth/2,screenHeight/2,true,"You Win!", "#FFFFFF", 100);
433 break;
434 case LOSE:
435 drawMessage(cbuffer, screenWidth/2,screenHeight/2,true,"Game Over", "#FFFFFF", 100);
436 break;
437 }
438
439 if (app.timeCounter) switch (pstate) {
440 case BOARD:
441 case SELECTED1:
442 case SELECTED2:
443 case MATCHED:
444 case WIN:
445 case LOSE:
446 case HINT:
447 case TIME:
448 updateTime();
449 int hours=(int)(playTime/(60*60));
450 int minutes=(int)((playTime/60)%60);
451 int seconds=(int)(playTime%60);
452 String time=String.format("%01d:%02d:%02d", hours, minutes, seconds);
453
454 int timePosX=screenWidth-120;
455 int timePosY=screenHeight-10;
456
457 drawMessage(cbuffer, timePosX+1,timePosY+1,false,time,"#000000",30);
458 drawMessage(cbuffer, timePosX,timePosY,false,time,"#FFFFFF",30);
459 break;
460 }
461
462 // Debug messages
463 /*
464 debugMessage="StatePlay: "+cstate+"\n"+"StatePaint: "+pstate;
465 if (debugMessage!=null && debugMessage.length()>0) {
466 int l = 20;
467 String lines[] = debugMessage.split("\n");
468 for (int i=0; i<lines.length; i++) {
469 drawMessage(cbuffer,1,l,false,lines[i],"#FFFF00",30);
470 l+=30;
471 }
472 }
473 */
474
475 // Double buffer dumping
476 // canvas.drawBitmap(buffer, 0, 0, null);
477
478 } catch (Exception e) {
479 e.printStackTrace();
480 }
481
482 }
483
484 @Override
485 public boolean onTouchEvent(MotionEvent event) {
486 if (event.getAction()==MotionEvent.ACTION_DOWN) {
487 onClick(Math.round(event.getX()),Math.round(event.getY()));
488 }
489 return super.onTouchEvent(event);
490 }
491
492 private void onClick(int x, int y) {
493 try {
494 int i=(y-(screenHeight-app.board.boardSize[0]*tileHeight)/2)/tileHeight;
495 int j=(x-(screenWidth-app.board.boardSize[1]*tileWidth)/2)/tileWidth;
496
497 switch (cstate) {
498 case IDLE:
499 if (i>=0 &&
500 i<app.board.boardSize[0] &&
501 j>=0 && j<app.board.boardSize[1] &&
502 app.board.board[i][j]!=0) {
503 selection1[0]=i;
504 selection1[1]=j;
505 paint(StatePaint.SELECTED1);
506 control(StatePlay.SELECTED1);
507 }
508 break;
509 case SELECTED1:
510 if (i>=0 && i<app.board.boardSize[0] &&
511 j>=0 && j<app.board.boardSize[1] &&
512 app.board.board[i][j]!=0) {
513 if (i==selection1[0] && j==selection1[1]) {
514 paint(StatePaint.BOARD);
515 control(StatePlay.IDLE);
516 } else {
517 selection2[0]=i;
518 selection2[1]=j;
519 paint(StatePaint.SELECTED2);
520
521 Point a=new Point(selection1[0],selection1[1]);
522 Point b=new Point(selection2[0],selection2[1]);
523 path=app.board.getPath(a,b);
524 paint(StatePaint.MATCHED);
525 app.sleep(2);
526 paint(StatePaint.BOARD);
527 if (path.size()>0) {
528 app.board.play(a,b);
529 }
530 path=null;
531 paint(StatePaint.BOARD);
532
533 pairs=app.board.getPairs(1);
534 if (pairs.size()==0) {
535 if (app.board.getNumPieces()==0) {
536 paint(StatePaint.WIN);
537 } else {
538 paint(StatePaint.LOSE);
539 }
540 control(StatePlay.GAMEOVER);
541 } else {
542 control(StatePlay.IDLE);
543 }
544 //undo.sensitive=app.board.getCanUndo();
545 }
546 }
547 break;
548 case GAMEOVER:
549 reset();
550 paint(StatePaint.BOARD);
551 break;
552 }
553 } catch (Exception e) {
554 e.printStackTrace();
555 }
556 }
557
558 public void surfaceChanged(SurfaceHolder holder, int format, int width,
559 int height) {
560 surfaceHolder = holder;
561 if (cstate!=StatePlay.GAMEOVER && app.timeCounter && !timerRegistered) {
562 registerTimer();
563 }
564 repaint();
565 }
566
567 public void surfaceCreated(SurfaceHolder holder) {
568 surfaceHolder = holder;
569 repaint();
570 }
571
572 public void surfaceDestroyed(SurfaceHolder holder) {
573 surfaceHolder = null;
574 if (timerRegistered) {
575 unregisterTimer();
576 }
577 }
578
579 /*
580 @Override
581 protected void onDraw(Canvas canvas) {
582 super.onDraw(canvas);
583
584 if (!initialized) initialize();
585
586 long currTime = System.currentTimeMillis();
587
588 a = (float)(currTime - startTime) / (float)duration;
589 if (a > (float)1.0) a = (float)1.0;
590
591 x = Math.round(nextx*a + prevx*(1-a));
592 y = Math.round(nexty*a + prevy*(1-a));
593
594 if (a == (float)1.0) computeNextTarget();
595
596 int bgWidth = bg.getWidth();
597 int bgHeight = bg.getHeight();
598 for (int i=0; i<height/bgHeight+1; i++) {
599 for (int j=0; j<width/bgWidth+1; j++) {
600 canvas.drawBitmap(bg, j*bgWidth, i*bgHeight, paint);
601 }
602 }
603
604 canvas.drawBitmap(tile[randomtile], x, y, paint);
605
606 repaint();
607 }
608
609 @Override
610 public boolean onTouchEvent(MotionEvent event) {
611 if (event.getActionMasked()==MotionEvent.ACTION_DOWN) {
612 //computeNextTarget();
613 //nextx=Math.round(event.getX());
614 //nexty=Math.round(event.getY());
615 }
616 return super.onTouchEvent(event);
617 }
618
619 private void initialize() {
620 width = getWidth();
621 height = getHeight();
622
623 bg = BitmapFactory.decodeResource(getResources(), R.drawable.kshisen_bgnd);
624 Bitmap tileset = BitmapFactory.decodeResource(getResources(), R.drawable.tileset);
625
626 // The tile set has 4 rows x 9 columns
627 tsrows = 4;
628 tscols = 9;
629 twidth = tileset.getWidth()/tscols;
630 theight = tileset.getHeight()/tsrows;
631 tile = new Bitmap[tsrows*tscols];
632 int k=0;
633 for (int i=0; i<tsrows; i++) {
634 for (int j=0; j<tscols; j++) {
635 tile[k] = Bitmap.createBitmap(tileset, j*twidth, i*theight, twidth, theight, null, false);
636 k++;
637 }
638 }
639
640 x = width/2;
641 y = height/2;
642
643 computeNextTarget();
644
645 initialized = true;
646 }
647
648 private void computeNextTarget() {
649 startTime = System.currentTimeMillis();
650 prevx = x;
651 prevy = y;
652 nextx = (int) Math.floor(Math.random() * width);
653 nexty = (int) Math.floor(Math.random() * height);
654 randomtile = (int) Math.floor(Math.random() * tile.length);
655
656 paint = new Paint();
657 paint.setColor(Color.parseColor("#006666"));
658 paint.setFlags(Paint.ANTI_ALIAS_FLAG);
659 }
660 */
661 }
Impressum, Datenschutz