用compose写个斗兽棋(二)

在上一章节的斗兽棋文章发出之后,有老哥在评论区指出,怎么和他们小时候玩的不一样。

这可问到我了,原来你的童年我的童年真的不一样,于是我去百度了一下, 按照百度写的斗兽棋玩法和地图,对我的斗兽棋小APP进行升级,进化为PLUS版本。

规则

UI

在Codding了几天之后,完成了这个Plus版本的斗兽棋,虽然看上去复杂了一些,但是逻辑上比上一期的简易版本更简单了。UI主要分为两部分,地图,棋子

地图

也就是一个 9X7 的格子,获取到屏幕宽度之后,除7,就是每个格子的尺寸了,按照规则图片,在对应的地方画上 水,兽巢,现金,即可。

kotlin 复制代码
    val paint = Paint()
    // 河流
    paint.color = Color(0xFF03A9F4)
    paint.style = PaintingStyle.Fill
    val leftRiver = Rect(CellSize.px, CellSize.px * 3, CellSize.px * 3, CellSize.px * 6)
    it.drawRect(leftRiver, paint)
    val rightRiver =
        Rect(CellSize.px * 4, CellSize.px * 3, CellSize.px * 6, CellSize.px * 6)
    it.drawRect(rightRiver, paint)

    paint.color = Color.Blue
    paint.style = PaintingStyle.Stroke
    val rect = Rect(0f, 0f, CellSize.px * 7, CellSize.px * 9)
    it.drawRect(rect, paint)

    // 画竖线
    for (row in 1..6) {
        it.drawLine(
            Offset(CellSize.px * row, 0f),
            Offset(CellSize.px * row, CellSize.px * 9),
            paint
        )
    }
    // 横线
    for (column in 1..8) {
        it.drawLine(
            Offset(0f, CellSize.px * column),
            Offset(CellSize.px * 7, CellSize.px * column),
            paint
        )
    }

    val trapImg = ImageBitmap.imageResource(
        res = MyApplication.instance.resources,
        id = R.drawable.trap
    )


    // 画陷阱和兽巢
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 2,
            (CellSize.px - trapImg.height) / 2f
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - trapImg.height) / 2f + CellSize.px
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 4,
            (CellSize.px - trapImg.height) / 2f
        ),
        paint
    )


    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 2,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 8
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 7
        ),
        paint
    )
    it.drawImage(
        trapImg,
        topLeftOffset = Offset(
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 4,
            (CellSize.px - trapImg.height) / 2f + CellSize.px * 8
        ),
        paint
    )

    val homeImg = ImageBitmap.imageResource(
        res = MyApplication.instance.resources,
        id = R.drawable.home
    )

    it.drawImage(
        homeImg,
        topLeftOffset = Offset(
            (CellSize.px - homeImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - homeImg.height) / 2f
        ),
        paint
    )

    it.drawImage(
        homeImg,
        topLeftOffset = Offset(
            (CellSize.px - homeImg.height) / 2f + CellSize.px * 3,
            (CellSize.px - homeImg.height) / 2f +  CellSize.px * 8
        ),
        paint
    )

棋子

创建一个二维数组,按照规则的位置,八种动物从小到大,赋值1到8,空地的level为-1,给每个棋子放好位置。

kotlin 复制代码
private fun initCell(): SnapshotStateList<SnapshotStateList<CellBean>> {
    val result = SnapshotStateList<SnapshotStateList<CellBean>>()
    for (i in 0 until 9) {
        val list = SnapshotStateList<CellBean>()
        for (j in 0 until 7) {
            val cellBean = CellBean()
            list.add(cellBean)
        }
        result.add(list)
    }
    result[0][0].isRed = true
    result[0][0].level = 7
    result[0][6].isRed = true
    result[0][6].level = 6
    result[1][1].isRed = true
    result[1][1].level = 3
    result[1][5].isRed = true
    result[1][5].level = 2
    result[2][0].isRed = true
    result[2][0].level = 1
    result[2][2].isRed = true
    result[2][2].level = 5
    result[2][4].isRed = true
    result[2][4].level = 4
    result[2][6].isRed = true
    result[2][6].level = 8
    result[6][0].isRed = false
    result[6][0].level = 8
    result[6][2].isRed = false
    result[6][2].level = 4
    result[6][4].isRed = false
    result[6][4].level = 5
    result[6][6].isRed = false
    result[6][6].level = 1
    result[7][1].isRed = false
    result[7][1].level = 2
    result[7][5].isRed = false
    result[7][5].level = 3
    result[8][0].isRed = false
    result[8][0].level = 6
    result[8][6].isRed = false
    result[8][6].level = 7
    return result
}

逻辑

逻辑方面,其实很简单,如果按照上一篇文章的思路,就是选中棋子 ,还是操作棋子 。但是如果按照程序来看,我把它按照 点击空白点击棋子 两种方式来写了,这样看上去更为简洁。

点击空白

点击空白的时候,我们要判断三种情况,

1、无效点击

如果当前无被选择棋子,当前的点击就是无效点击

kotlin 复制代码
    val lastIndex = state.value.selectedIndex
    val lastCell = getPiece(state.value.selectedIndex)

    if (lastIndex == -1) {
        //无效点击
        return
    }
2、无效移动棋子
3、有效移动棋子

2和3就放在一起了

kotlin 复制代码
if ((lastCell.isRed && index in RedHome) ||
    (!lastCell.isRed && index in BlueHome)
) {
    // 自家不能进自己屋
    return
}

if (lastCell.level == 6 || lastCell.level == 7) {
    //狮子老虎可以跨河,特殊处理,上下左右
    val access = getAccessCell(lastIndex)
    if (index in access) {
        //可走
        moveOrEat(lastIndex, index)
    }
} else {
    if (lastIndex % 7 == index % 7 + 1 || lastIndex % 7 == index % 7 - 1  //左右走
        || lastIndex / 7 == index / 7 + 1 || lastIndex / 7 == index / 7 - 1 //往上下走
    ) {
        if (index in River) {
            // 是老鼠,可以在河里跑,其它动物均为无效操作
            if (lastCell.level == 1) {
                moveOrEat(lastIndex, index)
            }
        } else {
            // 不是河,直接走
            moveOrEat(lastIndex, index)
        }
    }
}

首先判断是不是往自己家里面走,自己的棋子不准进自己的兽巢

然后是要对 老虎和狮子 特殊处理,老虎和狮子可以跨河,所以要判断是不是在让他们跨河,以及河流中间是不是有老鼠阻断。我是直接根据老虎或狮子的坐标,获取到它可以走的位置的集合,然后判断当前点击的位置,是不是属于它可以走的位置。

kotlin 复制代码
private fun getAccessCell(index: Int): IntArray {
    val result = intArrayOf(-1, -1, -1, -1)
    // 左边能不能到达
    if ((index - 1) % 7 != 6) {
        // 没有换行
        if (index - 1 in River) {
            // 有河流,判断能不能跨河
            var target = index - 1
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target--
            }
            if (!haveMouse) {
                result[0] = target
            }
        } else {
            // 没有河流,可到达
            result[0] = index - 1
        }
    }

    //右边能不能到达
    if ((index + 1) % 7 != 0) {
        // 没有换行
        if (index + 1 in River) {
            // 有河流,判断能不能跨河
            var target = index + 1
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target++
            }
            if (!haveMouse) {
                result[1] = target
            }
        } else {
            // 没有河流,可到达
            result[1] = index + 1
        }
    }

    //下边
    if (index + 7 <= 62) {
        // 没有越界
        if (index + 7 in River) {
            // 有河流,判断能不能跨河
            var target = index + 7
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target += 7
            }
            if (!haveMouse) {
                result[2] = target
            }
        } else {
            // 没有河流,可到达
            result[2] = index + 7
        }
    }

    //上边
    if (index - 7 >= 0) {
        // 没有越界
        if (index - 7 in River) {
            // 有河流,判断能不能跨河
            var target = index - 7
            var haveMouse = false
            while (target in River) {
                if (getPiece(target).level == 1) {
                    //河中间有老鼠
                    haveMouse = true
                    break
                }
                target -= 7
            }
            if (!haveMouse) {
                result[3] = target
            }
        } else {
            // 没有河流,可到达
            result[3] = index - 7
        }
    }
    return result
}

除了狮子和老虎,其它棋子就判断当前点击的区域是不是上下左右了,如果是的,判断是不是河流,只有老鼠可以进入河流,其它棋子均不行。

点击棋子

同样是三种情况

1、选中或者切换选中棋子

如果目前没有选中,且点击的是自己的棋子,即可选中。或者目前已经有选中了,点击了其它自己的棋子,就是切换选中

kotlin 复制代码
val lastIndex = state.value.selectedIndex
val lastCell = getPiece(state.value.selectedIndex)
val targetCell = getPiece(index)
if ((lastIndex == -1 && state.value.isRedTurn == targetCell.isRed) || state.value.isRedTurn == targetCell.isRed) {
    //选中或者切换选中
    state.value = state.value.copy(selectedIndex = index)
    return
}
2、吃别人的棋子
3、无效操作

2.3两种操作其实就和走空地差不多了,只是走的时候要判断一下等级

kotlin 复制代码
if (lastCell.level == 6 || lastCell.level == 7) {
    // 豹子老虎可以跨河吃,特殊处理
    val access = getAccessCell(lastIndex)
    if (index in access) {
        //可走
        if ((index in BlueTrap)
            || (index in RedTrap)
        ) {
            // 敌方棋子在我方陷阱中,可以吃掉,无视等级,直接吃掉
            moveOrEat(lastIndex, index)
        } else {
            if (lastCell.level >= targetCell.level) {
                // 可吃
                moveOrEat(lastIndex, index)
            }
        }
    }
} else {
    if (lastIndex % 7 == index % 7 + 1 || lastIndex % 7 == index % 7 - 1  //左右走
        || lastIndex / 7 == index / 7 + 1 || lastIndex / 7 == index / 7 - 1 //往上下走
    ) {
        if ((index in BlueTrap)
            || (index in RedTrap)
        ) {
            // 敌方棋子在我方陷阱中,可以吃掉,无视等级,直接吃掉
            moveOrEat(lastIndex, index)
        } else {
            if (lastCell.level >= targetCell.level || (lastCell.level == 1 && targetCell.level == 8)) {
                // 可吃
                moveOrEat(lastIndex, index)
            }
        }
    }
}

判断结束

在每一步 eatOrMove之后,就要判断游戏是不是结束了

kotlin 复制代码
private fun moveOrEat(lastIndex: Int, targetIndex: Int) {
    getPiece(targetIndex).level = getPiece(lastIndex).level
    getPiece(targetIndex).isRed = getPiece(lastIndex).isRed
    getPiece(lastIndex).level = -1
    state.value = state.value.copy(selectedIndex = -1, isRedTurn = !state.value.isRedTurn)
    checkFinish()
}

// 判断结束
private fun checkFinish() {

    if (getPiece(RedHome[0]).level != -1) {
        // 结束,蓝方赢了
        onFinished?.invoke(false)
        return
    }
    if (getPiece(BlueHome[0]).level != -1) {
        // 结束,红方胜利
        onFinished?.invoke(true)
        return
    }

    var isRedWin = true
    var isBlueWin = true

    for (index in 0 until 63) {
        val piece = getPiece(index)
        if (piece.level != -1) {
            if (piece.isRed) {
                //红的还没死完
                isRedWin = false
            } else {
                isBlueWin = false
            }
        }
        if (!isRedWin && !isBlueWin) {
            // 对局还没结束
            return
        }
    }
    if (isRedWin) {
        onFinished?.invoke(true)
    }else{
        onFinished?.invoke(false)
    }
}

这样,一个Plus版本的斗兽棋就完成了

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

相关推荐
雨白4 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹6 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空7 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭8 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日9 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安9 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑9 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟13 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡14 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0014 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体