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

相关推荐
好奇龙猫8 分钟前
【人工智能学习-AI-MIT公开课13.- 学习:遗传算法】
android·人工智能·学习
TO_ZRG11 分钟前
Unity打包安卓、iOS知识点
android·unity·android studio
周杰伦fans12 分钟前
AndroidStudioJava国内镜像地址gradle
android·java·android-studio
艾莉丝努力练剑13 分钟前
【Linux进程控制(一)】进程创建是呼吸,进程终止是死亡,进程等待是重生:进程控制三部曲
android·java·linux·运维·服务器·人工智能·安全
2501_9240641114 分钟前
2026年移动应用渗透测试流程方案及iOS与Android框架对比
android·ios
用户693717500138417 分钟前
谷歌官方推荐:Android 性能优化全攻略——从工具到实战,两周提升 App 评分
android·android studio·android jetpack
顾林海18 分钟前
Android Profiler实战宝典:揪出CPU耗时元凶与内存泄露小偷
android·面试·性能优化
城东米粉儿18 分钟前
Android刷新与绘制机制详解 笔记
android
李艺为38 分钟前
Android 16安兔兔分辨率作假显示(非修改TextView方案)
android
裴云飞42 分钟前
Compose原理二之GapBuffer
android·架构