Android Studio实现数独小游戏,休闲益智

一、项目概述

数独是一种逻辑解谜游戏,它规则稍复杂,解题过程富有挑战性。本次安卓数独小游戏,主页面有继续游戏、新游戏、关于和退出四个功能,下拉菜单有设置选项。新游戏可以选择简单、中等和困难3个模式,进入游戏后可以随时退出,然后点继续游戏就能回到上一次的游戏状态。关于是对数独游戏的规则介绍,在设置中可以开启或者关闭背景音乐,开启或关闭游戏提示。游戏界面,每个3x3的方块区域都被实线给分隔开,方便玩家观察填入数字。

涉及知识点:AlertDialog、KeyEvent、MediaPlayer、Canvas、Paint、Parcelable、Fragment、Menu、PreferenceManager、Bundle

二、开发环境

在这里插入图片描述

三、详细设计

3.1 界面设计

1、关于界面,非常简单,描述游戏规则只需要TextView即可。

在这里插入图片描述

2、键盘界面,一共3行,每行3列。用到3个TableRow控件,每个TableRow包含3个Button,在输入数字时候会作为对话框弹出。核心代码是button的style。

// 设置主界面的button的样式
 <style name="number_button">
     <item name="android:layout_width">0dp</item>
     <item name="android:layout_weight">1.0</item>
     <item name="android:layout_height">40dp</item>
     <item name="android:layout_margin">3dp</item>
     <item name="android:textSize">30sp</item>
     <item name="android:background">@drawable/select_number_click</item>
     <item name="android:textColor">#fff</item>
 </style>

在这里插入图片描述

3、主界面,其实设计也不难,主要是四个垂直排列的Button,主要内容还是在background中,solid的颜色为渐变色,stroke的宽度为1dp,color是灰色,radius是50dp,弧形半径非常明显,padding为2dp,有内边距视觉效果更好,最后根据state_pressed变色。

在这里插入图片描述

3.2 逻辑设计

1、背景音乐,直接定义一个类,定义play方法,创建MediaPlayer对象,播放传参resource,setLooping设为true就是循环播放。代码如下:

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) {
        if(mp != null){
            mp.stop();
            mp.release();
            mp = null;
        }
    }
}

在应用启动时开始播放音乐,退出时停止播放。

 @Override
 protected void onResume() {
     super.onResume();
     // 程序开始时,调用music activity开始播放音乐
     Music.play(this, R.raw.nothing_to_lose);
 }
 @Override
 protected void onPause() {
     super.onPause();
     // 程序暂停或退出时,停止播放音乐
     Music.stop(this);
 }

2、小键盘,绑定每个数字按钮,设置监听器,在显示键盘前会进行逻辑判断,只显示可以填入该方块内的数字,其余数字不显示。

// 为小键盘设置监听函数
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) {
                returnResult(t);
            }
        });
    }
    keypad.setOnClickListener(new View.OnClickListener() {
        public void onClick(View arg0) {
            returnResult(0);
        }
    });
}
// 返回结果函数
private void returnResult(int tile) {
    // 绘制用户选择的数字
    puzzleView.setSelectedTile(tile);
    dismiss();
}

在PuzzleView类中,有显示软键盘和手机屏幕点击事件的处理方法,该方法处理三种情况的事件:屏幕被按下时,屏幕被抬起时,屏幕中拖动,根据触摸位置的坐标选中对应区域的按钮。

 @Override
 public boolean onTouchEvent(MotionEvent event) {
     // 参数event为手机屏幕触摸事件封装类的对象,其中封装了该事件的所有信息,
     // 例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。
     // 该方法处理三种情况的事件:屏幕被按下时,屏幕被抬起时,屏幕中拖动
     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;
 }

3、PuzzleView是用来绘制游戏界面,当前活动主窗口大小改变时调用onSizeChanged,获取width和height,然后分成一共9x9个小方块。

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // 计算单元格的宽和高(横向是宽度,纵向是高度)
    width = w / 9f;
    height = h / 9f;
    getRect(selX, selY, selRect);
    Log.d(TAG, "onSizeChanged:width" + width + ",height" + height);
    super.onSizeChanged(w, h, oldw, oldh);
}

创建画笔对象,绘制数字,设置字体颜色,设置字体大小和对齐方式,定义了字体规格对象,该对象封装了有关在特定屏幕上呈现特定字体的信息。再创建选择的对象的画笔,按下变色的颜色,根据每个单元格可填的数目给出不同颜色的提示。

   // draw numbers 绘制数字
   Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);// 生成画数字的画笔
   foreground.setColor(getResources().getColor(R.color.puzzle_foreground));// 设置字体颜色
   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;// 横竖都居中
   // Ascent: 字符顶部到baseLine的距离。
   // Descent: 字符底部到baseLine的距离。
   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);
               }
           }
       }
   }

4、Game是游戏类,主要实现难度的选择,数字的绘制规则,一共三种游戏模式,每一种都是定义好的字符串,0表示当前没有填充数字,0之外表示有,然后遍历字符串,在PuzzleView中调用画笔绘制9x9的网格,并在每个方块中绘制数字,这样数独的界面就绘制好了。然后选中某一个方块,就会调用小键盘进行输入。

   // 获取难度 difficulty easy = 0  默认为简单
   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);

5、游戏状态保存依靠Bundle,实例状态存储在bundle中,保存当前游戏状态,parcelable是序列化的接口,方便处理窗口保存事件。

    @Override
    protected Parcelable onSaveInstanceState() {// 
        //用户打包需要传输的数据,然后在Binder中传输,用于跨进程传输数据
        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);// 保存当前的状态,用bundle传输
        return bundle;
    }

恢复已经保存的信息,只需要从Bundle里面取出来保存的坐标即可。

    @Override
    protected void onRestoreInstanceState(Parcelable state) {// 处理窗口还原事件
        Log.d(TAG, "onRestoreInstanceState");
        Bundle bundle = (Bundle) state;
        select(bundle.getInt(SELX), bundle.getInt(SELY));// 通过bundle对象获取 保存的坐标
        super.onRestoreInstanceState(bundle.getParcelable(VIEW_STATE));// 通过bundle对象获取存放的状态信息
        return;
    }

四、运行演示

1、启动应用,进入主界面,有继续、新游戏、关于和退出四大选项,标题栏显示“数独游戏”,右侧是菜单项。

在这里插入图片描述

2、点击新游戏,选择游戏难度,分为简单、中等和困难。

在这里插入图片描述

3、进入游戏后,可以看到有的小方块已经填有数字,剩下的小方块就是你需要填入数字的。玩家选中的方块是浅绿色,比如左上角第一个方块。游戏提示开启时,当某一个方块能填的数字只有1~2时,方块颜色不同于默认颜色,可以看到下图左上角第一块区域数字8的左右各有1个提示方块。

在这里插入图片描述

4、点击任意方块,将弹出键盘,选择填入的数字,当点击下一个方块时,刷新界面。

在这里插入图片描述

5、菜单栏进入设置界面,有背景音乐和提示选项,背景音乐如果开启会循环播放。

在这里插入图片描述

6、我们关闭提示,则方块没有颜色提示,显示的颜色一致,这是困难模式,没有提示太难了。

在这里插入图片描述

7、关于界面介绍了游戏规则。

在这里插入图片描述

五、源码获取

♻️下面两种方式都可以获取源代码
1️⃣ 点击直接下载 Android Studio实现数独小游戏
2️⃣ 关注公众号《 萌新加油站 》,后台回复: 数独

🚀这有你错过的精彩内容
Android Studio实现健身系统
Android Studio实现外卖订餐系统
Android Studio实现考试管理系统
Android Studio实现天气预报系统
Android Studio实现图书馆订座系统

从追求效率的角度看,只有真正有价值的事情,才值得你这样耗用自己宝贵的时间。

  • 28
    点赞
  • 127
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

振华OPPO

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值