Android应用实践之数独游戏开发

数独游戏是一种源自18世纪末的瑞士的游戏,后在美国发展、并在日本得以发扬光大的数学智力拼图游戏。拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格。在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列、每一行的数字都不重复。

数独的玩法逻辑简单,数字排列方式千变万化。不少教育者认为数独是锻炼脑筋的好方法,上外语阅读课的时候外教老师就很喜欢带我们玩这个,乐此不疲,老外的教学方式还是很受欢迎的。但是每次玩这个游戏的时候都要发一张数独游戏卡,嫌麻烦,就想着写一个demo放自己手机上,想想那个时候真是好奇心爆棚,碰上很火爆的小游戏都想整一个DIY的Demo,叨叨够了,哈哈,上源码。

一、界面布局

1.主界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:background="@color/background"
  android:layout_height="fill_parent"
  android:layout_width="fill_parent"
  android:padding="30dip"
  android:orientation="horizontal">
  <LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center">

    <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:layout_marginBottom="25dip"
      android:text="@string/main_title"
      android:textSize="24sp" />

    <Button
      android:id="@+id/continue_button"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/continue_label" />

    <Button
      android:id="@+id/new_button"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/new_game_label" />

    <Button
      android:id="@+id/about_button"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/about_label" />

    <Button
      android:id="@+id/exit_button"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/exit_label" />
  </LinearLayout>

</LinearLayout>

2.数字键盘布局

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/keypad"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:background="@color/puzzle_background"
  android:stretchColumns="*" >

  <TableRow >

    <Button
      android:id="@+id/keypad_1"
      android:text="@string/keypad_1" />

    <Button
      android:id="@+id/keypad_2"
      android:text="@string/keypad_2" />

    <Button
      android:id="@+id/keypad_3"
      android:text="@string/keypad_3" />
  </TableRow>

  <TableRow >

    <Button
      android:id="@+id/keypad_4"
      android:text="@string/keypad_4" />

    <Button
      android:id="@+id/keypad_5"
      android:text="@string/keypad_5" />

    <Button
      android:id="@+id/keypad_6"
      android:text="@string/keypad_6" />
  </TableRow>

  <TableRow >

    <Button
      android:id="@+id/keypad_7"
      android:text="@string/keypad_7" />

    <Button
      android:id="@+id/keypad_8"
      android:text="@string/keypad_8" />

    <Button
      android:id="@+id/keypad_9"
      android:text="@string/keypad_9" />
  </TableRow>

</TableLayout>

3.游戏提示布局

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:padding="10dip">
  <TextView
    android:id="@+id/about_content"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/about_text"/>
</ScrollView>

二、游戏提示类

package com.dw.gamesuduku;

import android.app.Activity;
import android.os.Bundle;
public class About extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.about);
  }
}

三、逻辑实现1

package com.dw.gamesuduku;

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class Game extends Activity {
  private static final String TAG="Sudoku";
  private static final String PREF_PUZZLE="puzzle";
  protected static final int DIFFICULTY_CONTINUE=-1;

  public static final String KEY_DIFFICULTY="difficulty";
  public static final int DIFFICULTY_EASY=0;
  public static final int DIFFICULTY_MEDIUM=1;
  public static final int DIFFICULTY_HARD=2;

  private int puzzle[]=new int[9*9];
  private PuzzleView puzzleView;
  //三种游戏模式
  private static final String easyPuzzle="360000000004230800000004200"+
                  "070460003820000014500013010"+
                  "001900000007048300000000045";
  private static final String mediumPuzzle="650000070000506000014000005"+
                       "007009000002314700000700800"+
                       "500000630000201000030000097";
  private static final String hardPuzzle="009000000080605020501078000"+
                      "000000700706040102004000000"+
                      "000720903090301080000000600";

  private final int used[][][]=new int[9][9][];
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    Log.e(TAG, "onCreate");
    int diff=getIntent().getIntExtra(KEY_DIFFICULTY, DIFFICULTY_EASY);
    puzzle=getPuzzle(diff);
    calculateUsedTiles();

    puzzleView=new PuzzleView(this);
    setContentView(puzzleView);
    puzzleView.requestFocus();
    //if the activity is restarted ,do a continue next time
    getIntent().putExtra(KEY_DIFFICULTY, DIFFICULTY_CONTINUE);
  }

  @Override
  protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    Music.stop(this);
    //Save the current puzzle
    getPreferences(MODE_PRIVATE).edit().putString(PREF_PUZZLE, toPuzzleString(puzzle)).commit();
  }

  @Override
  protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    Music.play(this, R.raw.game);
  }

  protected int[] getUsedTiles(int x,int y){
    return used[x][y];
  }

  private void calculateUsedTiles() {
    // TODO Auto-generated method stub
    for (int x = 0; x < 9; x++) {
      for (int y = 0; y < 9; y++) {
        used[x][y]=calculateUsedTiles(x,y);
      }
    }
  }
  private int[] calculateUsedTiles(int x, int y) {
    // TODO Auto-generated method stub
    int c[]=new int[9];
    //horizontal

    for(int i=0;i<9;i++){
      if(i==y)
        continue;
      int t=getTitle(x, i);
      if(t!=0)
        c[t-1]=t;
    }
    //vertical

    for(int i=0;i<9;i++){
      if(i==x)
        continue;
      int t=getTitle(i, y);
      if(t!=0)
        c[t-1]=t;
    }
    //same cell block
    int startx=(x/3)*3;
    int starty=(y/3)*3;
    for(int i=startx;i<startx+3;i++){
      for(int j=starty;j<starty+3;j++){
        if(i==x&&j==y)
          continue;
        int t=getTitle(i, j);
        if(t!=0)
          c[t-1]=t;
      }
    }
    //compress
    int nused=0;
    for (int t : c) {
      if(t!=0)
      nused++;
    }
    int c1[]=new int[nused];
    nused=0;
    for (int t : c) {
      if(t!=0)
        c1[nused++]=t;
    }
    return c1;
  }
  //give a difficulty level
  private int[] getPuzzle(int diff) {
    // TODO Auto-generated method stub
    String puz = null;
    switch (diff) {
    case DIFFICULTY_CONTINUE:
      puz=getPreferences(MODE_PRIVATE).getString(PREF_PUZZLE, easyPuzzle);
      break;
    case DIFFICULTY_HARD:
      puz=hardPuzzle;
      break;
    case DIFFICULTY_MEDIUM:
      puz=mediumPuzzle;
      break;
    case DIFFICULTY_EASY:
      puz=easyPuzzle;
      break;
    }
    return fromPuzzleString(puz);
  }
  //convert an array into a puzzle string
  static private String toPuzzleString(int[] puz){
    StringBuilder buf=new StringBuilder();
    for (int element : puz) {
      buf.append(element);
    }
    return buf.toString();
  }
  //convert a puzzle string to an array
  static protected int[] fromPuzzleString(String string) {
    // TODO Auto-generated method stub
    int[] puz=new int[string.length()];
    for (int i = 0; i < puz.length; i++) {
    puz[i]=string.charAt(i)-'0';
    }
    return puz;
  }
  public String getTitleString(int x, int y) {
    // TODO Auto-generated method stub
    int v=getTitle(x,y);
    if(v==0)
      return "";
    else
      return String.valueOf(v);
  }
  private int getTitle(int x, int y) {
    // TODO Auto-generated method stub
    return puzzle[y*9+x];
  }
  private void setTitle(int x,int y,int value){
    puzzle[y*9+x]=value;
  }
  //change the tile only if it's a valid move
  protected boolean setTileIfValid(int x, int y, int value) {
    // TODO Auto-generated method stub
    int tiles[]=getUsedTiles(x, y);
    if(value!=0){
      for (int tile : tiles) {
        if(tile==value)
          return false;
      }
    }
    setTitle(x, y, value);
    calculateUsedTiles();
    return true;

  }
  //open the keypad if there are any valid moves
  protected void showKeypadOrError(int x, int y) {
    // TODO Auto-generated method stub
    int tiles[]=getUsedTiles(x, y);
    if(tiles.length==9){
      Toast toast=Toast.makeText(this, R.string.no_moves_label, Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.BOTTOM, 0, 0);
      toast.show();
    }else{
      Log.d(TAG, "showKeypad:used="+toPuzzleString(tiles));
      Dialog v=new Keypad(this,tiles,puzzleView);
      v.show();
    }
  }
}

四、数字键盘

package com.dw.gamesuduku;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public class Keypad extends Dialog {

  protected static final String TAG="Sudoku";
  private final View keys[]=new View[9];
  private View keypad;
  private final int useds[];
  private PuzzleView puzzleView;

  public Keypad(Context context,int useds[],PuzzleView puzzleView){
    super(context);
    this.useds=useds;
    this.puzzleView=puzzleView;
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.keypad);
    findViews();
    for (int element : useds) {
      if(element!=0){
        keys[element-1].setVisibility(View.INVISIBLE);
      }
      setListeners();
    }
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    // TODO Auto-generated method stub
    int tile=0;
    switch (keyCode) {
    case KeyEvent.KEYCODE_0:
    case KeyEvent.KEYCODE_SPACE:tile=0;break;
    case KeyEvent.KEYCODE_1:tile=1;break;
    case KeyEvent.KEYCODE_2:tile=2;break;
    case KeyEvent.KEYCODE_3:tile=3;break;
    case KeyEvent.KEYCODE_4:tile=4;break;
    case KeyEvent.KEYCODE_5:tile=5;break;
    case KeyEvent.KEYCODE_6:tile=6;break;
    case KeyEvent.KEYCODE_7:tile=7;break;
    case KeyEvent.KEYCODE_8:tile=8;break;
    case KeyEvent.KEYCODE_9:tile=9;break;
    default:
      return super.onKeyDown(keyCode, event);
    }
    if(isValid(tile)){
      returnResult(tile);
    }
    return true;
  }

  private boolean isValid(int tile) {
    // TODO Auto-generated method stub
    for (int t : useds) {
      if(tile==t)
        return false;
    }
    return true;
  }

  private void findViews() {
    // TODO Auto-generated method stub
    keypad=findViewById(R.id.keypad);
    keys[0]=findViewById(R.id.keypad_1);
    keys[1]=findViewById(R.id.keypad_2);
    keys[2]=findViewById(R.id.keypad_3);
    keys[3]=findViewById(R.id.keypad_4);
    keys[4]=findViewById(R.id.keypad_5);
    keys[5]=findViewById(R.id.keypad_6);
    keys[6]=findViewById(R.id.keypad_7);
    keys[7]=findViewById(R.id.keypad_8);
    keys[8]=findViewById(R.id.keypad_9);
  }
  private void setListeners(){
    for(int i=0;i<keys.length;i++){
      final int t=i+1;
      keys[i].setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
          // TODO Auto-generated method stub
          returnResult(t);
        }
      });
    }
    keypad.setOnClickListener(new View.OnClickListener() {
      public void onClick(View arg0) {
        // TODO Auto-generated method stub
        returnResult(0);
      }
    });
  }
  private void returnResult(int tile) {
    // TODO Auto-generated method stub
    puzzleView.setSelectedTile(tile);
    dismiss();
  }

}

五、背景音乐

package com.dw.gamesuduku;

import android.content.Context;
import android.media.MediaPlayer;

public class Music {
  private static MediaPlayer mp=null;
  //stop old song and start a new song
  public static void play(Context context,int resource){
    stop(context);
    if(Settings.getMusic(context)){
    mp=MediaPlayer.create(context, resource);
    mp.setLooping(true);
    mp.start();
    }
  }
  //stop the music
  public static void stop(Context context) {
    // TODO Auto-generated method stub
    if(mp!=null){
      mp.stop();
      mp.release();
      mp=null;
    }
  }
}

六、逻辑实现2

package com.dw.gamesuduku;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;

@SuppressLint("DrawAllocation")
public class PuzzleView extends View {
  private static final String TAG = "Sudoku";
  private final Game game;

  private float width;
  private float height;
  private int selX;
  private int selY;
  private final Rect selRect = new Rect();

  private static final String SELX="selX";
  private static final String SELY="selY";
  private static final String VIEW_STATE="viewState";
  private static final int ID=42;//any positive int num

  public PuzzleView(Context context) {
    super(context);
    this.game = (Game) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    setId(ID);
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // TODO Auto-generated method stub
    width = w / 9f;
    height = h / 9f;
    getRect(selX, selY, selRect);
    Log.d(TAG, "onSizeChanged:width" + width + ",height" + height);
    super.onSizeChanged(w, h, oldw, oldh);
  }

  //实例状态保存在bundle中,保存当前游戏状态
  @Override
  protected Parcelable onSaveInstanceState() {
    // TODO Auto-generated method stub
    Parcelable p=super.onSaveInstanceState();
    Log.d(TAG, "onSavedInstanceState");
    Bundle bundle=new Bundle();
    bundle.putInt(SELX, selX);
    bundle.putInt(SELY, selY);
    bundle.putParcelable(VIEW_STATE, p);
    return bundle;
  }
   //恢复已经保存的信息
  @Override
  protected void onRestoreInstanceState(Parcelable state) {
    // TODO Auto-generated method stub
    Log.d(TAG, "onRestoreInstanceState");
    Bundle bundle=(Bundle) state;
    select(bundle.getInt(SELX),bundle.getInt(SELY));
    super.onRestoreInstanceState(bundle.getParcelable(VIEW_STATE));
    return;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    // draw background
    Paint background = new Paint();
    background.setColor(getResources().getColor(R.color.puzzle_background));
    canvas.drawRect(0, 0, getWidth(), getHeight(), background);

    // draw board
    Paint dark = new Paint();
    dark.setColor(getResources().getColor(R.color.puzzle_dark));

    Paint hilite = new Paint();
    hilite.setColor(getResources().getColor(R.color.puzzle_hilite));

    Paint light = new Paint();
    light.setColor(getResources().getColor(R.color.puzzle_light));

    // draw minor grid lines
    for (int i = 0; i < 9; i++) {
      canvas.drawLine(0, i * height, getWidth(), i * height, light);
      canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
          hilite);
      canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
      canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
          hilite);
    }
    // draw major grid lines
    for (int i = 0; i < 9; i++) {
      if (i % 3 != 0)
        continue;
      canvas.drawLine(0, i * height, getWidth(), i * height, dark);
      canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
          hilite);
      canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
      canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
          hilite);
    }
    // draw numbers
    Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
    foreground.setColor(getResources().getColor(R.color.puzzle_foregroud));
    foreground.setStyle(Style.FILL);
    foreground.setTextSize(height * 0.75f);
    foreground.setTextScaleX(width / height);
    foreground.setTextAlign(Paint.Align.CENTER);
    // draw num in the center of the tile
    FontMetrics fm = foreground.getFontMetrics();
    float x = width / 2;
    float y = height / 2 - (fm.ascent + fm.descent) / 2;
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        canvas.drawText(this.game.getTitleString(i, j), i * width + x,
            j * height + y, foreground);
      }
    }
    // draw the selection
    Log.e(TAG, "selRect=" + selRect);
    Paint selected = new Paint();
    selected.setColor(getResources().getColor(R.color.puzzle_selected));
    canvas.drawRect(selRect, selected);

    //draw the hints pick a hint color based on moves left
    //根据每个单元格可填的数目给出不同颜色的提示
    if(Settings.getHints(getContext())){
    Paint hint=new Paint();
    int c[]={getResources().getColor(R.color.puzzle_hint_0),
        getResources().getColor(R.color.puzzle_hint_1),
        getResources().getColor(R.color.puzzle_hint_2),};
    Rect r=new Rect();
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        int movesleft=9-game.getUsedTiles(i, j).length;
        if(movesleft<c.length){
          getRect(i, j, r);
          hint.setColor(c[movesleft]);
          canvas.drawRect(r, hint);
        }
      }
    }
  }
  }
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    // TODO Auto-generated method stub
    Log.d(TAG, "onKeyDown:keycode=" + keyCode + ",event=" + event);
    switch (keyCode) {
    case KeyEvent.KEYCODE_DPAD_UP:
      select(selX, selY - 1);
      break;
    case KeyEvent.KEYCODE_DPAD_DOWN:
      select(selX, selY + 1);
      break;
    case KeyEvent.KEYCODE_DPAD_LEFT:
      select(selX - 1, selY);
      break;
    case KeyEvent.KEYCODE_DPAD_RIGHT:
      select(selX + 1, selY);
      break;
    case KeyEvent.KEYCODE_0:
    case KeyEvent.KEYCODE_SPACE:
      setSelectedTile(0);
      break;
    case KeyEvent.KEYCODE_1:
      setSelectedTile(1);
      break;
    case KeyEvent.KEYCODE_2:
      setSelectedTile(2);
      break;
    case KeyEvent.KEYCODE_3:
      setSelectedTile(3);
      break;
    case KeyEvent.KEYCODE_4:
      setSelectedTile(4);
      break;
    case KeyEvent.KEYCODE_5:
      setSelectedTile(5);
      break;
    case KeyEvent.KEYCODE_6:
      setSelectedTile(6);
      break;
    case KeyEvent.KEYCODE_7:
      setSelectedTile(7);
      break;
    case KeyEvent.KEYCODE_8:
      setSelectedTile(8);
      break;
    case KeyEvent.KEYCODE_9:
      setSelectedTile(9);
      break;
    case KeyEvent.KEYCODE_ENTER:
    case KeyEvent.KEYCODE_DPAD_CENTER:
      game.showKeypadOrError(selX, selY);
    default:
      return super.onKeyDown(keyCode, event);
    }
    return true;
  }

  //显示软键盘
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if(event.getAction()!=MotionEvent.ACTION_DOWN)
    return super.onTouchEvent(event);

    select((int)(event.getX()/width),(int)(event.getY()/height));
    game.showKeypadOrError(selX, selY);
    Log.d(TAG, "onTouchEvent:x"+selX+",y"+selY);
    return true;
  }

  public void setSelectedTile(int tile) {
    // TODO Auto-generated method stub
    //num is not valid for this tile
    Log.d(TAG, "selectedTile:invalid:"+tile);
//   startAnimation(AnimationUtils.loadAnimation(game, R.aims.shake));
    if (game.setTileIfValid(selX, selY, tile)) {
      invalidate();
    } else {
      // num is not invalid for this tile
      Log.d(TAG, "setSelectedTile:invalid " + tile);
    }

  }
  // 首先计算选定区域的x,y坐标,然后再次调用getRect方法计算新的选择矩形
  private void select(int x, int y) {
    // TODO Auto-generated method stub
    invalidate(selRect);// 第一次调用通知原选择的区域需要重绘
    selX = Math.min(Math.max(x, 0), 8);
    selY = Math.min(Math.max(y, 0), 8);
    getRect(selX, selY, selRect);
    invalidate(selRect);// 第二次调用通知新选择的区域也需要重绘
  }

  private void getRect(int x, int y, Rect rect) {
    // TODO Auto-generated method stub
    rect.set((int) (x * width), (int) (y * height),
        (int) (x * width + width), (int) (y * height + height));

  }

}

七、游戏设置

package com.dw.gamesuduku;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;

public class Settings extends Activity {
  private static final String OPT_MUSIC="music";
  private static final boolean OPT_MUSIC_DEF=true;
  private static final String OPT_HINTS="hints";
  private static final boolean OPT_HINTS_DEF=true;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragement()).commit();
  }
  public static class PrefsFragement extends PreferenceFragment{
    public void onCreate(Bundle savedInstanceState) {
      // TODO Auto-generated method stub
      super.onCreate(savedInstanceState);
      addPreferencesFromResource(R.xml.settings);
    }
  }
  //get the current music option
  public static boolean getMusic(Context context){
    return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_MUSIC,OPT_MUSIC_DEF);
  }
  //get the current music option
  public static boolean getHints(Context context){
    return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_HINTS,OPT_HINTS_DEF);
  }
}

八、游戏入口

package com.dw.gamesuduku;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;

public class Sudoku extends Activity implements OnClickListener {
  private static final String TAG = "Sudoku";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    View continueButton = this.findViewById(R.id.continue_button);
    continueButton.setOnClickListener(this);

    View newButton = this.findViewById(R.id.new_button);
    newButton.setOnClickListener(this);

    View aboutButton = this.findViewById(R.id.about_button);
    aboutButton.setOnClickListener(this);

    View exitButton = this.findViewById(R.id.exit_button);
    exitButton.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    // TODO Auto-generated method stub
    switch (v.getId()) {
    case R.id.continue_button:
      startGame(Game.DIFFICULTY_CONTINUE);
    case R.id.about_button:
      Intent i = new Intent(this, About.class);
      startActivity(i);
      break;
    case R.id.new_button:
      openNewGameDialog();
      break;
    case R.id.exit_button:
      finish();
      break;
    }
  }
  @Override
  protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    Music.play(this, R.raw.welcome);
  }
  @Override
  protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    Music.stop(this);
  }
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // TODO Auto-generated method stub

    super.onCreateOptionsMenu(menu);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // TODO Auto-generated method stub
    switch (item.getItemId()) {
    case R.id.settings:
      startActivity(new Intent(this, Settings.class));
      return true;
    }
    return false;
  }

  private void openNewGameDialog() {
    // TODO Auto-generated method stub
    new AlertDialog.Builder(this).setTitle(R.string.new_game_title)
        .setItems(R.array.difficulty,
            new DialogInterface.OnClickListener() {

              @Override
              public void onClick(
                  DialogInterface dialoginterface, int i) {
                // TODO Auto-generated method stub
                startGame(i);
              }
            }).show();
  }
  protected void startGame(int i) {
    // TODO Auto-generated method stub
    Log.i(TAG, "clicked on"+i);
    Intent intent=new Intent(Sudoku.this,Game.class);
    intent.putExtra(Game.KEY_DIFFICULTY, i);
    startActivity(intent);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义View实现数独游戏

    先说一下数独游戏的规则: 1.在整个横坐标和纵坐标的9个格子上只能填土1-9的数字且不重复 2.在当前3*3 的格子上填入1-9数字且不重复 先给大家看效果图 项目思路 1.UI呈现:这个放在 GameView 类里面         显示原始数据         显示当然用户填写的数据         显示用户当前点击的位置         显示候选区数据 2.逻辑处理:这个是放在Matrix类里面的     原始数据:游戏开始的时候就要创建出来的,     当前数据:用户填写上去的实时数据

  • java数独游戏完整版分享

    本文实例为大家分享了java数独游戏的具体代码,供大家参考,具体内容如下 自己写的数独游戏,共9关,代码如下: 1.DoShudu类用于产生数独数组 import java.util.Random; public class DoShudu { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[][] cells=newshudu(); //ce

  • 简单实现Android数独游戏

    本文实例为大家分享了Android数独游戏的具体代码,供大家参考,具体内容如下 实现了点击了相关的单元格之后会显示出对话框提示可选数字. 原始的自定义对话框仍旧不能满足我们的要求,原始的自定义对话框只能够生成Bulider对象  然后通过LayoutInflater获取相应的View 对象 (其实就是Layout 布局文件) 其实也是可以的,只是我们不能再次进行一些其他的操作了,比如说我们即使设置了TableLayout但是我们不能够在上面完成任何操作,因为并不允许使用 自定义方法设置相关功能,

  • java版数独游戏界面实现(二)

    本文实例为大家分享了java版数独游戏界面实现的具体代码,供大家参考,具体内容如下 实现效果图: 这里写图片描述 主函数用于启动程序: package hlc.shudu.app; import hlc.shudu.src.ShuduHelper; import hlc.shudu.ui.ShuduMainFrame; public class AppStart { public static void main(String[] args) { ShuduMainFrame mainFrame

  • java版数独游戏核心算法(一)

    之前学习javascript时用javascript写过一个数独游戏,最近看了一点java的内容,于是就心血来潮想搞一个java版的数独游戏. 现在将全部代码分享出来和大家学习交流,当然代码中有着各种各样的问题和不足之处,望各位朋友批评指点. 以下是生成数独地图的核心算法,算法不是很好,也是之前参考过网上的一些思想: package hlc.shudu.src; /* * 数独的帮助类,里面提供数据所需的所有算法 */ public class ShuduHelper { //数独地图数组 pr

  • 简单实现java数独游戏

    本文实例为大家分享了java数独游戏的具体代码,供大家参考,具体内容如下 打算把javaFx需要的组件装好以后直接用javaFx的,但似乎eclipse的版本不对,安装了也不能用... 数独代码是在之前寒假受命写的,学了一个月java的成果,现在看来有些不足但毕竟是第一个程序,就直接放上来,数独终盘的实现直接用了暴力,时间复杂度有点高,懒得改了直接放代码 终盘实现: import java.util.Random; public class SudokuPuzzleGenerator { pri

  • Android游戏之数独游戏开发

    数独游戏是一种源自18世纪末的瑞士的游戏,后在美国发展.并在日本得以发扬光大的数学智力拼图游戏.在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列.每一行的数字都不重复. 数独的玩法逻辑简单,数字排列方式千变万化,是锻炼脑筋的好方法. 本文实现简单的数独游戏,通过mars的视频教程完成编程 1.自定义View: package com.example.administrator.shudugame; /** * Created by Administrator on 2016/9/1

  • 基于Android实现数独游戏

    本文实例为大家分享了Android实现数独游戏的具体代码,供大家参考,具体内容如下 1.在src中有4个Java类: 其中代码分别是: Game.java: package com.example.test1; import android.R.integer; public class Game { public final String str="360000000004230800000004200" +"070460003820000014500013020"

  • Android应用实践之数独游戏开发

    数独游戏是一种源自18世纪末的瑞士的游戏,后在美国发展.并在日本得以发扬光大的数学智力拼图游戏.拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格.在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列.每一行的数字都不重复. 数独的玩法逻辑简单,数字排列方式千变万化.不少教育者认为数独是锻炼脑筋的好方法,上外语阅读课的时候外教老师就很喜欢带我们玩这个,乐此不疲,老外的教学方式还是很受欢迎的.但是每次玩这个游戏的时候都要发一张数独游戏卡,嫌麻烦,就想着写一个demo放自

  • Android游戏开发实践之人物移动地图的平滑滚动处理

    如图所示为程序效果动画图 地图滚动的原理 在本人之前博客的文章中介绍过人物在屏幕中的移动方式,因为之前拼的游戏地图是完全填充整个手机屏幕的,所以无需处理地图的平滑滚动.这篇文章我着重的向 大家介绍一下控制人物移动后地图滚动的处理方式.举个例子 如上图所示 比如人物向右移动,如果地图贴在屏幕左边边界 将先移动人物在地图的坐标,当人物在屏幕中超过三分之二后 则将地图向人物行走的反方向移动给玩家一种人物还在向右移动的假象,其实这时候人物只是播放向右行走的动画 在屏幕中的坐标不变 ,当地图向人物行走反方

  • Android数字华容道小游戏开发

    目的 上周新一期的最强大脑出来了,虽然上季被称为最强黑幕,不过呢.我决定还是看看= =.它里面第一关是叫做数字华容道.说白了,就是和拼图差不多.一开始我准备下一个玩玩的.结果没搜到.所以决定写了一个.最后效果差不多是这样: 思路以及实现 首先,我们应该考虑如何去实现这个效果.细想一下,其实和之前的2048有点像,但是又不是完全一直.于是,便又折腾了一波.这次布局和内容项参考之前2048的,下面放上代码: 自定义一个frame layout,我们先绘制里面的数字: private void ini

  • Android游戏开发:实现手势操作切换图片的实例

    对于Android 的手势不光在软件中会经常用到,比如浏览器中的翻页,滚动页面等等;当然其实在我们开发Android游戏的时候加上了Android手势操作更会让游戏增加一个亮点,比如一般的CAG.PUZ等类型的游戏选择关卡.简单背景的移动等,都可以使用手势来操作即可,类似前段时间很火的<愤怒的小鸟>,小鸟这个游戏确实不错,我所看到的唯一的亮点是这款游戏的创意!说实话,现在的游戏没有做不出来的只有想不出来的好创意.回到话题来,那么下面我们来了解下什么是Android 手势!        手势识

  • Android 游戏开发入门简单示例

    在Android系统上开发游戏是Android开发学习者所向往的,有成就感也有乐趣,还能取得经济上的报酬.那怎样开发Android游戏呢?下面介绍一个简单的入门实例.        一.创建新工程 首先,我们在Eclipse中新建一个名为Movement的工程,并且选择合适的Android SDK,在这里,我们选用的API是比较低的1.5版本,这样可以让其适应性更强.接下来,我们新建两个类,一个是UpdateThread类,一个是SurfaceView类,它们在项目中分别是负责处理线程和画面的两

  • Android游戏开发学习②焰火绽放效果实现方法

    本文实例讲述了Android游戏开发学习②焰火绽放效果实现方法.分享给大家供大家参考.具体如下: 本节介绍在游戏开发中常用到的数学物理应用--粒子系统.粒子系统与上一节的小球有类似的地方,都是通过数学方法和物理公式模拟客观世界中的物体的运动轨迹.不同的是小球更强调个体运动,而焰火粒子等粒子系统更注重整体感觉. 一.焰火粒子效果 1.粒子对象类Particle类和粒子集合类ParticleSet类 每个粒子都为一个Particle类的对象,程序中产生的所有Particle对象都由一个Particl

随机推荐