用Compose写个斗兽棋

前段时间在掘金上面看到一个老哥分享了一篇关于用前端技术写个斗兽棋的文章,就想到小时候学校小卖部出售的贴纸斗兽棋。

这个样子的

于是想能不能写一个安卓的斗兽棋APP

说干就干,在经过一段时间的Coding之后,完成了一个简易版本的斗兽棋

分为红蓝两方,每一方分别拥有 象,狮,虎,豹,犬,狼,狗,猫,鼠 八张牌,在一个 4 X 4 的棋盘中覆盖,象,狮,虎,豹,犬,狼,狗,猫,鼠 从大到小,大的可以吃掉小的,但是鼠鼠可以吃掉大象,一方的棋子被吃光了,游戏就结束,对方胜利

总体还是比较简单的

代码逻辑

首先是UI状态

1、4X4的二位数组,用来存放每个格子的状态
2、当前选中的棋子
3、当前是哪一方的回合
kotlin 复制代码
data class UiState(
    val Pieces: SnapshotStateList<SnapshotStateList<CellBean>> = mutableStateListOf(),
    val selectedIndex: Int = -1,
    val isRedTurn: Boolean = false,
)

格子对象

kotlin 复制代码
data class CellBean(
    var isCover: Boolean = true, // 是否是覆盖状态
    var isBlock: Boolean = false,   // 是否是空位
    var isRed:Boolean = false, // 红方还是蓝方
    var level:Int = 0   // 象,狮,虎,豹,犬,狼,狗,猫,鼠,从8 - 1
)

接着就是在界面上把每个格子画出来

scss 复制代码
setContent {
    Column(
        Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        Text(
            text = if (GameController.state.value.isRedTurn) "红方回合" else "蓝方回合",
            modifier = Modifier.padding(bottom = 40.dp),
            style = TextStyle(
                fontSize = 20.sp,
                color = if (GameController.state.value.isRedTurn) Color.Red else Color.Blue
            )
        )

        Box(
            modifier = Modifier
                .width(240.dp)
                .height(240.dp)
        ) {
            BoardView()
            Row(modifier = Modifier.fillMaxSize()) {
                for (i in 0 until 4) {
                    Column(
                        Modifier
                            .fillMaxHeight()
                            .width(60.dp)
                    ) {
                        for (j in 0 until 4) {
                            CellView(
                                cellBean = GameController.state.value.Pieces[i][j],
                                i * 4 + j
                            )
                        }
                    }
                }
            }
        }
    }
}

BorderView()是绘画了一个4X4的空格子,然后每个格子里面画上一个Cell

绘画格子

CellView就是每个格子,共有五种状态

空格子

蓝方棋子

红方棋子

未翻起棋子

选中态棋子

根据CellBean对象的状态进行绘画即可

逻辑处理

逻辑处理其实只有三个
1、初始化,打乱棋子,然后放到数组里面
2、处理棋盘的点击事件
3、判断本盘棋是否结束

棋子顺序初始化

先创建一个长度为16的数组,然后通过洗牌算法把数组乱序,最后依次填入到4X4的数组中去

ini 复制代码
private fun initCell(): SnapshotStateList<SnapshotStateList<CellBean>> {
    val array = IntArray(16) {
        return@IntArray it
    }
    // 乱序
    for (index in 15 downTo  1) {
        val random = (Math.random() * index).toInt()
        val temp = array[index]
        array[index] = array[random]
        array[random] = temp
    }
    val pieces = ArrayList<SnapshotStateList<CellBean>>()
    for (i in 0..3) {
        val list: ArrayList<CellBean> = ArrayList()
        for (j in 0..3) {
            val cell = CellBean()
            val index = i * 4 + j
            if (array[index] > 7) {
                // 红方
                cell.level = array[index] - 7
                cell.isRed = true
            } else {
                cell.level = array[index] + 1
                cell.isRed = false
            }
            list.add(cell)
        }
        pieces.add(list.toMutableStateList())
    }
    return pieces.toMutableStateList()
}

处理点击事件

点击事件的处理比较繁琐。

arduino 复制代码
 首先判断当前有没有被选中的棋子,
 如果为true,则情况为
     1、吃掉对方棋子
     2、移动到空位
     3、选中其它棋子
     4、取消选中态
     5、无效操作(例如小的吃大的,往还未翻开的位置走)
 如果为false,则情况为
     1、点击的空白区域,无效点击
     2、点击的未翻开棋子,翻开
     3、点击的己方棋子,选中
     4、点击对方棋子,无效操作

就不贴具体的代码了,其实后来想想,应该按照此操作是否导致此回合结束,来区分会比较好,会在判断是否结束的时候更加的清晰。

判断是否结束

在翻开某张棋子,或者移动了某张棋子之后,轮到对方回合,并判断游戏是否结束。

kotlin 复制代码
/**
 *     判断是否结束了
 */
private fun checkFinish() {
    val pieces = state.value.Pieces
    var redLive = false
    var blueLive = false
    for (cellList in pieces) {
        for (cell in cellList) {
            if (cell.isRed) {
                if (!redLive)
                    redLive = !cell.isBlock
            } else {
                if (!blueLive)
                    blueLive = !cell.isBlock
            }
        }
        if (redLive && blueLive) {
            // 双方此刻都还存活,切换到对方回合
            state.value =
                state.value.copy(selectedIndex = -1, isRedTurn = !state.value.isRedTurn)
            return
        }
    }
    // 结束了,某一方已经嗝屁了
    onFinish(redLive)
}

其实在进行翻开操作的时候,并不用判断是否结束了,但是把切换回合也写在checkFinish里面了,所以多余的执行了一下,后面再优化一下吧。

结束

至此一个斗兽棋小游戏就已经写好了。

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

相关推荐
xvch1 小时前
Kotlin 2.1.0 入门教程(二十五)类型擦除
android·kotlin
simplepeng10 小时前
我的天,我真是和androidx的字体加载杠上了
android
小猫猫猫◍˃ᵕ˂◍11 小时前
备忘录模式:快速恢复原始数据
android·java·备忘录模式
CYRUS_STUDIO13 小时前
使用 AndroidNativeEmu 调用 JNI 函数
android·逆向·汇编语言
梦否13 小时前
【Android】类加载器&热修复-随记
android
徒步青云14 小时前
Java内存模型
android
今阳14 小时前
鸿蒙开发笔记-6-装饰器之@Require装饰器,@Reusable装饰器
android·app·harmonyos
-优势在我19 小时前
Android TabLayout 实现随意控制item之间的间距
android·java·ui
hedalei19 小时前
android13修改系统Launcher不跟随重力感应旋转
android·launcher
Indoraptor20 小时前
Android Fence 同步框架
android