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

相关推荐
积跬步DEV6 小时前
Android 获取签名 keystore 的 SHA1和MD5值
android
陈旭金-小金子9 小时前
发现 Kotlin MultiPlatform 的一点小变化
android·开发语言·kotlin
二流小码农11 小时前
鸿蒙开发:DevEcoStudio中的代码提取
android·ios·harmonyos
江湖有缘11 小时前
使用obsutil工具在OBS上完成基本的数据存取【玩转华为云】
android·java·华为云
移动开发者1号12 小时前
Android 多 BaseUrl 动态切换策略(结合 ServiceManager 实现)
android·kotlin
移动开发者1号12 小时前
Kotlin实现文件上传进度监听:RequestBody封装详解
android·kotlin
AJi15 小时前
Android音视频框架探索(三):系统播放器MediaPlayer的创建流程
android·ffmpeg·音视频开发
柿蒂16 小时前
WorkManager 任务链详解:优雅处理云相册上传队列
android
alexhilton16 小时前
使用用例(Use Case)以让Android代码更简洁
android·kotlin·android jetpack
峥嵘life17 小时前
Android xml的Preference设置visibility=“gone“ 无效分析解决
android·xml