[文章]HarmonyOS LYEVK-3861开发板小游戏开发-贪吃蛇

阅读量0
1
4

前言

在LYEVK-3861开发板套件中,有1个OLED屏幕扩展板,带按键的照明板,本次我们用这2个扩展板实现一个简易的贪吃蛇小游戏。由于现有的板子资源有限,综合考虑,计划用OLED屏幕显示游戏运行界面,OLED扩展板和照明板上的按键复用为游戏选择和游戏控制方向键。

​ OLED屏幕为128*64的点阵,使用I2C接口,

​ OLED扩展板上的按键 用于游戏难度的选择和游戏开始的方向控制(向左)

照明板主要是使用板子上的按键,按键用于整个游戏中的确认操作和游戏运行过程中的方向控制(向右)

快速上手(推荐使用DevEco Device Tool工具下载,编译和烧录)

准备硬件环境

  • LYEVK-3861A套件

准备开发环境

开发环境安装配置参照文档:[DevEco Device Tool 环境搭建]

准备工程

本用例采DevEco Device Tool工具进行开发,当配置完开发环境后,我们可以在IDE上进行工程的配置下载。

  • 打开DevEco Device Tool,连接远程linux服务器:[DevEco Device Tool 环境搭建]
  • 点击左下角DevEco插件图标,然后点击左边框出现的主页,弹出主页界面,主页中选择新建项目,如下图:

main_config

  • 配置下载工程

config && download

如上图所示,填写对应样例工程的名称,选择对应的样例组件和样例工程存放路径后,点击创建即可进行样例工程的下载。下载界面如下:

download

当左下角显示正在下载OpenHarmony镜像时,耐心等待下载完成即可。

download

准备工具链

  • 在Projects中,点击Settings按钮,进入snake配置界面。

  • 在toolchain页签中,DevEco Device Tool会自动检测依赖的编译工具链是否完备,如果提示部分工具缺失,可点击SetUp按钮,自动安装所需工具链。

  • 如果出现安装pip组件失败,可参考[修改Python源的方法]进行修改,完成尝试重新安装。

  • 工具链自动安装完成后如下图所示。

    工具链配置成功

编译

样例代码下载完成后,DevEco Device

Tool会重新要求连接远程服务器,输入密码连接后会进入对应的代码编辑界面,此时点击左下角DevEco插件图标,选择PROJECT

TASKS可以查看到对应的样例工程,点击build选项进行编译,并可在终端查看对应的编译结果。

build ok

固件生成在对应工程目录的out/hispark_pegasus/wifiiot_hispark_pegasus/目录下。

烧录/安装

编译完成后可以通过DevEco Device Tool进行烧录,在烧录前需要做一些烧录的配置:

配置准备

在配置烧录前需要先查看DevEco Device Tool是否可以正常识别串口。

  • 点击左边栏"REMOTE DEVELOPMENT",找到 并点击” Local PC “ 选项。

  • 查看 Local PC右边图标

    如若图标为方型图标,则代表DevEco Device Tool已连接本地,可以正常识别串口。

    如若图标为箭头图标,则代表DevEco Device Tool未连接本地,不能识别串口,此时需要点击该绿色图标进行连接,连接成功后图标会变为方型图标

check local pc

  • 点击主页,在主页选择对应工程,点击配置工程进入到配置页面

config project

配置串口

配置页面选择的板级配置页面,在该页面查找到烧录选项,配置烧录选项中的upload_port和upload_protocol,upload_port选择开发板对应的串口号,upload_protocol默认选择hiburn-serial,最后点击右上角的保存按钮进行保存。

config serail port

烧录

当配置完串口以及固件后,直接点击左边栏工程管理中的upload即可,此时下方终端会出现对应烧录的信息,当终端出现BootromDownloadBoot字样,按下开发板的 “RESET” 键复位开发板即可。

burn

OLED模块与SSD1306分析

OLED与SSD1306显示原理

​ 板子上的OLED屏幕约为0.96寸,显存大小128*64,分8个页,PAGE0~PAGE7,128列。

OLED与方块

方块点阵定义

贪吃蛇的蛇身采用■方块表示,现有的板子的OLED的驱动库里是没有■的点阵定义的,使用PCtoLCD2002这个工具可以生成■的字符点阵定义,可以按照自己的需要生成指定大小的点阵,我们这里使用8*8的点阵,取模结果如下:

按照如图所示的步骤,实现对方块的取模。实际测试过程中,发现使用原始的取模结果,组成完整蛇的身体的过程中,每个方块之间的间隙比较大,显示效果不是很好,我们对取模结果做了修改,最后的方块的8*8点阵表示如下:

/*---8*8 点阵*/
static const unsigned char F8X8[]=
{
   //0x00,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x00,
   0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x00, //■
};

OLED显示方块

关于方块的显示和消除,我们使用自己定义的函数来显示整个方块,这函数需要指定方块的起始位置,整个方块的处理不影响屏幕其他区域的显示

/*打印1个方块或者消除方块*/
void Bar(uint8 x0, uint8 y0, DisOnOff onOff)

贪吃蛇

有了以上的一些基础,我们就可以根据我们LYEVK-3861的开发板来设计一个简短贪吃蛇小游戏了。

贪吃蛇游戏基本定义

1、按键复用

​ OLED扩展板上的按键功能:①游戏主界面,点击按钮,可选择不同的难度;② 游戏界面,功能为控制蛇头左转;

​ 照明板上的按键功能:①游戏主界面、游戏结束界面、游戏通过界面,确认操作,界面跳转 ②游戏界面,功能为控制蛇头右转。

2、主界面

​ 显示游戏的名字、游戏的可选难度(1、2、3,数字越大难度越大),按键功能选择

3、游戏界面

​ 使用整个屏幕128x64作为游戏可运行的界面,蛇由方块(8x8的点阵)组成,方块充满整个界面需要16*8个方块。

4、游戏规则定义

初始长度为3,方向为右

每次移动1个长度单位(匀速,不同难度移动速度不同)

通过按键,方向可以改变为蛇前进方向的左边或右边

随机生成食物

吃到食物长度+1

碰到墙壁或身体结束游戏(失败)

长度达到最长长度结束游戏(成功)

贪吃蛇基本算法设计

蛇的定义

typedef struct {
    int8 X[SNAKE_MAX_LONG];
    int8 Y[SNAKE_MAX_LONG];
    uint8 Long;           //蛇的长度
    gameLevel Level;          // 1-简单 2- 正常 3- 困难
    snakeDirection Direction; //蛇的前进方向 默认向右
} snakeType;                      //蛇结构体

蛇的移动

  • 蛇的局部刷新

由于开发板的CPU

Hi3861性能和0.96寸的处理性能都很有限,在贪吃蛇游戏的运行过程中,不能每次都刷新整个屏幕,更新蛇的身体。这里,我们采用局部刷新的方法,避免一次刷新整个屏幕,影响游戏的性能。具体处理方法如下:

蛇每移动一个长度单位(1个方块),不管有没有吃到食物,蛇头方块的位置都会被打印到屏幕上,蛇的尾部方块在未吃到食物的情况下,会被消除,吃到食物,则本次不消除尾部方块。这样做的好处时,蛇每一次的位置变化,除了判断是否吃到食物,只需要对头尾部的方块做打印处理,不需要重复打印蛇身的所有方块。

  • 蛇的移动规则

基于开发板的现有资源,想要实现贪吃蛇的4个方向直接控制是不现实的,为了合理利用开发板的配套资源,我们使用OLED扩展板和照明板上的2个按键来控制蛇的移动。设计方法简要说明如下:

1、 8x8的点阵分割整个屏幕后,每个方块的坐标范围在横向(0-15),纵向(0-7),蛇每次移动一个方块的位置,蛇头的变化范围都是在-1,0,1这个3个数字之间变化,按照蛇的4个行进方向和是否左右转,定义以下的参数:

typedef enum {
    DIREC_STRAIGHT = -1,
    DIREC_RIGHT,  //右
    DIREC_TOP,    //上
    DIREC_LEFT,   //左
    DIREC_BOTTOM, //底
    DIREC_MAX
} snakeDirection;

/*1-2 直行  3-4 左转 5-6 右转*/
static int8 snakeDirectonInfo[4][6] = {
    {1, 0, 0, -1, 0, 1},  //DIREC_RIGHT
    {0, -1, -1, 0, 1, 0}, //DIREC_TOP
    {-1, 0, 0, 1, 0, -1}, //DIREC_LEFT
    {0, 1, 1, 0, -1, 0}   //DIREC_BOTTOM
};

说明:每个方向有6个元素定义, 按照两位一组,分别为直行、左转、右转,这样在处理蛇的移动的时候,可以直接套用定义好的数组,来优化蛇身移动的逻辑处理。

2、没有按键时,蛇按照一定的频率(刷新频率)向前移动,每次移动一个方块;有按键时,根据不同的按键选择不同的处理方式:

if (direc == DIREC_LEFT)
    { //左转
        newPos[0] = snakeDirectonInfo[Snake.Direction][2];
        newPos[1] = snakeDirectonInfo[Snake.Direction][3];
        Snake.Direction = (Snake.Direction + 1) > DIREC_BOTTOM ? (DIREC_RIGHT) : (Snake.Direction + 1);//新的方向
    }
    else if (direc == DIREC_RIGHT)
    { //右转
        newPos[0] = snakeDirectonInfo[Snake.Direction][4];
        newPos[1] = snakeDirectonInfo[Snake.Direction][5];
        Snake.Direction = (Snake.Direction - 1) < DIREC_RIGHT ? (DIREC_BOTTOM) : (Snake.Direction - 1);//新的方向
    }
    else
    { //前进
        newPos[0] = snakeDirectonInfo[Snake.Direction][0];
        newPos[1] = snakeDirectonInfo[Snake.Direction][1];
    }

说明: 当前蛇的行进方向在有偏转的情况下,需要更新蛇的行进方向,这样设计的好处是,便于计算蛇下次的运行位置,让蛇在我们设计的正确的路径上行进。

  • 蛇是否撞墙,是否吃到自己

​ 撞墙和吃到自己的算法也简单,撞墙就判断蛇头坐标是否和墙重合,吃自己函数就遍历所有身体坐标,看是否与头重合。是这一部分是否吃到自己的判断可能会影响到一些游戏的性能

食物

  • 食物生成/更新

    游戏开始或者食物被吃,重新生成食物坐标,取系统的时钟计数取模来生成一个随机的坐标,若坐标和蛇身重合,则重新生成。

  • 食物是否被吃

    算法也很简单,先判断蛇头坐标是否和食物坐标重合。如果重合则蛇变长一节,把之前储存的蛇尾后面一节坐标赋给最新一节身体。然后重新生成一次食物。

按鍵检测

​ 本程序使用到2个按键,相关代码如下:

IoTGpioInit(IOT_IO_NAME_GPIO_8); //button  按键B
    IoTGpioSetDir(IOT_IO_NAME_GPIO_8, IOT_GPIO_DIR_IN);

    IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_8, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, OnButtonBPressed, NULL);

    IoTGpioInit(IOT_IO_NAME_GPIO_5); // oled button  按键A
    IoTGpioSetDir(IOT_IO_NAME_GPIO_5, IOT_GPIO_DIR_IN);

    IoTGpioRegisterIsrFunc(IOT_IO_NAME_GPIO_5, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, OnButtonAPressed, NULL);

按键响应函数独立检测按键:①游戏主界面,按键选择难度和开始游戏,②游戏运行中,未按键时,蛇身在当前方向移动,直至蛇撞墙;有按键时,根据不同的按程序调整蛇的移动方向,并做其他的逻辑处理。

说明:只是简单的对按键进行响应,并未做复杂的优先级和锁的控制,这一部分有待后续完善。

总结

以上,完成一个基于LVEVK-3861开发板的贪吃蛇小游戏的开发, 限于篇幅,只列出了部分代码。 由于本人业务水平不够,整个开发的过程还是有不少的问题出现,解决了部分,也有很多没有解决。部分功能也没有做完善,留待后续再去补充吧,毕竟没有十全十美。

回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友