RISC-V技术论坛
直播中

jefljel

9年用户 1199经验值
擅长:20762
私信 关注
[经验]

利用RV-STAR开发板移植Chrome的离线游戏小恐龙

RV-STAR开发板上正好有一个按钮,不来做小游戏可惜了,就买了OLED屏幕,改了网上大佬的游戏代码,移植了Chrome的离线小游戏Dino小恐龙。





我买的OLED是7脚的,支持I2C和SPI协议,通过焊接电阻来修改协议,我没修改用的是默认的SPI协议。接线如下图:


本来GD32VF103支持硬件SPI的,但是我一直成功不了,就用软件SPI(用普通GPIO模拟SPI协议传输信号)了。
OLED的厂商会提供相应的驱动,网上随便就找得到,不只包括OLED初始化代码(但不同厂商的初始化代码好像不一样),还有软件SPI通信的实现、OLED图形GUI库等等。开发起来还是很方便的。

游戏代码是修改自网上大佬cr4fun代码,我把代码从MicroPython修改为了C语言,基本游戏逻辑没太大改动。                              



感谢芯来科技公司提供的RISC-V课程和体验机会,RV-STAR开发板有板载调试器,调试起来很方便,现在免驱动并且有不错的IDE,建立工程下载代码很方便,GD32VF103的库函数看起来也很丰富了,只是网上的资料、例程还不算多,学习起来有点迷茫。
希望芯来科技和国产芯片发展得越来越好!



代码如下。

入口:

#include "gd32vf103.h"#include "gd32vf103v_rvstar.h"#include "game.h"#include "oled.h"#include "gui.h"/*!    brief      main function    param[in]  none    param[out] none    retval     none*/int main(void){        gd_rvstar_key_init(KEY_WAKEUP,KEY_MODE_EXTI);        __enable_irq();         OLED_Init();                                //初始化OLED        OLED_Clear(1);             //清屏(全黑)        while(1)        {                game_loop();        }}OLED初始化:
//-----------------Pin Def----------------#define OLED_PORT GPIOA#define OLED_CS //empty#define OLED_DC GPIO_PIN_8#define OLED_RST GPIO_PIN_6#define OLED_SCK GPIO_PIN_5#define OLED_MOSI GPIO_PIN_7//-----------------OLED Reg Clr/Set function----------------#define OLED_CS_Clr() //empty#define OLED_CS_Set() //empty#ifdef SPI_SW#define OLED_MOSI_Clr() gpio_bit_reset(OLED_PORT, OLED_MOSI)#define OLED_MOSI_Set() gpio_bit_set(OLED_PORT, OLED_MOSI)#define OLED_CLK_Clr() gpio_bit_reset(OLED_PORT, OLED_SCK)#define OLED_CLK_Set() gpio_bit_set(OLED_PORT, OLED_SCK)#define OLED_DC_Clr() gpio_bit_reset(OLED_PORT, OLED_DC)#define OLED_DC_Set() gpio_bit_set(OLED_PORT, OLED_DC)#define OLED_RST_Clr() gpio_bit_reset(OLED_PORT, OLED_RST)#define OLED_RST_Set() gpio_bit_set(OLED_PORT, OLED_RST)void OLED_Init_GPIO(void){    //         RCU config    rcu_periph_clock_enable(RCU_GPIOA);    //  GPIO config    /* SPI_SW GPIO config:SCK/PA5->D0, MOSI/PA7->D1 */    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_SCK | OLED_MOSI);    /* GPIO config:PA6->RES, PA8->DC */    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_DC | OLED_RST);    /* GND->CS */}void SPI_SW_WriteByte(uint8_t Data){    uint8_t i = 0;    for (i = 8; i > 0; i--) {        if (Data & 0x80) {            OLED_MOSI_Set(); //写数据1        } else {            OLED_MOSI_Clr(); //写数据0        }        OLED_CLK_Clr(); //将时钟拉低拉高        OLED_CLK_Set(); //发送1bit数据        Data <<= 1;    }}void OLED_WR_Byte(uint8_t dat, uint8_t cmd){    if (cmd) {        OLED_DC_Set();    } else {        OLED_DC_Clr();    }    OLED_CS_Clr();    SPI_SW_WriteByte(dat);    OLED_CS_Set();}void OLED_Init(void){    OLED_Init_GPIO(); //初始化GPIO    delay_1ms(200);    OLED_Reset(); //复位OLED    /**************初始化SSD1306*****************/    OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel    OLED_WR_Byte(0x00, OLED_CMD); //---set low column address    OLED_WR_Byte(0x10, OLED_CMD); //---set high column address    OLED_WR_Byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)    OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register    OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness    OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常    OLED_WR_Byte(0xC8, OLED_CMD); //Set COM/Row Scan Direction   0xc0上下反置 0xc8正常    OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display    OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)    OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty    OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset        Shift Mapping RAM Counter (0x00~0x3F)    OLED_WR_Byte(0x00, OLED_CMD); //-not offset    OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency    OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec    OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period    OLED_WR_Byte(0xF1, OLED_CMD); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock    OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration    OLED_WR_Byte(0x12, OLED_CMD);    OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh    OLED_WR_Byte(0x40, OLED_CMD); //Set VCOM Deselect Level    OLED_WR_Byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)    OLED_WR_Byte(0x02, OLED_CMD); //    OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable    OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable    OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)    OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)    OLED_WR_Byte(0xAF, OLED_CMD);    OLED_Clear(0);}

游戏主体(原仓库:https://github.com/OpensourceBooks/chrome_offline_game_on_esp8266
#include "game.h"#include "gui.h"#include "oled.h"#include #include #define TRUE 1#define FALSE 0#define FONTSIZE 8#define jump_button_click_handler EXTI0_IRQHandler//===========================BMP===================================uint8_t OBJ_BMP[] = {    0x1C, 0x00, 0x1C, 0x00, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0xDD, 0x80,    0xDD, 0x80, 0xDF, 0x00, 0xDE, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x7C, 0x00, 0x3C, 0x00,    0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00};uint8_t PLAYER_BMP[] = {    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xE0, 0x00,    0x06, 0x60, 0x00, 0x04, 0x20, 0x00, 0x04, 0x20, 0x00, 0x06, 0x30, 0x00};uint8_t PLAYER1_BMP[] = {    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xA0, 0x00,    0x06, 0x20, 0x00, 0x04, 0x30, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00};uint8_t PLAYER2_BMP[] = {    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0C, 0xE0, 0x00,    0x04, 0x60, 0x00, 0x06, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00};//===========================ENUM===================================typedef enum BMPn_Enum {    PLAYER_BMPN,    PLAYER_LEG1_BMPN,    PLAYER_LEG2_BMPN,    OBJ_BMPN,} BMPn_Enum;typedef enum Game_State_Enum {    READY,    PLAYING,    GAMEOVER} Game_State_Enum;//===========================Global variables===================================Game_State_Enum Game_State = PLAYING;int Status_is_jumpfinish = 0, Status_is_jumping = 0;uint16_t Gametime = 0, Distance = 0;char Distance_str[20] = { '�' };int X_obj = 130, Y_obj = 44;int X_player = 10, Y_player = 44, Status_leg_player = 1;const int X_bg = 0, Y_bg = 53;//===========================Functions===================================#define blit_text(str, x, y) (GUI_ShowString((x), (y), (str), (FONTSIZE), 1))void blit_bmp(BMPn_Enum BMPn, uint8_t x, uint8_t y){    switch (BMPn) {    case PLAYER_BMPN:        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER_BMP, 1);        break;    case PLAYER_LEG1_BMPN:        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER1_BMP, 1);        break;    case PLAYER_LEG2_BMPN:        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER2_BMP, 1);        break;    case OBJ_BMPN:        GUI_DrawBMP_TransparentBg(x, y, 10, 20, OBJ_BMP, 1);        break;    default:        break;    }}void game_init(void){    Game_State = READY;    Gametime = 0;    Distance = 0;    Status_is_jumping = FALSE;    Status_is_jumpfinish = TRUE;    X_obj = 130;    Y_obj = 44;    Y_player = 44;}void jump_button_click_handler(void){    if (RESET != exti_interrupt_flag_get(WAKEUP_KEY_PIN)) {        if (RESET == gd_rvstar_key_state_get(KEY_WAKEUP)) {            if (Game_State == PLAYING) {                if (Status_is_jumpfinish) {                    Status_is_jumping = TRUE;                    Status_is_jumpfinish = FALSE;                }            }            if (Game_State == GAMEOVER) {                Game_State = READY;                game_init();            } else {                Game_State = PLAYING;            }        }    }    /* clear EXTI lines pending flag */    exti_interrupt_flag_clear(WAKEUP_KEY_PIN);}void draw_player(void){    static uint8_t player_pic = PLAYER_BMPN;    if (Status_is_jumping) {        Y_player -= 3;        blit_bmp(player_pic, X_player, Y_player);        if (Y_player < 15)            Status_is_jumping = FALSE;    } else {        player_pic = PLAYER_LEG1_BMPN;        Y_player += 3;    }    if (Y_player >= 43) {        Y_player = 43;        Status_is_jumpfinish = TRUE;    }    if (Status_leg_player == 1) {        blit_bmp(PLAYER_LEG1_BMPN, X_player, Y_player);        Status_leg_player = 2;    }    else if (Status_leg_player == 2) {        blit_bmp(PLAYER_LEG2_BMPN, X_player, Y_player);        Status_leg_player = 1;    }}void draw_obj(void){    X_obj -= 4;    blit_bmp(OBJ_BMPN, X_obj, Y_obj);    if (X_obj <= -10)        X_obj = 130;}void draw_score(void){    itoa(Distance, Distance_str, 10);    strcat(Distance_str, " km");    blit_text(Distance_str, 2, 0);}void check(void){    if (X_obj - X_player < 15 && Y_obj - Y_player < 15)        Game_State = GAMEOVER;}int game_loop(void){    while (TRUE) {        GUI_Fill(0, 0, 127, 63, 0); //Black        if (Game_State == READY) {            blit_text("> Click to play!", 10, 10);            blit_text("by cr4fun", 10, 30);            blit_text("   & Endless", 10, 40);        } else if (Game_State == PLAYING) {            Distance += 1;            Gametime += 1;            GUI_DrawLine(0, 63, 127, 63, 1); //draw the ground            draw_score();            draw_player();            draw_obj();            check();        } else if (Game_State == GAMEOVER) {            draw_score();            GUI_ShowString(23, 20, "GAME OVER!", 16, 1);        }        OLED_Display();        delay_1ms(100);    }}



                                                                                

更多回帖

发帖
×
20
完善资料,
赚取积分