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