用compose写个斗兽棋(二)

在上一章节的斗兽棋文章发出之后,有老哥在评论区指出,怎么和他们小时候玩的不一样。

这可问到我了,原来你的童年我的童年真的不一样,于是我去百度了一下, 按照百度写的斗兽棋玩法和地图,对我的斗兽棋小APP进行升级,进化为PLUS版本。

规则

UI

在Codding了几天之后,完成了这个Plus版本的斗兽棋,虽然看上去复杂了一些,但是逻辑上比上一期的简易版本更简单了。UI主要分为两部分,地图,棋子

地图

也就是一个 9X7 的格子,获取到屏幕宽度之后,除7,就是每个格子的尺寸了,按照规则图片,在对应的地方画上 水,兽巢,现金,即可。

kotlin 复制代码
    val paint = Paint()
    // 河流
    paint.color = Color(0xFF03A9F4)
    paint.style = PaintingStyle.Fill
    val leftRiver = Rect(CellSize.px, CellSize.px * 3, CellSize.px * 3, CellSize.px * 6)
    it.drawRect(leftRiver, paint)
    val rightRiver =
        Rect(CellSize.px * 4, CellSize.px * 3, CellSize.px * 6, CellSize.px * 6)
    it.drawRect(rightRiver, paint)

    paint.color = Color.Blue
    paint.style = PaintingStyle.Stroke
    val rect = Rect(0f, 0f, CellSize.px * 7, CellSize.px * 9)
    it.drawRect(rect, paint)

    // 画竖线
    for (row in 1..6) {
        it.drawLine(
            Offset(CellSize.px * row, 0f),
            Offset(CellSize.px * row, CellSize.px * 9),
            paint
        )
    }
    // 横线
    for (column in 1..8) {
        it.drawLine(
            Offset(0f, CellSize.px * column),
            Offset(CellSize.px * 7, CellSize.px * column),
            paint
        )
    }

    val trapImg = ImageBitmap.imageResource(
        res = MyApplication.instance.resources,
        id = R.drawable.trap
    )


    // 画陷阱和兽巢
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 2,
            (CellSize.px - trapImg.height) / 2f
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - trapImg.height) / 2f + CellSize.px
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 4,
            (CellSize.px - trapImg.height) / 2f
        ),
        paint
    )


    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 2,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 8
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 7
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 4,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 8
        ),
        paint
    )

    val homeImg = ImageBitmap.imageResource(
        res = MyApplication.instance.resources,
        id = R.drawable.home
    )

    it.drawImage(
        homeImg,
        topLeftOffset = Offset(
            (CellSize.px - homeImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - homeImg.height) / 2f
        ),
        paint
    )

    it.drawImage(
        homeImg,
        topLeftOffset = Offset(
            (CellSize.px - homeImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - homeImg.height) / 2f +  CellSize.px * 8
        ),
        paint
    )

棋子

创建一个二维数组,按照规则的位置,八种动物从小到大,赋值1到8,空地的level为-1,给每个棋子放好位置。

kotlin 复制代码
private fun initCell(): SnapshotStateList<SnapshotStateList<CellBean>> {
    val result = SnapshotStateList<SnapshotStateList<CellBean>>()
    for (i in 0 until 9) {
        val list = SnapshotStateList<CellBean>()
        for (j in 0 until 7) {
            val cellBean = CellBean()
            list.add(cellBean)
        }
        result.add(list)
    }
    result[0][0].isRed = true
    result[0][0].level = 7
    result[0][6].isRed = true
    result[0][6].level = 6
    result[1][1].isRed = true
    result[1][1].level = 3
    result[1][5].isRed = true
    result[1][5].level = 2
    result[2][0].isRed = true
    result[2][0].level = 1
    result[2][2].isRed = true
    result[2][2].level = 5
    result[2][4].isRed = true
    result[2][4].level = 4
    result[2][6].isRed = true
    result[2][6].level = 8
    result[6][0].isRed = false
    result[6][0].level = 8
    result[6][2].isRed = false
    result[6][2].level = 4
    result[6][4].isRed = false
    result[6][4].level = 5
    result[6][6].isRed = false
    result[6][6].level = 1
    result[7][1].isRed = false
    result[7][1].level = 2
    result[7][5].isRed = false
    result[7][5].level = 3
    result[8][0].isRed = false
    result[8][0].level = 6
    result[8][6].isRed = false
    result[8][6].level = 7
    return result
}

逻辑

逻辑方面,其实很简单,如果按照上一篇文章的思路,就是选中棋子 ,还是操作棋子 。但是如果按照程序来看,我把它按照 点击空白点击棋子 两种方式来写了,这样看上去更为简洁。

点击空白

点击空白的时候,我们要判断三种情况,

1、无效点击

如果当前无被选择棋子,当前的点击就是无效点击

kotlin 复制代码
    val lastIndex = state.value.selectedIndex
    val lastCell = getPiece(state.value.selectedIndex)

    if (lastIndex == -1) {
        //无效点击
        return
    }
2、无效移动棋子
3、有效移动棋子

2和3就放在一起了

kotlin 复制代码
if ((lastCell.isRed && index in RedHome) ||
    (!lastCell.isRed && index in BlueHome)
) {
    // 自家不能进自己屋
    return
}

if (lastCell.level == 6 || lastCell.level == 7) {
    //狮子老虎可以跨河,特殊处理,上下左右
    val access = getAccessCell(lastIndex)
    if (index in access) {
        //可走
        moveOrEat(lastIndex, index)
    }
} else {
    if (lastIndex % 7 == index % 7 + 1 || lastIndex % 7 == index % 7 - 1  //左右走
        || lastIndex / 7 == index / 7 + 1 || lastIndex / 7 == index / 7 - 1 //往上下走
    ) {
        if (index in River) {
            // 是老鼠,可以在河里跑,其它动物均为无效操作
            if (lastCell.level == 1) {
                moveOrEat(lastIndex, index)
            }
        } else {
            // 不是河,直接走
            moveOrEat(lastIndex, index)
        }
    }
}

首先判断是不是往自己家里面走,自己的棋子不准进自己的兽巢

然后是要对 老虎和狮子 特殊处理,老虎和狮子可以跨河,所以要判断是不是在让他们跨河,以及河流中间是不是有老鼠阻断。我是直接根据老虎或狮子的坐标,获取到它可以走的位置的集合,然后判断当前点击的位置,是不是属于它可以走的位置。

kotlin 复制代码
private fun getAccessCell(index: Int): IntArray {
    val result = intArrayOf(-1, -1, -1, -1)
    // 左边能不能到达
    if ((index - 1) % 7 != 6) {
        // 没有换行
        if (index - 1 in River) {
            // 有河流,判断能不能跨河
            var target = index - 1
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target--
            }
            if (!haveMouse) {
                result[0] = target
            }
        } else {
            // 没有河流,可到达
            result[0] = index - 1
        }
    }

    //右边能不能到达
    if ((index + 1) % 7 != 0) {
        // 没有换行
        if (index + 1 in River) {
            // 有河流,判断能不能跨河
            var target = index + 1
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target++
            }
            if (!haveMouse) {
                result[1] = target
            }
        } else {
            // 没有河流,可到达
            result[1] = index + 1
        }
    }

    //下边
    if (index + 7 <= 62) {
        // 没有越界
        if (index + 7 in River) {
            // 有河流,判断能不能跨河
            var target = index + 7
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target += 7
            }
            if (!haveMouse) {
                result[2] = target
            }
        } else {
            // 没有河流,可到达
            result[2] = index + 7
        }
    }

    //上边
    if (index - 7 >= 0) {
        // 没有越界
        if (index - 7 in River) {
            // 有河流,判断能不能跨河
            var target = index - 7
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target -= 7
            }
            if (!haveMouse) {
                result[3] = target
            }
        } else {
            // 没有河流,可到达
            result[3] = index - 7
        }
    }
    return result
}

除了狮子和老虎,其它棋子就判断当前点击的区域是不是上下左右了,如果是的,判断是不是河流,只有老鼠可以进入河流,其它棋子均不行。

点击棋子

同样是三种情况

1、选中或者切换选中棋子

如果目前没有选中,且点击的是自己的棋子,即可选中。或者目前已经有选中了,点击了其它自己的棋子,就是切换选中

kotlin 复制代码
val lastIndex = state.value.selectedIndex
val lastCell = getPiece(state.value.selectedIndex)
val targetCell = getPiece(index)
if ((lastIndex == -1 && state.value.isRedTurn == targetCell.isRed) || state.value.isRedTurn == targetCell.isRed) {
    //选中或者切换选中
    state.value = state.value.copy(selectedIndex = index)
    return
}
2、吃别人的棋子
3、无效操作

2.3两种操作其实就和走空地差不多了,只是走的时候要判断一下等级

kotlin 复制代码
if (lastCell.level == 6 || lastCell.level == 7) {
    // 豹子老虎可以跨河吃,特殊处理
    val access = getAccessCell(lastIndex)
    if (index in access) {
        //可走
        if ((index in BlueTrap)
            || (index in RedTrap)
        ) {
            // 敌方棋子在我方陷阱中,可以吃掉,无视等级,直接吃掉
            moveOrEat(lastIndex, index)
        } else {
            if (lastCell.level >= targetCell.level) {
                // 可吃
                moveOrEat(lastIndex, index)
            }
        }
    }
} else {
    if (lastIndex % 7 == index % 7 + 1 || lastIndex % 7 == index % 7 - 1  //左右走
        || lastIndex / 7 == index / 7 + 1 || lastIndex / 7 == index / 7 - 1 //往上下走
    ) {
        if ((index in BlueTrap)
            || (index in RedTrap)
        ) {
            // 敌方棋子在我方陷阱中,可以吃掉,无视等级,直接吃掉
            moveOrEat(lastIndex, index)
        } else {
            if (lastCell.level >= targetCell.level || (lastCell.level == 1 && targetCell.level == 8)) {
                // 可吃
                moveOrEat(lastIndex, index)
            }
        }
    }
}

判断结束

在每一步 eatOrMove之后,就要判断游戏是不是结束了

kotlin 复制代码
private fun moveOrEat(lastIndex: Int, targetIndex: Int) {
    getPiece(targetIndex).level = getPiece(lastIndex).level
    getPiece(targetIndex).isRed = getPiece(lastIndex).isRed
    getPiece(lastIndex).level = -1
    state.value = state.value.copy(selectedIndex = -1, isRedTurn = !state.value.isRedTurn)
    checkFinish()
}

// 判断结束
private fun checkFinish() {

    if (getPiece(RedHome[0]).level != -1) {
        // 结束,蓝方赢了
        onFinished?.invoke(false)
        return
    }
    if (getPiece(BlueHome[0]).level != -1) {
        // 结束,红方胜利
        onFinished?.invoke(true)
        return
    }

    var isRedWin = true
    var isBlueWin = true

    for (index in 0 until 63) {
        val piece = getPiece(index)
        if (piece.level != -1) {
            if (piece.isRed) {
                //红的还没死完
                isRedWin = false
            } else {
                isBlueWin = false
            }
        }
        if (!isRedWin && !isBlueWin) {
            // 对局还没结束
            return
        }
    }
    if (isRedWin) {
        onFinished?.invoke(true)
    }else{
        onFinished?.invoke(false)
    }
}

这样,一个Plus版本的斗兽棋就完成了

代码地址:github.com/yuuuuke/Bea...

相关推荐
fanqi9873 分钟前
Android模拟器ADB异常断开一个容易忽视原因的记录
android·adb·android studio
冬奇Lab6 分钟前
稳定性性能系列之五——Native Crash深度分析:工具实战
android·性能优化·debug
峥嵘life10 分钟前
深耕Android技术——2025年CSDN博客之星总评选深度总结
android
无言Echo10 分钟前
App 深色模式切换流程简述(api32)及相关bug
android
GoldenPlayer11 分钟前
Android网络请求报错(直接请求http)
android
花卷HJ13 分钟前
Android 多媒体文件工具类封装(MediaFileUtils)
android·java
csj5014 分钟前
安卓基础之《(11)—数据存储(1)共享参数SharedPreferences》
android
走在路上的菜鸟14 分钟前
Android学Dart学习笔记第二十七节 异步编程
android·笔记·学习·flutter
哆啦安全15 分钟前
Android智能调试分析工具V7.5
android
モンキー・D・小菜鸡儿16 分钟前
Android 自定义粒子连线动画视图实现:打造炫酷背景效果
android·java