“我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛”
开局一张图,第一关
- 只可点击挨着缺失部分的图片,点击即为和缺失部分互换。
过关显示缺失图片
- 我用了264秒,你呐
零、 体验方式
安卓手机
可扫码下载体验
一、创意灵感
- 专属
90后
的回忆,当年大家一定都玩过一种拼图游戏
- 整个图片是
缺少一块
的,用于移动
其余打乱的图片
,最终所有图片移动到对应的位置时
,缺少
的图片将显示
,并通关成功!
- 整个图片是
- 为了增加趣味性,选择使用
船长
来作为拼图的图片
- 由于
船长头像分割到4X4
的时候会出现多个黑色方块
,所以图片设计成了这个样子,此处感谢南方者提供的图片
。
游戏规则
只可点击
空白区域周边的图片
,点击的图片
即为想移动到空白位置的图片
- 基础功能还是将打乱的图恢复到
原始位置
。 - 增加了关卡,
第一关是3x3
,第二关是4x4
,第三关是5x5
,第四关是6x6
,第五关是8x8
。 - 五关分别对应
新手、入门、高手、变态、超神
通过五关
才算拯救船长成功!
(为降低难度,目前开放前两关,通过即拯救船长)
二、思路分析
- 拼图的核心是一个
nxn
的矩阵,点击矩阵中的图片- 判断
点击的图片
在第几行我们/n(除法)
- 判断
点击的图片
在第几列我们%n(取余)
- 判断
空白图片
所在的行列同上
两两相减
,进行判断- 如果在
同一行,列数相减,绝对值为1,可移动
- 如果在
同一列,行数相减,绝对值为1,可移动
- 其他
情况不符合条件不进行移动
- 判断
- 界面设计(安卓屏幕多尺寸适配)——
ConstraintLayout
符合 - 开始撸码
三、AC 代码:
- 首先是布局
- 还没有用过ConstraintLayout的建议补一下我之前的这篇文章ConstraintLayout+ViewPager2打造《摇一摇新年幸运签》App这里就不多介绍了
- 讲一下需要注意的点,约束布局
至少需要两个方向添加约束
,若你想均分
就和我一样左右都添加约束
即可 宽高比
可通过layout_constraintDimensionRatio
属性设置
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/design_default_color_error"
android:padding="20dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="10dp"
android:text="时间 : 0"
android:textColor="#FF0000"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/x00"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_01"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/x01"
app:layout_constraintTop_toBottomOf="@id/tv_time" />
<ImageView
android:id="@+id/x01"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_02"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x00"
app:layout_constraintRight_toLeftOf="@id/x02"
app:layout_constraintTop_toBottomOf="@id/tv_time" />
<ImageView
android:id="@+id/x02"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_03"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x01"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_time" />
<ImageView
android:id="@+id/x10"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_04"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/x01"
app:layout_constraintTop_toBottomOf="@id/x00" />
<ImageView
android:id="@+id/x11"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_05"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x00"
app:layout_constraintRight_toLeftOf="@id/x02"
app:layout_constraintTop_toBottomOf="@id/x01" />
<ImageView
android:id="@+id/x12"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_06"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x01"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/x02" />
<ImageView
android:id="@+id/x20"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_07"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/x01"
app:layout_constraintTop_toBottomOf="@id/x10" />
<ImageView
android:id="@+id/x21"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_08"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x00"
app:layout_constraintRight_toLeftOf="@id/x02"
app:layout_constraintTop_toBottomOf="@id/x11" />
<ImageView
android:id="@+id/x22"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@mipmap/xy9_09"
android:visibility="invisible"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/x01"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/x12" />
<Button
android:id="@+id/btn_restart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="restart"
android:layout_gravity="center"
android:text="重新开始"
android:backgroundTint="#ff0000"
android:background="@null"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@id/x20"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 拼图
移动判断核心代码
//判断选中的图片在第几行
val sitex = site / imageX
//判断选中的图片在第几列
val sitey = site % imageY
//获取空白区域的行
val blankx = blankSwap / imageX
//获取空白区域的列
val blanky = blankSwap % imageY
//相减取绝对值
val x = abs(sitex - blankx)
val y = abs(sitey - blanky)
//1.在同一行,列数相减,绝对值为1,可移动 2.在同一列,行数相减,绝对值为1,可以移动
if (x == 0 && y == 1 || y == 0 && x == 1) {
//通过id,查找到这个可以移动的按钮
val clickButton: ImageView = findViewById(imageButtonId)
//点击的位置变成空白
clickButton.visibility = View.INVISIBLE
//查找到空白区域的按钮
val blankButton: ImageView = findViewById(blankImgId)
//将空白区域的按钮设置图片
blankButton.setImageResource(image[imageIndex[site]])
//移动之前是不可见的,移动之后,将控件设置为可见
blankButton.visibility = View.VISIBLE
//将改变角标的过程记录到存储图片位置数组当中
swap(site, blankSwap)
//新的空白区域位置更新等于传入的点击按钮的位置
blankSwap = site
blankImgId = imageButtonId
//定义标志位
var loop = true
//循环判断位置是否匹配,不匹配则将标志位置为false
for (i in imageIndex.indices) {
if (imageIndex[i] != i) {
loop = false
break
}
}
if (loop) {
//拼图成功了
//停止计时
handler.removeMessages(1)
//拼图成功后,禁止玩家继续移动按钮
xy00.isClickable = false
xy01.isClickable = false
xy02.isClickable = false
xy10.isClickable = false
xy11.isClickable = false
xy12.isClickable = false
xy20.isClickable = false
xy21.isClickable = false
xy22.isClickable = false
xy22.setImageResource(image[8])
xy22.visibility = View.VISIBLE
//弹出提示用户成功的对话框
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setMessage("恭喜,拯救船长成功!您用的时间为" + time + "秒")
.setPositiveButton("确认", null)
val dialog: AlertDialog = builder.create()
dialog.show()
四、总结:
- 好了,代码撸完,我们
总结一下
:-
首先我们做了
屏幕适配
-
除法和取余
的运用 -
最后不要忘记判断是否成功
-