关键词:
目标
在做这个游戏之前,我们先定一些小目标列出来,一个一个的解决,这样,一个小游戏就不知不觉的完成啦。我们的目标如下:
- 游戏全屏,将图片拉伸成屏幕大小,并将其切成若干块。
- 将拼图块随机打乱,并保证其能有解。
- 在屏幕上留出一个空白块,当点空白块旁边的块,将这块移动到空白块。
判断是否已经拼好。
实现目标
1.将图片拉伸成屏幕大小,并将其切成若干块。
想拉伸成屏幕大小,首先要知道屏幕的大小,Android获得屏幕大小的代码如下:
DisplayMetrics metrics =new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);//sdk17+
int screenWidth = metrics.widthPixels;//屏幕宽
int screenHeight = metrics.heightPixels;//屏幕高
将图片拉伸到屏幕大小
Bitmap back=Bitmap.createScaledBitmap(bitmap,
MainActivity.getScreenWidth(),
MainActivity.getScreenHeight(),
true);
将图片切成若干块
private final int COL=3;//列,默认3列
private final int ROW=3;//行,默认3行
int tileWidth=back.getWidth()/COL;//每一块的宽
int tileHeight=back.getHeight()/ROW;//每一块的高
Bitmap[] bitmapTiles =new Bitmap[COL*ROW];
int idx=0;
for(int i=0;i<ROW;i++)
for(int j=0;j<COL;j++)
bitmapTiles[idx++]=Bitmap.createBitmap(back,
j*tileWidth,
i*tileHeight,
tileWidth,tileHeight);
2. 将拼图块随机打乱,并保证其能有解。
这个问题应该是这个小游戏的核心了,有些人在做拼图的时候就随便乱摆,最后发现拼不回来,超级尴尬。要想打乱了还能拼回来,我们呢,就想到了模拟人打乱拼图的方法,就是将空白块与旁边的非空白块交换位置,与旁边哪个非空白块交换是随机的,然后将这个过程重复若干次,重复的次数也是随机的,这样一来,保证了图块的随机,又保证了能拼回来。在这里我们用数字0到N-1(N为块的数量)表示每一块,并用二维数组存储他们。
private void createIntegerArray(int row,int col)
array=new int[row][col];
int idx=0;
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
array[i][j]=idx++;
下面是打乱块的算法,最后一块是空白块,让它随机与旁边的某一块进行交换,这个过程中要检查数组边界,不要让它越界。
//四个方向
private int[][] dir=
0,1,//下
1,0,//右
0,-1,//上
-1,0//左
;
/**
* 移动块的位置
* @param srcX 初始x位置
* @param srcY 初始y位置
* @param xOffset x偏移量
* @param yOffset y偏移量
* @return 新的位置,错误返回new Point(-1,-1);
*/
private Point move(int srcX,int srcY,int xOffset,int yOffset)
int x=srcX+xOffset;
int y=srcY+yOffset;
if(x<0||y<0||x>=col||y>=row)
return new Point(-1,-1);
int temp=array[y][x];
array[y][x]=array[srcY][srcX];
array[srcY][srcX]=temp;
return new Point(x,y);
/**
* 得到下一个可以移动的位置
* @param src 初始的点
* @return
*/
private Point getNextPoint(Point src)
Random rd=new Random();
int idx=rd.nextInt(4);//,因为有4个方向,所以产生0~3的随机数
int xOffset=dir[idx][0];
int yOffset=dir[idx][1];
Point newPoint=move(src.getX(),src.getY(),xOffset,yOffset);
if(newPoint.getX()!=-1&&newPoint.getY()!=-1)
return newPoint;//找到了新的点
return getNextPoint(src);//没有找到,继续
/**
* 生成拼图数据
* @param row
* @param col
* @return
*/
public int[][] createRandomBoard(int row,int col)
if(row<2||col<2)
throw new IllegalArgumentException("行和列都不能小于2");
this.row=row;
this.col=col;
createIntegerArray(row,col);//初始化拼图数据
int count=0;
Point tempPoint=new Point(col-1,row-1);//最后一块是空白块
Random rd=new Random();
int num=rd.nextInt(100)+20;//产生20~119的随机数,表示重复的次数
while (count<num)
tempPoint=getNextPoint(tempPoint);//获得下个点,并更新空白块位置
count++;
return array;
3. 在屏幕上留出一个空白块,当点空白块旁边的块,将这块移动到空白块。
留出空白块很简单,由于上面我们将最后一块作为空白块。当我们绘图时,略过它即可。代码实现如下:
@Override
protected void onDraw(Canvas canvas)
canvas.drawColor(Color.GRAY);
for(int i=0;i<ROW;i++)
for (int j = 0; j < COL; j++)
int idx=dataTiles[i][j];
if(idx==ROW*COL-1&&!isSuccess)
continue;
canvas.drawBitmap(bitmapTiles[idx],
j*tileWidth,
i*tileHeight,paint);
移动块也很简单,当点击屏幕时,计算其在拼图数据中对应的索引。当计算到点击非空白块就寻找它旁边有没有空白块,有,则将拼图数据中表示空白块和非空白块的数据交换,并刷新View即可
/**
* 将屏幕上的点转换成,对应拼图块的索引
* @param x
* @param y
* @return
*/
private Point xyToIndex(int x,int y)
int extraX=x%tileWidth>0?1:0;
int extraY=x%tileWidth>0?1:0;
int col=x/tileWidth+extraX;
int row=y/tileHeight+extraY;
return new Point(col-1,row-1);
/**
*点击屏幕时发生
*/
@Override
public boolean onTouchEvent(MotionEvent event)
if(event.getAction()==MotionEvent.ACTION_DOWN)
Point point = xyToIndex((int) event.getX()
, (int) event.getY());
for(int i=0;i<dir.length;i++)
int newX=point.getX()+dir[i][0];
int newY=point.getY()+dir[i][1];
if(newX>=0&&newX<COL&&newY>=0&&newY<ROW)
if(dataTiles[newY][newX]==COL*ROW-1)
int temp=dataTiles[point.getY()][point.getX()];
dataTiles[point.getY()][point.getX()]=dataTiles[newY][newX];
dataTiles[newY][newX]=temp;
invalidate();
return true;
4. 判断是否已经拼好
我们初始化数据时,是从0开始,依次增加作为拼图数据。当拼好的时候,拼图数据也应该是一样的,所以我们比较数组中每一个数据与它的下一个数据,如果每一个数据都小于它的下一个数据,说明数组里面的数据已经从小到大排列好。
/**
* 判断是否拼图成功
* @param arr
* @return
*/
public boolean isSuccess(int[][] arr)
int idx=0;
for(int i=0;i<arr.length;i++)
for(int j=0;j<arr[i].length&&idx<row*col-1;j++)
if(arr[idx/row][idx%col]>arr[(idx+1)/row][(idx+1)%col])
return false;
idx++;
return true;
拼图游戏技巧
拼图技巧觉得也有必要说一下,不然有些人就会说:你的算法有问题,这根本拼不好!我也是超级无奈啊!拼图的技巧是,我们先把上面的第一行拼好,然后再把第二行拼好,这样,一直下去~就能完全拼好了。
总结
这个小游戏简单,可以拿来练手,还可以拿来装(liao)逼(mei),如果不会,何乐而不看呢。这个小游戏也是将视图和数据分开,代码容易移植。
项目地址
https://github.com/luoyesiqiu/PuzzleGame
自己动手做个分页插件(代码片段)
PC分页,完美支持ie8+,2KB下面就是见证奇迹的时刻dome地址https://github.com/cleartime/pageSize/blob/master/dome/index.html配置详情varconfig=el:document.getElementById("page"),//绑定到你的dompageCount:10,//总页数ps:如果后两项填写了则本字段失效,两者只需其 查看详情
与其想当然的overdesign,不如自己动手做个试验(代码片段)
ConmajiaJan.29th,2019早在2012年,我曾经针对C#System.Random不同的初始化方案专门做过一次试验,得出了单次默认初始化即可获得质量很好的随机数的结论。可是这么多年过去,C#从2.0升到了4.7,还能在网上看到很多新手(甚至是老鸟)... 查看详情
逆序数-拼图游戏必备知识(代码片段)
...教程,准备时候遇到一些问题,收集保存分享下来,一来自己用,二来涨点知识,三来有需要的小伙伴刚好也看看。事情起因很简单,比如下面这个拼图(矩阵):123空这样一个2*2矩阵,是标准原始矩阵,但是变一下:312空这样... 查看详情
android拼图游戏开发全纪录5(代码片段)
今天我们终于可以把这个项目给结束掉啦,有了前几天的准备,相信最后一天还是比较轻松的,国际惯例:最后要完成的就是我们的主要功能--拼图界面。布局比较简单,在前几天就已经做好了,现在我们... 查看详情
python小游戏自己动手编写,你能写出几个(分享版)(代码片段)
...重温这些童年小游戏,后面还会分享源码,可以自己学习游戏编写,相信你会超有成就感!Paint涂鸦 在屏幕上绘制线条和形状单击以标记形状的开始,然后再次单击以标记其结束;可以 查看详情
❤️手把手教你用androidstudio做一个超好玩的拼图游戏,0基础android小白也能包你学会,附送超详细注释的源码,建议收藏!❤️(代码片段)
...码一、项目概述之前有不少粉丝私信我说,能不能用Android原生的语言开发一款在手机上运行的游戏呢?说实话,使用java语言直接开发游戏这个需 查看详情
[自己做个游戏服务器二]游戏服务器的基石-netty全解析,有例子,多图解释(代码片段)
目录1、Netty是什么2、Netty的优点3、核心组件3.1Netty的线程模型3.2EventLoopGroup3.3Channel3.4 option()与childOption()3.5 inbound和outbound3.6ByteBuf3.7使用Netty自带的解码器3.8Netty版本4、HelloWorld4.1官方的demo4.2idea建立maven项目4.3服务端代码4.4客 查看详情
[自己做个游戏服务器二]游戏服务器的基石-netty全解析,有例子,多图解释(代码片段)
目录1、Netty是什么2、Netty的优点3、核心组件3.1Netty的线程模型3.2EventLoopGroup3.3Channel3.4 option()与childOption()3.5 inbound和outbound3.6ByteBuf3.7使用Netty自带的解码器3.8Netty版本4、HelloWorld4.1官方的demo4.2idea建立maven项目4.3服务端代码4.4客 查看详情
猿创征文|[自己做个游戏服务器三]将二进制流转换为具体的protobuf消息(代码片段)
...协议使用protobuf传输,具体的内容可以看下上篇文章[自己做个游戏服务器一]搞清楚游戏通信协议之p 查看详情
猿创征文|[自己做个游戏服务器三]将二进制流转换为具体的protobuf消息(代码片段)
...协议使用protobuf传输,具体的内容可以看下上篇文章[自己做个游戏服务器一]搞清楚游戏通信协议之p 查看详情
[自己做个游戏服务器]搞清楚游戏通信协议之protobuf的方方面面,评论继续送书(代码片段)
目录1、protobuf环境搭建2、protobuf语法2.1注释规则2.2数据类型2.3默认值规则2.4protobuf选项2.5protoc生成java文件3、idea生成插件3.1GenProtobuf3.2protobuf4、序列化和反序列化4.1常规序列化和反序列化4.2通用的反序列化5、protostuff6、总结最近... 查看详情
[自己做个游戏服务器]搞清楚游戏通信协议之protobuf的方方面面,评论继续送书(代码片段)
目录1、protobuf环境搭建2、protobuf语法2.1注释规则2.2数据类型2.3默认值规则2.4protobuf选项2.5protoc生成java文件3、idea生成插件3.1GenProtobuf3.2protobuf4、序列化和反序列化4.1常规序列化和反序列化4.2通用的反序列化5、protostuff6、总结最近... 查看详情
自己动手做个微信聊天机器人
长夜慢慢无人聊天,自己动手做个微信聊天机器人陪自己。 智力太低,还是让他调戏别人吧。 看了上面的动画图片是不是有人好奇程序是怎么实现的?解决方案其实很简单:1.通过微信的web接口可以实现自动回复、登录... 查看详情
动手做个智能水族箱(代码片段)
下图是本案例除硬件连线外的3步导学,每个步骤中实现的功能请参考图中的说明。1、简介1.1、背景 伴随着人们生活水平的提高,养鱼已经成为了一种新的时尚,各种桌面鱼缸层出不穷,但是市面上的鱼缸系... 查看详情
动手做个智能水族箱(代码片段)
下图是本案例除硬件连线外的3步导学,每个步骤中实现的功能请参考图中的说明。1、简介1.1、背景 伴随着人们生活水平的提高,养鱼已经成为了一种新的时尚,各种桌面鱼缸层出不穷,但是市面上的鱼缸系... 查看详情
python游戏制作拼图永不过时,这就是我这个年龄该玩的游戏~(代码片段)
前言嗨喽~大家好呀,这里是魔王呐!拼图游戏是广受欢迎的一种智力游戏,它的变化多端,难度不一它分为单面拼图、双面拼图、立体拼图、球形拼图、虚拟拼图今天我就给带来虚拟的单面拼图小游戏准备素材字体文... 查看详情
自己动手,做个cpu
纯手工打造一个CPU这个事儿。在电子专业的同学眼里,很容易。在计算机专业的同学眼里,稍稍有点复杂,有的专业课的实验课可能会带着同学做一个,或者用Logisim这样的仿真软件去模拟实现一个。在非计算机专... 查看详情
上班划水,给男朋友做个数字炸弹游戏(代码片段)
...有男朋友的女程序员,那我也不能落下,赶紧给自己的男朋友安排。本游戏纯手工unity+C#制作,素材来源于情侣间的生活照。游戏主界面既然是给男朋友做的,那男朋友的排面肯定不能小 查看详情