# 呆鸟修仙 游戏系统

本文档详细说明游戏系统的核心玩法、关卡机制和数据逻辑。
## 功能概述
游戏系统是呆鸟修仙的核心玩法,玩家控制小鸟收集灵气球、躲避敌人,通过关卡提升境界。
## 游戏架构
### 核心要素
1. **关卡系统** - 30个关卡,跨越10个修仙境界
2. **灵气收集** - 收集灵气球获得分数和成长
3. **敌人机制** - 躲避不同类型的敌人
4. **境界系统** - 通过关卡提升修仙境界
5. **体型系统** - 收集灵气球增加体型,撞击敌人减少体型
6. **排行榜** - 基于累计灵气值的排行榜
### 境界系统
| 境界 | 关卡范围 | 鸟皮肤 | 特点 |
|------|---------|--------|------|
| 练气期 | 1-3 | public/assets/bird-realms/bird_zjq_01.png | 基础境界 |
| 练气期 | 4-6 | public/assets/bird-realms/bird_zjq_02.png | 开启打坐冥想 |
| 练气期 | 7-9 | public/assets/bird-realms/bird_zjq_03.png | 道心初成 |
| 练气期 | 10-12 | public/assets/bird-realms/bird_zjq_04.png | 元神出窍 |
| 练气期 | 13-15 | public/assets/bird-realms/bird_zjq_05.png | 神识外放 |
| 练气期 | 16-18 | public/assets/bird-realms/bird_zjq_06.png | 虚空炼化 |
| 练气期 | 19-21 | public/assets/bird-realms/bird_zjq_07.png | 身魂合一 |
| 练气期 | 22-24 | public/assets/bird-realms/bird_zjq_08.png | 法力无边 |
| 练气期 | 25-27 | public/assets/bird-realms/bird_zjq_09.png | 天雷淬炼 |
| 练气期 | 28-30 | public/assets/bird-realms/bird_zjq_10.png | 飞升成仙 |
## 数据库表结构
### game_records 表
**字段说明**:
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | varchar(36) | PRIMARY KEY | 记录UUID |
| user_id | varchar(36) | NOT NULL | 用户ID |
| level | int | NOT NULL | 关卡编号 |
| score | int | NOT NULL | 本次得分 |
| realm | varchar(50) | NOT NULL | 所属境界 |
| play_time | int | NOT NULL | 游戏时长(秒) |
| created_at | timestamp | DEFAULT NOW() | 游戏时间 |
**索引**:
- `game_records_user_idx`: user_id
- `game_records_score_idx`: score(用于排行榜)
### level_configs 表
**字段说明**:
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | varchar(36) | PRIMARY KEY | 配置UUID |
| level | int | UNIQUE, NOT NULL | 关卡编号 |
| realm | varchar(50) | NOT NULL | 所属境界 |
| game_mode | varchar(20) | NOT NULL | 游戏模式 |
| target_score | int | NOT NULL | 目标分数 |
| is_open | boolean | DEFAULT true | 关卡是否开放 |
| spirit_interval | int | DEFAULT 1000 | 灵气生成间隔(毫秒) |
| spirit_max_count | int | DEFAULT 8 | 灵气最大数量 |
| spirit_life_time | int | DEFAULT 15000 | 灵气生命周期(毫秒) |
| enemy_count | int | DEFAULT 2 | 敌人数量 |
| enemy_speed_multiplier | int | DEFAULT 100 | 敌人速度倍率 |
| enemy_tracking_strength | int | DEFAULT 0 | 追踪强度(0-100) |
| enemy_types | jsonb | NOT NULL | 敌人种类配置 |
| player_max_lives | int | DEFAULT 5 | 主角最大生命值 |
| player_speed_multiplier | int | DEFAULT 100 | 主角速度倍率 |
| player_size_multiplier | int | DEFAULT 100 | 主角大小倍率 |
| bird_size_growth_rate | int | DEFAULT 8 | 收集灵气球增加体型百分比 |
| bird_size_shrink_rate | int | DEFAULT 20 | 撞击敌人减少体型百分比 |
| bird_max_size | int | DEFAULT 330 | 最大体型百分比 |
## 游戏模式
### 1. 经典模式 (classic)
**目标**: 收集灵气球,达到目标分数
**特点**:
- 无生命值限制
- 体型成长机制
- 累计灵气值
### 2. 生存模式 (survival)
**目标**: 尽可能长时间生存
**特点**:
- 生命值机制
- 敌人逐渐增强
- 难度递增
### 3. 挑战模式 (challenge)
**目标**: 在限定时间内达到目标
**特点**:
- 时间限制
- 高难度
- 特殊奖励
## 游戏机制
### 灵气收集
**灵气球属性**:
- **分值**: 1-50分(根据稀有度)
- **稀有度**: common, rare, epic, legendary
- **颜色**: 不同稀有度对应不同颜色
- **生命周期**: 15秒后消失
- **移动轨迹**: 左右飘动 + 上下浮动
**收集效果**:
```typescript
// 增加分数
setScore((s) => s + spirit.points);
// 增加体型(根据关卡配置)
setBirdSize(prev => {
const newSize = prev + birdSizeGrowthRate;
const maxSize = 330;
return Math.min(newSize, maxSize);
});
// 增加灵气收集数量
setCollectedSpiritsCount(prev => prev + 1);
```
**稀有度概率**:
- 普通 (common): 60% - 1-10分
- 稀有 (rare): 25% - 11-30分
- 史诗 (epic): 12% - 31-40分
- 传说 (legendary): 3% - 41-50分
### 敌人机制
**敌人属性**:
- **速度**: 基础速度 × 速度倍率
- **追踪强度**: 0-100(100为完全追踪)
- **碰撞伤害**: 减少体型
- **生命值**: 多次撞击后消失
**敌人类型**:
```typescript
interface EnemyType {
emoji: string;
name: string;
health: number;
speed: number;
tracking: number;
}
```
**碰撞效果**:
```typescript
// 减少体型(根据关卡配置)
setBirdSize(prev => {
const newSize = prev - birdSizeShrinkRate;
const minSize = 20;
return Math.max(newSize, minSize);
});
// 减少生命值(如果启用)
setLives((l) => l - 1);
```
### 体型系统
**体型范围**: 20% - 150%
**成长规则**:
- 收集灵气球:+8%(可配置)
- 撞击敌人:-20%(可配置)
**体型效果**:
- 视觉变大
- 颜色变金(体型越大越金)
- 收集范围变大
**境界影响**:
```typescript
const realmFlapBonus = {
"练气期": 0,
"筑基期": 0.02,
"金丹期": 0.03,
// ... 境界越高,扇动越有力量
};
```
### 生命值系统
**初始生命值**: 5(可配置)
**生命值归零**:
- 游戏结束
- 记录分数
- 保存到数据库
- 返回菜单
### 控制方式
#### 支持的输入方式
游戏支持以下两种控制方式:
1. **鼠标控制** - 适用于桌面端
2. **触屏控制** - 适用于移动端
#### 鼠标控制
**操作方式**:
- 移动鼠标:小鸟会跟随鼠标位置移动
- 控制灵敏度:鼠标移动的位移 × 0.6
- 最大速度限制:基础速度 × 2.5
**关键代码** (src/app/page.tsx):
```typescript
// 鼠标移动事件处理
const handleMouseMove = (e: MouseEvent) => {
if (gameState !== 'playing') return;
const canvas = canvasRef.current;
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 计算位移增量(灵敏度 0.6)
const deltaX = (x - bird.x) * 0.6;
const deltaY = (y - bird.y) * 0.6;
// 限制最大增量(2.5倍基础速度)
const maxDelta = 2.5 * bird.baseSpeed;
const clampedDeltaX = Math.max(-maxDelta, Math.min(maxDelta, deltaX));
const clampedDeltaY = Math.max(-maxDelta, Math.min(maxDelta, deltaY));
// 更新小鸟位置
setBird({
...bird,
x: bird.x + clampedDeltaX,
y: bird.y + clampedDeltaY
});
};
```
**注意事项**:
- 确保背景图片不拦截鼠标事件
```typescript
// 为背景图片添加样式
style={{ pointerEvents: 'none' }}
```
#### 触屏控制
**操作方式**:
- 手指触摸:小鸟会跟随触摸点移动
- 多点触控:支持多点触控(取最后触摸点)
- 控制灵敏度:触摸移动的位移 × 0.6
- 最大速度限制:基础速度 × 2.5
**关键代码** (src/app/page.tsx):
```typescript
// 触摸开始事件
const handleTouchStart = (e: React.TouchEvent) => {
e.preventDefault();
if (gameState !== 'playing') return;
const canvas = canvasRef.current;
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const touch = e.touches[0];
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
// 更新触摸位置
setTouchPosition({ x, y });
};
// 触摸移动事件
const handleTouchMove = (e: React.TouchEvent) => {
e.preventDefault();
if (gameState !== 'playing') return;
const canvas = canvasRef.current;
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const touch = e.touches[0];
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
// 计算位移增量(灵敏度 0.6)
const deltaX = (x - bird.x) * 0.6;
const deltaY = (y - bird.y) * 0.6;
// 限制最大增量(2.5倍基础速度)
const maxDelta = 2.5 * bird.baseSpeed;
const clampedDeltaX = Math.max(-maxDelta, Math.min(maxDelta, deltaX));
const clampedDeltaY = Math.max(-maxDelta, Math.min(maxDelta, deltaY));
// 更新小鸟位置
setBird({
...bird,
x: bird.x + clampedDeltaX,
y: bird.y + clampedDeltaY
});
setTouchPosition({ x, y });
};
```
**注意事项**:
- 添加 `e.preventDefault()` 防止页面滚动
- 使用 `touch` 事件而非 `click` 事件以获得更好的响应速度
- 支持 `touchstart`、`touchmove`、`touchend` 事件
#### 控制灵敏度参数
**可调参数** (src/data/LevelConfig.ts):
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `MOUSE_CONTROL_MULTIPLIER` | 0.6 | 鼠标/触屏控制灵敏度倍率 |
| `MAX_CONTROL_MULTIPLIER` | 2.5 | 最大速度倍率(相对于基础速度) |
| `BIRD_BASE_SPEED` | 3.5 | 小鸟基础速度(像素/帧) |
| `BIRD_MAX_SPEED` | 5.5 | 小鸟最大速度(像素/帧) |
**调整建议**:
- **更灵敏的控制**:增大 `MOUSE_CONTROL_MULTIPLIER`(0.6 → 0.8)
- **更平滑的控制**:减小 `MOUSE_CONTROL_MULTIPLIER`(0.6 → 0.4)
- **更快的飞行**:增大 `BIRD_BASE_SPEED`(3.5 → 5)
- **更慢的飞行**:减小 `BIRD_BASE_SPEED`(3.5 → 2)
**配置示例** (src/data/LevelConfig.ts):
```typescript
export const GAME_CONFIG = {
// 控制灵敏度
MOUSE_CONTROL_MULTIPLIER: 0.6, // 鼠标/触屏控制倍率
MAX_CONTROL_MULTIPLIER: 2.5, // 最大控制倍率
// 飞行速度
BIRD_BASE_SPEED: 3.5, // 基础速度(像素/帧)
BIRD_MAX_SPEED: 5.5, // 最大速度(像素/帧)
SPEED_INCREMENT_PER_LEVEL: 0.04, // 每关卡速度增量
// ... 其他配置
};
```
#### 控制最佳实践
**优化建议**:
1. **防止背景遮挡**:确保背景图片不拦截鼠标事件
```tsx
<div
style={{
backgroundImage: `url(${bgImage})`,
pointerEvents: 'none' // 关键:防止拦截鼠标事件
}}
/>
```
2. **响应式适配**:确保 Canvas 尺寸正确适配不同设备
```typescript
// 获取 Canvas 尺寸
const rect = canvas.getBoundingClientRect();
// 计算触摸/鼠标在 Canvas 内的相对坐标
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
```
3. **边界检测**:防止小鸟移出 Canvas 边界
```typescript
// 限制 X 轴范围
bird.x = Math.max(birdSize, Math.min(canvasWidth - birdSize, bird.x));
// 限制 Y 轴范围
bird.y = Math.max(birdSize, Math.min(canvasHeight - birdSize, bird.y));
```
4. **性能优化**:使用 `requestAnimationFrame` 优化渲染
```typescript
// 在游戏循环中使用
useEffect(() => {
let animationFrameId: number;
const gameLoop = () => {
// 更新小鸟位置
// 更新灵气球位置
// 检测碰撞
// 绘制画面
animationFrameId = requestAnimationFrame(gameLoop);
};
if (gameState === 'playing') {
gameLoop();
}
return () => cancelAnimationFrame(animationFrameId);
}, [gameState, ...]);
```
#### 常见问题
**Q1: 鼠标控制没反应?**
A: 检查以下几点:
1. 确保游戏状态为 `playing`
2. 检查背景图片是否拦截了鼠标事件(添加 `pointerEvents: 'none'`)
3. 确认 Canvas 是否正确挂载
4. 检查浏览器控制台是否有错误
**Q2: 触屏控制不流畅?**
A: 优化建议:
1. 使用 `e.preventDefault()` 防止页面滚动
2. 增大 `MOUSE_CONTROL_MULTIPLIER` 提升灵敏度
3. 使用 `touch` 事件而非 `click` 事件
4. 确保没有其他元素拦截触摸事件
**Q3: 如何调整控制灵敏度?**
A: 修改 `GAME_CONFIG` 中的参数:
```typescript
// 更灵敏:增大倍率
MOUSE_CONTROL_MULTIPLIER: 0.8, // 从 0.6 增加到 0.8
// 更平滑:减小倍率
MOUSE_CONTROL_MULTIPLIER: 0.4, // 从 0.6 减少到 0.4
```
**Q4: 小鸟飞得太快了?**
A: 降低基础速度:
```typescript
// 降低飞行速度
BIRD_BASE_SPEED: 2.5, // 从 3.5 降低到 2.5
BIRD_MAX_SPEED: 4.0, // 从 5.5 降低到 4.0
```
#### 相关代码位置
**主要实现文件**:
- **游戏主逻辑**: `src/app/page.tsx` (约 2000-2200 行)
- **关卡配置**: `src/data/LevelConfig.ts`
- **境界配置**: `src/data/RealmConfig.ts`
**关键函数**:
- `handleMouseMove()` - 鼠标移动处理
- `handleTouchStart()` - 触摸开始处理
- `handleTouchMove()` - 触摸移动处理
- `handleTouchEnd()` - 触摸结束处理
**历史优化记录**:
- 2026-01-19: 添加鼠标和触屏控制支持
- 2026-01-19: 修复背景图片拦截鼠标事件问题
- 2026-01-19: 提升控制灵敏度(0.35 → 0.6)
- 2026-01-19: 降低飞行速度(5 → 3.5)
## 关卡设计
### 关卡配置
**文件**: `src/data/LevelConfig.ts`
```typescript
export interface LevelConfig {
level: number;
realm: string;
gameMode: "classic" | "survival" | "challenge";
targetScore: number;
isOpen: boolean;
// ... 更多配置
}
export const LEVELS: LevelConfig[] = [
{
level: 1,
realm: "练气期",
gameMode: "classic",
targetScore: 100,
isOpen: true,
spiritInterval: 1000,
spiritMaxCount: 5,
enemyCount: 1,
// ...
},
// ... 30个关卡
];
```
### 关卡进度
**保存逻辑**:
```typescript
// 游戏结束时
if (score > user.maxScore) {
await updateUser(user.id, { maxScore: score });
}
if (level > user.maxLevel) {
await updateUser(user.id, { maxLevel: level });
}
// 保存游戏记录
await db.insert(gameRecords).values({
userId: user.id,
level: level,
score: score,
realm: realm,
playTime: playTime,
});
// 更新累计灵气值(排行榜使用)
await db.execute(sql`
UPDATE users
SET total_score = total_score + ${score}
WHERE id = ${userId}
`);
```
## 排行榜系统
### 排行榜类型
1. **好友排行榜** - 仅显示好友
2. **全服排行榜** - 显示所有玩家
3. **本周排行榜** - 按本周分数排名
4. **历史排行榜** - 按累计分数排名
### 排行榜查询
**SQL查询**:
```sql
-- 全服排行榜(按累计灵气值)
SELECT
u.id,
u.username,
u.max_score,
u.total_score,
u.max_level,
u.avatar
FROM users u
WHERE u.is_disabled = false
ORDER BY u.total_score DESC
LIMIT 100;
-- 好友排行榜
SELECT
u.*,
f.created_at as friendship_date
FROM users u
JOIN friendships f ON u.id = f.friend_id
WHERE f.user_id = ? AND f.status = 'accepted'
ORDER BY u.total_score DESC
LIMIT 50;
```
### 排行榜更新
**实时更新**:
- 游戏结束时立即更新
- 使用缓存优化查询
- 定时刷新全服排行榜(每小时)
## API接口
### 1. 保存游戏记录
**接口**: `POST /api/game/save-record`
**请求参数**:
```json
{
"userId": "uuid",
"level": 5,
"score": 150,
"realm": "金丹期",
"playTime": 120
}
```
**响应示例**:
```json
{
"success": true,
"newMaxScore": true,
"newMaxLevel": false,
"totalScore": 150
}
```
### 2. 获取排行榜
**接口**: `GET /api/game/leaderboard`
**查询参数**:
- `type`: all/friends/weekly
- `page`: 页码
- `limit`: 每页数量
**响应示例**:
```json
{
"success": true,
"type": "all",
"rankings": [
{
"rank": 1,
"username": "玩家A",
"totalScore": 50000,
"maxLevel": 15,
"avatar": "🦅"
}
],
"myRank": 10,
"total": 1000
}
```
### 3. 获取关卡配置
**接口**: `GET /api/game/level/:id`
**响应示例**:
```json
{
"success": true,
"level": {
"level": 1,
"realm": "练气期",
"gameMode": "classic",
"targetScore": 100,
"spiritInterval": 1000,
"enemyCount": 1
}
}
```
## 关键代码位置
### 游戏主循环
**文件**: `src/app/page.tsx`
```typescript
// 游戏循环(约2000-2200行)
useEffect(() => {
const gameLoop = setInterval(() => {
// 更新小鸟位置
// 更新灵气球位置
// 检测碰撞
// 检测游戏结束
// 绘制画面
}, 1000 / 60); // 60 FPS
return () => clearInterval(gameLoop);
}, [gameState, ...]);
```
### 关卡配置
**文件**: `src/data/LevelConfig.ts`
```typescript
export const LEVELS: LevelConfig[] = [
// 30个关卡配置
];
export const GAME_CONFIG = {
canvasWidth: 400,
canvasHeight: 600,
birdSize: 50,
// ... 全局配置
};
```
### 境界配置
**文件**: `src/data/RealmConfig.ts`
```typescript
export const REALM_CONFIG: Record<string, RealmConfig> = {
"练气期": { birdEmoji: "🐦", birdSkin: "/birds/bird_01.png", ... },
"筑基期": { birdEmoji: "🦅", birdSkin: "/birds/bird_02.png", ... },
// ... 10个境界
};
```
## 扩展功能建议
### 1. 成就系统
- 首次通关关卡
- 收集特定数量灵气
- 连续收集奖励
- 境界里程碑
### 2. 每日挑战
- 每日关卡
- 特殊规则
- 额外奖励
### 3. 多人对战
- 实时对战
- 排位系统
- 战队模式
### 4. 道具系统
- 护盾(无敌)
- 速度提升
- 体型增大
- 时间冻结
### 5. 剧情模式
- 境界剧情
- NPC对话
- 任务系统
## 性能优化
### 渲染优化
- 使用 Canvas API
- 限制最大灵气球数量
- 对象池复用
- 帧率控制(60 FPS)
### 数据库优化
- 游戏记录索引优化
- 排行榜缓存
- 批量保存记录
- 定时清理旧数据
## 常见问题
### Q1: 为什么游戏结束后分数没有增加?
A: 检查以下几点:
1. 游戏是否正常结束(生命值归零)
2. API调用是否成功
3. 数据库连接是否正常
4. 查看浏览器控制台错误
### Q2: 如何调整游戏难度?
A: 修改 `LevelConfig.ts` 中的关卡配置:
- `enemyCount`: 敌人数量
- `enemySpeedMultiplier`: 敌人速度
- `birdSizeShrinkRate`: 体型减少幅度
- `spiritInterval`: 灵气生成间隔
### Q3: 排行榜多久更新一次?
A: 当前为实时更新,建议优化:
- 好友排行榜:实时
- 全服排行榜:每小时
- 本周排行榜:每日重置
### Q4: 体型过大如何处理?
A: 限制最大体型为130% ,如果需要:
- 添加体型上限配置
- 体型过大时触发特殊效果
- 体型影响收集范围
## 维护记录
- 2026-01-19: 完善游戏系统文档
- 2026-01-19: 排行榜改为按累计灵气值排序
- 2026-01-19: 游戏结束自动累加灵气值
