关注公众号学习更多知识

灵感来源

前段时间看到了大佬fundroid使用compose编写俄罗斯方块的文章,深受启发,当时便决定也要把诺基亚的贪吃蛇搬到android上来,因此才有了这篇文章

本篇文章界面和思路参考于 fundroid的文章

fundroid俄罗斯方块传送: https://blog.csdn.net/vitaviva/article/details/115878190

最终效果

提前发一下效果,让读者有个心理预期,逻辑真不复杂,务必耐心看完

思路

我们的界面分为两部分,上半部分是游戏的动态显示区域,下半部分是操作区域

显示区域

显示区域也可以细分为两部分,

  • 边框+黑线边框
  • 屏幕动态显示区域

所以我们把这两部分分成两个组合@Composable BaseScreen@Composable GameScreen

BaseScreen用于绘制边框和黑线边框,这部分只需要绘制一次即可,所以我们需要抽离出来

GameScreen用于绘制动态区域,主要是绘制基础的浅色砖块矩阵,和蛇身深色砖块、游离蛇身深色砖块

操作区域

操作区域也有两部分,

  • 开始重置按钮、恢复暂停按钮,这两个按钮用于操作游戏状态
  • 方向键按钮,用于操纵蛇头方向

操作区域组合名称为@Composable OperateBody

其中操作状态按钮使用Row包裹两个@Composable GameButton来实现

方向键按钮使用一个Box来包裹四个@Composable DirectionButtom来实现

逻辑

如何数据通信

使用StateFlow.collectAsState方法来获取Compose状态,从而在状态更改的时候刷新界面

如何刷新游戏状态

使用LauncherEffect内部定义一个死循环来维护时钟,保证我们可以在自定义的时间间隔内更新游戏状态。

蛇身状态

我们使用一个数组来维护所有蛇身的砖块,然后就是蛇移动、蛇吃游离蛇身、蛇撞墙几个逻辑

蛇移动

蛇单纯移动的话,我们可以通过构建一个新数据的方式来实现,新数组的第一个元素就是蛇身下一个要移动到的砖块,然后将老的蛇身数组addAll到新的蛇身数组中,最后移除新蛇身数组的最后一个蛇身。刷新StateFlow状态

蛇吃游离蛇身

如果蛇下次要移动到的砖块位置刚好是游离蛇身的位置的话,那么我们直接将游离蛇身插入到数组的第一个元素位置,并且不移除蛇身数组最后位置的砖块

蛇撞墙

整个屏幕被我们栅格化为Width_Matrix * Height_Matrix数组,如果蛇头的位置超出栅格数组那么蛇撞墙死,游戏结束。

代码分析

StateFlow声明和使用

声明StateFlow,这部分不需要引入任何依赖

private val _flow = MutableStateFlow(SnakeState(action = Action.GameTick))
val stateFlow = _flow.asStateFlow()

使用StateFlow获取状态

 val model = viewModel<GameViewModel>()val state = model.stateFlow.collectAsState().value

这里的SnakeState就是我们定义的状态实体,代码如下:

data class SnakeState(var action: Action,val direction: Direction = Direction.Bottom,val snakeBody: MutableList<SnakePart> = mutableListOf(SnakePart(10, 10)),val freeSnakePart: SnakePart = SnakePart(15, 15),var Width_Matrix: Int = 0,var Height_Matrix: Int = 0,var isRunning: Boolean = true
)

游戏状态时钟代码

使用LauncherEffect维持死循环,300ms分发一次时钟

val model = viewModel<GameViewModel>()LaunchedEffect(key1 = Unit) {while (isActive) {delay(300)model.dispatch()}}

蛇移动、吃游离蛇身、撞墙代码

fun dispatch() {val state = stateFlow.valueif (state.action!=Action.GameTick){return}if (!state.isRunning) {//暂停状态不更新数据return}val firstPart = state.snakeBody.first()val newList = mutableListOf<SnakePart>()if (state.direction == Direction.Left || state.direction == Direction.Right) {val x = firstPart.x + state.direction.increaseif (x == state.freeSnakePart.x && firstPart.y == state.freeSnakePart.y) {//吃游离蛇身newList.add(state.freeSnakePart)newList.addAll(state.snakeBody)emit(state.copy(snakeBody = newList, freeSnakePart = newFreeSnakePart()))return}if (x > state.Width_Matrix || x < 0) {//撞墙emit(state.copy(action = Action.GameOver,))return} else {newList.add(SnakePart(x, firstPart.y))newList.addAll(state.snakeBody)newList.removeLast()//删除蛇身的最后一节}} else {val y = firstPart.y + state.direction.increaseif (y == state.freeSnakePart.y && firstPart.x == state.freeSnakePart.x) {//吃游离蛇身newList.add(state.freeSnakePart)newList.addAll(state.snakeBody)emit(state.copy(snakeBody = newList, freeSnakePart = newFreeSnakePart()))return}if (y > state.Height_Matrix || y < 0) {//撞墙emit(state.copy(action = Action.GameOver,))return} else {newList.add(SnakePart(firstPart.x, y))newList.addAll(state.snakeBody)newList.removeLast()//删除蛇身的最后一节}}emit(state.copy(snakeBody = newList))}fun emit(state: SnakeState) {_flow.value = state}

未实现部分

  • 蛇撞自身蛇身逻辑
  • 蛇撞墙后游戏结束的动画

这部分有兴趣的可以fork代码后自己实现一下,相信会有所收获。

代码:https://github.com/ananananzhuo-blog/HappySnake

android-使用compose写一个贪吃蛇游戏相关推荐

  1. python写一个游戏多少代码-使用Python写一个贪吃蛇游戏实例代码

    我在程序中加入了分数显示,三种特殊食物,将贪吃蛇的游戏逻辑写到了SnakeGame的类中,而不是在Snake类中. 特殊食物: 1.绿色:普通,吃了增加体型 2.红色:吃了减少体型 3.金色:吃了回到 ...

  2. python游戏脚本实例-使用Python写一个贪吃蛇游戏实例代码

    我在程序中加入了分数显示,三种特殊食物,将贪吃蛇的游戏逻辑写到了SnakeGame的类中,而不是在Snake类中. 特殊食物: 1.绿色:普通,吃了增加体型 2.红色:吃了减少体型 3.金色:吃了回到 ...

  3. 使用python game写一个贪吃蛇游戏

    前言 最近在用python 做项目,也想对python有多一些了解,之前有用C语言和C++写过python游戏,刚好可以通过这个游戏来对python多一些了解. 文章内容翻译自以下链接 https:/ ...

  4. 手机java做贪吃蛇_如何用Java写一个贪吃蛇游戏

    这是一位拓胜学员用Java写贪吃蛇游戏的心得:今天课程设计终于结束了自己学java没以前学C+那么用功了觉得我学习在哪里都是个开口向上的抛物线,现在应该在右半边吧,好了进入正题. 写java贪吃蛇也是 ...

  5. 用c语言写一个贪吃蛇游戏代码

    首先,贪吃蛇是一个经典的游戏,主要通过控制一条蛇在地图上吃食物,不断长长身体,最终实现最高分数. 以下是使用C语言编写贪吃蛇游戏的示例代码: ``` #include<stdio.h> # ...

  6. 前端三小时用html和js写一个贪吃蛇游戏,非常简单带讲解,代码可直接用,功能完整

    目录 游戏主体部分--普通模式 游戏主体部分--地狱模式 游戏主页入口 预览图 游戏入口代码 1.html 2.css 3.js 注册页面代码 游戏实现很简单,只写游戏主体的话只要三小时就够了. 话不 ...

  7. 贪吃蛇博弈算法python_算法应用实践:如何用Python写一个贪吃蛇AI

    原标题:算法应用实践:如何用Python写一个贪吃蛇AI 前言 这两天在网上看到一张让人涨姿势的图片,图片中展示的是贪吃蛇游戏, 估计大部分人都玩过.但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势 ...

  8. 好玩的c语言编程游戏,C语言写个贪吃蛇游戏

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 C语言写个贪吃蛇游戏 贪吃蛇是个非常经典的游戏,用C语言来实现也是一个好玩的事情.这个游戏我写完后放在知乎,竟然点赞的人数超级多.我觉得大家喜欢,一个方面 ...

  9. python游戏贪吃蛇_Python写的贪吃蛇游戏例子_python

    这篇文章主要介绍了Python写的贪吃蛇游戏例子,练手作品,又好玩又可以学到东西,需要的朋友可以参考下 第一次用Python写这种比较实用且好玩的东西,权当练手吧 游戏说明: * P键控制" ...

最新文章

  1. svcagent32.exe,javaM.exe木马查杀解决方案 (转Ad0.cn)
  2. MyBatis常见面试题汇总
  3. 不仅能搜索还能查信息 带你了解LBS应用
  4. 结合JDK源码看设计模式——桥接模式
  5. 解决Ubuntu IDEA 不能输入中文
  6. [Java核心技术(卷I)] - Java中的参数能做什么和不能做什么
  7. spring 2.2 改进_Spring 4中@ControllerAdvice的改进
  8. c 连接mysql示例 源码_MySQL 连接
  9. MySQL 为什么用索引,为什么是 B+树,怎么用索引
  10. 腾讯云挂在和格式化数据盘
  11. HDU 6241 Color a Tree
  12. Fiddler抓包一键生成代码
  13. 90-0004Web颜色标准【中英文颜色对照】
  14. Linux指令部分(一)
  15. HTML如何返回上一页?
  16. android系统优化启动时间(Google官方推荐)
  17. 我的时间管理之一 ——做好规划
  18. 9个offer,12家公司
  19. CCNP350-401学习笔记(1-50题)
  20. 《Python+Kivy(App开发)从入门到实践》自学笔记:打包——Windwos打包

热门文章

  1. 谈一谈DDD面向领域编程
  2. FCS(Frame Check Sequence)
  3. Chef集中管理工具实践
  4. 解决计算机的一些小问题,电脑故障怎么办?排除法解决电脑的一些小问题
  5. HandsFree——OpenRE库学习(一)
  6. Codeforces Round 867 (Div. 3) G2. Magic Triples (Hard Version)
  7. iOS8的一些好玩的升级
  8. JAVA抖音潜艇挑战,抖音怎么玩潜水艇挑战
  9. DELL R720服务器诊断
  10. 阿里云落地北美 誓与亚马逊一争高下?