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

相关推荐
轻口味2 小时前
Android应用性能优化
android
全职计算机毕业设计2 小时前
基于 UniApp 平台的学生闲置物品售卖小程序设计与实现
android·uni-app
dgiij3 小时前
AutoX.js向后端传输二进制数据
android·javascript·websocket·node.js·自动化
SevenUUp4 小时前
Android Manifest权限清单
android
高林雨露4 小时前
Android 检测图片抓拍, 聚焦图片后自动完成拍照,未对准图片的提示请将摄像头对准要拍照的图片
android·拍照抓拍
wilanzai4 小时前
Android View 的绘制流程
android
INSBUG5 小时前
CVE-2024-21096:MySQLDump提权漏洞分析
android·adb
Mercury Random6 小时前
Qwen 个人笔记
android·笔记
苏苏码不动了7 小时前
Android 如何使用jdk命令给应用/APK重新签名。
android
aqi007 小时前
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
android·ffmpeg·音视频·直播·流媒体