找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 18|回复: 0

[冒泡] 冒泡Mrp软件游戏开发规范

[复制链接]

3万

主题

0

回帖

11万

积分

管理员

积分
114388
发表于 12 小时前 |中国| 显示全部楼层 |阅读模式
# 功能机游戏开发规范

本文档为功能机平台(冒泡平台)游戏开发人员提供编写规范和最佳实践指南。

---

## 一、基础开发约束

### 1.1 编译器和语言标准
- **编译器**:使用 `mrpbuilder` 编译器(基于 ADS 1.2 的 armcc)
- **语言标准**:严格遵循 **C98 标准**,不支持 C99 特性
- **变量声明**:所有变量必须在函数或代码块开头声明,不能在中间声明
  ```c
  /* 正确示例 */
  void foo(void) {
      int i;
      char* text;
      /* 变量全部在开头声明 */

      i = 0;
      text = "hello";
  }

  /* 错误示例 */
  void bar(void) {
      doSomething();
      int i = 0;  /* 错误:变量声明不在开头 */
  }
  ```

### 1.2 不支持的系统头文件
- 不能使用标准 C 库头文件(如 `string.h`、`stdlib.h`)
- 但相关函数已映射到 mrc 函数,可直接使用:
  ```c
  malloc   -> mrc_malloc
  free     -> mrc_free
  memcpy   -> mrc_memcpy
  memset   -> mrc_memset
  strcpy   -> mrc_strcpy
  strcmp   -> mrc_strcmp
  sprintf  -> mrc_sprintf
  atoi     -> mrc_atoi
  ```

### 1.3 可用头文件
```c
#include <mrc_base.h>       /* 基础API、按键定义、事件定义 */
#include "uc3_font.h"       /* 字体绘制 */
#include "mrc_graphics.h"   /* 图形绘制API */
#include "mpc.h"            /* MPC 图片格式支持 */
```

### 1.4 线程与定时器
- **禁止使用线程**:功能机不支持多线程
- **游戏主循环**:使用定时器 `mrc_timerCreate/Start` 模拟游戏循环
  ```c
  /* 创建定时器实现30fps游戏循环 */
  timer_cd = mrc_timerCreate();
  mrc_timerStart(timer_cd, 33, 0, timer_run, 1);  /* 33ms = 30fps */
  ```

---

## 二、窗口管理系统

### 2.1 窗口类型定义
使用枚举定义所有窗口类型,便于管理:
```c
/* 窗口类型枚举 */
enum {
    WINDOW_MENU = 0,    /* 主菜单窗口 */
    WINDOW_GAME = 1,    /* 游戏窗口 */
    WINDOW_HELP = 2,    /* 帮助窗口 */
    WINDOW_ABOUT = 3    /* 关于窗口 */
};

/* 全局当前窗口变量 */
int currentWindow;
```

### 2.2 窗口切换函数
实现统一的窗口切换函数,集中管理页面跳转逻辑:
```c
void switchWindow(int windex, int level) {
    if (windex == 1) {
        /* 从菜单进入其他窗口 */
        if (level == MENU_GAME) {
            currentWindow = WINDOW_GAME;
            initGame();
            drawGame();
        } else if (level == MENU_HELP) {
            currentWindow = WINDOW_HELP;
            drawHelp();
        }
    } else if (windex == 0) {
        /* 返回菜单 */
        currentWindow = WINDOW_MENU;
        pmenu_draw(&mainMenu);
    }
}
```

### 2.3 事件分发机制
在 `mrc_event` 中根据当前窗口分发事件:
```c
int32 mrc_event(int32 code, int32 param0, int32 param1) {
    if (currentWindow == WINDOW_MENU) {
        /* 菜单窗口事件 */
        pmenu_event(&mainMenu, code, param0, param1);
    } else if (currentWindow == WINDOW_GAME) {
        /* 游戏窗口事件 */
        gameEvent(code, param0, param1);
    } else if (currentWindow == WINDOW_HELP) {
        /* 帮助窗口事件 */
        helpEvent(code, param0, param1);
    }
    return 0;
}
```

### 2.4 游戏逻辑隔离
定时器回调中只在游戏窗口时执行游戏逻辑:
```c
void timer_run(int32 id) {
    /* 只在游戏窗口时更新游戏状态 */
    if (currentWindow == WINDOW_GAME) {
        updateGame();
        drawGame();
    }
}
```

---

## 三、软键提示规范

### 3.1 软键位置和作用

功能机通常有两个软键(左软键和右软键),位于屏幕下方实体按键区域:

| 软键 | 按键常量 | 位置 | 常用功能 |
|-----|---------|------|---------|
| 左软键 | `_SLEFT` | 屏幕左下 | **确认** / 选择 / 进入 |
| 右软键 | `_SRIGHT` | 屏幕右下 | **返回** / 取消 / 退出 |

### 3.2 屏幕提示显示规范

**必须在屏幕底部显示软键提示文字**,告知用户按键功能:

```
┌─────────────────────────────┐
│                             │
│     游戏内容区域            │
│                             │
│                             │
├─────────────────────────────┤
│ 确认              返回      │  ← 软键提示区域
└─────────────────────────────┘
  ↑                   ↑
左软键              右软键
```

### 3.3 软键提示实现示例

#### 方法一:简洁文字(推荐)
```c
void drawSoftKeyHints(char* leftText, char* rightText) {
    int leftX, rightX, y;

    y = SCRH - 25;  /* 距离底部25像素 */

    /* 左软键提示(屏幕左下) */
    if (leftText != NULL) {
        leftX = 10;
        uc3_drawText(leftText, leftX, y, 0, 0, 0, 0);
    }

    /* 右软键提示(屏幕右下) */
    if (rightText != NULL) {
        rightX = SCRW - uc3_getWidth(rightText, 0) - 10;
        uc3_drawText(rightText, rightX, y, 0, 0, 0, 0);
    }
}

/* 使用示例 */
drawSoftKeyHints("确认", "返回");
```

#### 方法二:带背景高亮(可选)
```c
void drawSoftKeyHintsWithBg(char* leftText, char* rightText) {
    int leftX, rightX, y;
    int textW;

    y = SCRH - 30;

    /* 左软键 */
    if (leftText != NULL) {
        leftX = 10;
        textW = uc3_getWidth(leftText, 0);
        gl_drawRect(leftX - 5, y - 2, textW + 10, 20, 0xFFE0E0E0);
        uc3_drawText(leftText, leftX, y, 0, 0, 0, 0);
    }

    /* 右软键 */
    if (rightText != NULL) {
        textW = uc3_getWidth(rightText, 0);
        rightX = SCRW - textW - 10;
        gl_drawRect(rightX - 5, y - 2, textW + 10, 20, 0xFFE0E0E0);
        uc3_drawText(rightText, rightX, y, 0, 0, 0, 0);
    }
}
```

### 3.4 不同场景的软键配置

| 场景 | 左软键文字 | 右软键文字 | 说明 |
|-----|-----------|-----------|------|
| 主菜单 | "选择" / "确认" | "退出" | 左键进入选项,右键退出程序 |
| 游戏中 | NULL | "返回" | 只显示返回,游戏操作靠触屏 |
| 帮助页面 | "确认" | "返回" | 确认关闭帮助,返回菜单 |
| 设置页面 | "保存" | "取消" | 保存设置或取消 |
| 对话框 | "确定" | "取消" | 确认或取消操作 |

### 3.5 事件处理示例

```c
void gameEvent(int32 code, int32 param0, int32 param1) {
    if (code == KY_UP) {  /* 按键松开事件 */
        if (param0 == _SRIGHT) {
            /* 右软键:返回菜单 */
            switchWindow(0, 0);
        } else if (param0 == _SLEFT) {
            /* 左软键:暂停游戏 */
            gamePause();
        }
    }
}

void menuEvent(int32 code, int32 param0, int32 param1) {
    if (code == KY_UP) {
        if (param0 == _SLEFT) {
            /* 左软键:确认进入选中项 */
            enterMenuItem();
        } else if (param0 == _SRIGHT) {
            /* 右软键:退出程序 */
            mrc_exit();
        }
    }
}
```

---

## 四、图形渲染规范

### 4.1 屏幕刷新
**每次绘制完成后必须调用 `mrc_refreshScreen`**,否则画面不会更新:
```c
void drawGame(void) {
    /* 绘制背景 */
    drawBitmap(bgBitmap, 0, 0);

    /* 绘制游戏元素 */
    drawPlayer();
    drawEnemies();

    /* 绘制UI */
    drawScore();

    /* 必须刷新屏幕! */
    mrc_refreshScreen(0, 0, SCRW, SCRH);
}
```

### 4.2 屏幕尺寸变量
使用全局变量获取屏幕尺寸,支持不同分辨率设备:
```c
extern int16 SCRW;   /* 屏幕宽度 */
extern int16 SCRH;   /* 屏幕高度 */
```

### 4.3 颜色格式
`mrc_graphics.h` 中的颜色使用 **ARGB 格式**:
```c
0xFFFF0000  /* 红色 */
0xFF00FF00  /* 绿色 */
0xFF0000FF  /* 蓝色 */
0x80000000  /* 半透明黑色 */
```

`mrc_base.h` 中的函数使用 **RGB 分量**:
```c
mrc_drawPointEx(x, y, 255, 0, 0);      /* 红色 */
mrc_clearScreen(255, 255, 255);        /* 白色 */
```

---

## 五、资源管理

### 5.1 图片资源加载
```c
/* 从资源文件加载 */
BITMAP_565* bmp = readBitmap565FromAssets("fish.bma");

/* 使用完毕后必须释放 */
bitmapFree(bmp);
```

### 5.2 字体初始化和释放
```c
/* 在 mrc_init 中初始化字体 */
uc3_init();

/* 在 mrc_exitApp 中释放字体 */
uc3_free();
```

### 5.3 定时器管理
```c
/* 创建和启动 */
int32 timer = mrc_timerCreate();
mrc_timerStart(timer, 33, 0, timer_callback, 1);

/* 退出时必须停止和删除 */
mrc_timerStop(timer);
mrc_timerDelete(timer);
```

---

## 六、按键和触摸事件

### 6.1 事件类型
```c
enum {
    KY_DOWN,  /* 按键按下 */
    KY_UP,    /* 按键松开 */
    MS_DOWN,  /* 触摸按下 */
    MS_UP,     /* 触摸松开 */
    MS_MOVE=12      /* 触摸移动 */
};
```

### 6.2 按键常量
```c
_UP          /* 方向键上 */
_DOWN        /* 方向键下 */
_LEFT        /* 方向键左 */
_RIGHT       /* 方向键右 */
_SELECT      /* 确认键(方向键中心) */
_SLEFT       /* 左软键 */
_SRIGHT      /* 右软键 */
_0 到 _9     /* 数字键 */
_STAR        /* * 键 */
_POUND       /* # 键 */
```

### 6.3 事件处理模板
```c
int32 mrc_event(int32 code, int32 param0, int32 param1) {
    if (code == KY_UP) {
        /* 按键松开 */
        /* param0 是按键码 */
        if (param0 == _SELECT) {
            /* 处理确认键 */
        }
    } else if (code == MS_UP) {
        /* 触摸松开 */
        /* param0 是 X 坐标,param1 是 Y 坐标 */
        int x = param0;
        int y = param1;
        /* 处理点击 */
    }
    return 0;
}
```

---

## 七、常见陷阱和注意事项

### 7.2 for 循环变量声明
**错误**:
```c
for (int i = 0; i < 10; i++) {  /* C99语法,不支持 */
    /* ... */
}
```

**正确**:
```c
int i;
for (i = 0; i < 10; i++) {
    /* ... */
}
```

### 7.3 注释风格
建议使用 C89 风格注释(`/* */`),虽然 `//` 通常也能工作:
```c
/* 这是推荐的注释方式 */
// 这种注释可能在某些编译器配置下出错
```

### 7.4 函数声明顺序
**函数必须在使用前声明**,否则会产生 `inventing extern` 警告:
```c
/* 前向声明 */
void drawGame(void);
void updateGame(void);

void timer_run(int32 id) {
    updateGame();  /* 正确:函数已声明 */
    drawGame();
}

void updateGame(void) {
    /* 实现 */
}

void drawGame(void) {
    /* 实现 */
}
```

---

## 八、项目结构建议

```
project/
├── main.c              # 主程序入口
├── game_menu.c         # 菜单系统
├── game_menu.h
├── assets/             # 资源文件
│   ├── bg_240.bma      # 背景图
│   ├── fish_01.bma     # 游戏元素
│   └── logo_240.bma    # Logo
├── src/                # 库文件
│   ├── mrc_base.h
│   ├── mrc_graphics.h
│   ├── uc3_font.h
│   └── mpc.h
├── 程序编写说明.md      # 平台API文档
└── 功能机开发规范.md    # 本文档
```

---

## 九、调试技巧

### 9.1 日志输出
使用 `mrc_printf` 输出调试信息:
```c
mrc_printf("Score: %d\n", score);
mrc_printf("[DEBUG] x=%d, y=%d\n", x, y);
```

### 9.2 分阶段初始化
在 `mrc_init` 中打印各阶段日志,方便定位初始化问题:
```c
int32 mrc_init(void) {
    mrc_printf("[INIT] Starting...\n");

    mrc_printf("[INIT] Loading resources...\n");
    loadAssets();

    mrc_printf("[INIT] Initializing font...\n");
    uc3_init();

    mrc_printf("[INIT] Done!\n");
    return 0;
}
```

---

## 十、完整窗口切换示例

以下是一个完整的多窗口游戏框架示例:

```c
#include <mrc_base.h>
#include "uc3_font.h"
#include "mrc_graphics.h"
#include "game_menu.h"

/* 窗口类型 */
enum {
    WINDOW_MENU = 0,
    WINDOW_GAME = 1,
    WINDOW_HELP = 2
};

/* 全局变量 */
int currentWindow;
PMENU mainMenu;

/* 函数声明 */
void drawGame(void);
void drawHelp(void);
void drawSoftKeyHints(char* left, char* right);

/* 窗口切换 */
void switchWindow(int windex, int level) {
    if (windex == 1) {
        if (level == 0) {
            currentWindow = WINDOW_GAME;
            drawGame();
        } else if (level == 1) {
            currentWindow = WINDOW_HELP;
            drawHelp();
        }
    } else {
        currentWindow = WINDOW_MENU;
        pmenu_draw(&mainMenu);
    }
}

/* 绘制软键提示 */
void drawSoftKeyHints(char* left, char* right) {
    int leftX, rightX, y;

    y = SCRH - 25;

    if (left != NULL) {
        leftX = 10;
        uc3_drawText(left, leftX, y, 0, 0, 0, 0);
    }

    if (right != NULL) {
        rightX = SCRW - uc3_getWidth(right, 0) - 10;
        uc3_drawText(right, rightX, y, 0, 0, 0, 0);
    }
}

/* 游戏绘制 */
void drawGame(void) {
    gl_clearScreen(200, 200, 200);
    uc3_drawText("游戏界面", 10, 10, 0, 0, 0, 0);
    drawSoftKeyHints(NULL, "返回");
    mrc_refreshScreen(0, 0, SCRW, SCRH);
}

/* 帮助绘制 */
void drawHelp(void) {
    gl_clearScreen(240, 240, 240);
    uc3_drawText("帮助信息", 10, 10, 0, 0, 0, 0);
    uc3_drawText("按右软键返回", 10, 40, 0, 0, 0, 0);
    drawSoftKeyHints("确认", "返回");
    mrc_refreshScreen(0, 0, SCRW, SCRH);
}

/* 事件分发 */
int32 mrc_event(int32 code, int32 param0, int32 param1) {
    if (currentWindow == WINDOW_MENU) {
        pmenu_event(&mainMenu, code, param0, param1);
    } else if (currentWindow == WINDOW_GAME) {
        if (code == KY_UP && param0 == _SRIGHT) {
            switchWindow(0, 0);
        }
    } else if (currentWindow == WINDOW_HELP) {
        if (code == KY_UP && param0 == _SRIGHT) {
            switchWindow(0, 0);
        }
    }
    return 0;
}

/* 初始化 */
int32 mrc_init(void) {
    currentWindow = WINDOW_MENU;
    uc3_init();
    pmenu_init(&mainMenu);
    pmenu_draw(&mainMenu);
    return 0;
}

/* 退出 */
int32 mrc_exitApp(void) {
    pmenu_free(&mainMenu);
    uc3_free();
    return 0;
}
```

---

## 十一、参考资料

- **平台API详细说明**:见 `程序编写说明.md`
- **常用函数速查**:
  - 图形:`gl_drawRect`, `gl_drawLine`, `gl_drawCir`, `drawBitmap`
  - 文字:`uc3_drawText`, `uc3_getWidth`
  - 系统:`mrc_exit`, `mrc_printf`, `mrc_refreshScreen`
  - 定时器:`mrc_timerCreate/Start/Stop/Delete`

---


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|幻蓝小站

GMT+8, 2026-7-10 22:42

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表