用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...

相关推荐
爱勇宝1 天前
鸿蒙生态的下半场:开发者不只要能开发,还要能赚钱
android·前端·程序员
Yeyu1 天前
刷新一帧的艺术:invalidate / postInvalidate / postInvalidateOnAnimation全解析
android
潘潘潘1 天前
Android OTA 升级原理和流程介绍
android
plainGeekDev2 天前
null 判断 → Kotlin 可空类型
android·java·kotlin
plainGeekDev2 天前
getter/setter → Kotlin 属性
android·java·kotlin
YXL1111YXL2 天前
Handler 消息回收与协程异步执行的时序陷阱
android
恋猫de小郭2 天前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
三少爷的鞋2 天前
Android 协程并发控制:别动线程池,控制好并发语义就够了
android
weiggle2 天前
第七篇:状态提升与单向数据流——架构设计的核心
android
xingpanvip2 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua