模仿星露谷物语的游戏开发实践
这是我大二下学期做的期末课设,用c++编写,是模仿星露谷做的一款游戏,我大概花了一个月时间写了五千多行代码,简单实现了星露谷的一些基本游戏功能。
全程个人开发,gpt辅助,做完之后真的有莫大的成就感。
先简单的放一个演示视频
一、项目功能简单介绍
这是以星露谷物语这一游戏为方向开发的游戏,此为一个像素风的RGB游戏,现已实现钓鱼,挖矿,打怪,玩家,背包,npc,时间,存档读档这八大系统。
1. 背包系统
a) 背包内的道具类型主要分为三大类:消耗品,装备,材料
b) 消耗/获取道具,道具可自动堆叠
c) 绘制背包页面,在左上角显示背包界面,显示各个已有道具图片和数量
d) 鼠标点击背包中的道具会显示高亮,表示现在持有
2. 钓鱼系统:
a) 拿着钓鱼竿道具左键则会进入钓鱼小游戏界面。
b) 通过玩家快速点击或长按实现“钓鱼条”的垂直移动
c) 鱼的行为AI:鱼会根据预设曲线垂直移动,鱼的速度与玩家钓鱼等级有关
d) 实时检测钓鱼条与鱼图标的碰撞(矩形或圆形碰撞检测),成功则填充捕获进度条。捕获进度条则钓鱼成功,在十种鱼里面随机选取一种进入背包。
3. 挖矿系统
a) 现在设置了四层矿洞,每次进入矿洞,矿石的种类和位置都会根据当前层数随机生成
b) 持有稿子道具靠近并点击对应矿石进行挖矿,此动作消耗矿石耐度条,矿石耐度条清零时,矿石消失,玩家根据玩家挖矿等级和矿石种类概率获得矿物
c) 挖矿动作消耗玩家耐力条,玩家耐力条清零时挖不了矿
4. 打怪系统
a) 在每层矿洞中都会出现怪物,每次进入矿洞时自动随机生成。每层的怪物机制和类型也不同,有些可以无视地形,有些可以发射光弹
b) 每层怪物的血量和攻击造成的伤害也不相同,怪物攻击玩家,玩家会扣除相应血量,玩家血量清零时,显示死亡界面,传送回家,并且能量条减半
c) 玩家拿着剑道具靠近怪物点击怪物,则会对怪物造成伤害,伤害量与玩家打怪等级有关
5. 玩家
a) 玩家UI包括血量和能量会以进度条的形式显示在屏幕右下角
b) 按下q键显示人物面板,包括人物打怪,钓鱼,挖矿技能的等级及经验条,它们颜色不同
c) 玩家在屏幕中随着地图移动会尽量显示在视觉中心
6. Npc系统
a) 游戏中加载了12个npc,可以给npc对话和送礼,左键对话右键送礼,当然送礼时需保证手中有物品
b) 对话和送礼时都会显示人物对话框和头像框
c) 人物好感界面,按g显示,左键翻面,人物好感不同,显示的颜色不同。对话和送礼都会加好感,送的礼物不同加的好感不同,讨厌的礼物会减好感。
7. 时间系统
a) 时间UI包括当前游戏中时间和季节图片会显示在屏幕右上角,不同季节显示的图片不同
b) 根据时间调整游戏内亮度
c) 凌晨两点必须睡觉,如果这个时间还在野外,会自动晕倒并掉落一定道具
d) 在自己加靠近床,按z键就能睡觉,睡觉则在当前挡位自动存档
8. 存档读档系统
a) 在首页可以选择创建存档或者读档,读取玩家,背包,npc,时间等一系列信息
b) 睡觉时自动在当前档位存档
二、程序的设计
总体设计结构
1. 背包系统
结构体
struct Item {
int id; // 道具唯一标识
HBITMAP icon; // 图标位图(正常尺寸)
HBITMAP icon1; // 备用图标(可能用于不同状态)
std::wstring name; // 道具名称(宽字符支持多语言)
int count; // 堆叠数量
int type; // 道具类型(ItemType枚举)
std::string resourcePath; // 资源文件路径(用于动态加载)
};
类图:
2. npc系统
结构体
class NPC {
string name; // NPC名称
int x, y; // 世界坐标位置
int friendship; // 好感度(0-100)
map<int, int> giftPreferences; // 礼物偏好表(物品ID->好感度增减值)
HBITMAP icon, icon2; // 行走图(不同状态)
HBITMAP portrait; // 对话头像
Direction dirnow; // 当前移动方向
int timel, time; // 移动计时器
AppState npcstate; // 所属游戏区域
int clos; // 行走图帧控制
};
类图:
NPC 核心类
plaintext
+---------------------+
| NPC |
+---------------------+
| - name: string |
| - friendship: int |
| - giftPreferences |
| - position(x,y) |
| - bitmap资源... |
+---------------------+
| + initnpc() |
| + moveRandomlyk() |
| + talk() |
| + giveGift() |
| + Save()/Load() |
+---------------------+
全局管理
plaintext
+---------------------+
| npcs全局 |
+---------------------+
| - vector<NPC> npcs |
| - initnpcs() |
| - npcsRender() |
| - HandleRightClick()|
+---------------------+
3. 挖矿系统
class MiningSystem {
public:
int mineLevel;//当前深度
int energyCost = 5;//挖掘能量消耗
std::vector<OreNode> oreNodes; // 存储当前地图的矿石节点}
4. 打怪系统
5. 钓鱼系统
6. 玩家系统
7. 存档读档系统
存档系统
存档选择页面:
8. 时间系统
类图
三、程序的实现过程
1. 挖矿系统
· 矿石生成流程
GenerateOres → 根据矿层深度计算矿石数量和稀有概率 → 生成 OreNode 并存储到 oreNodes。
· 挖掘流程
TryMine → 检测玩家坐标与 OreNode 的碰撞 → 扣除耐久度 → 耐久度为 0 时生成对应 OreType → 调用 AddOreToInventory 存入背包。
· 渲染流程
RenderOres → 遍历 oreNodes → 根据 OreSType 选择对应的纹理 → 世界坐标转屏幕坐标后绘制到窗口。
· 层级提升流程
DescendToNextLevel → 调用 IncreaseLevel 提升矿层 → 重新调用 GenerateOres 生成新层矿石。
2. 打怪系统
· 怪物生成流程
GenerateMonster → 根据等级计算怪物数量 → 随机生成坐标并校验有效性 → 设置怪物属性(类型、生命值、掉落物等)→ 加入 monsters 列表。
· 怪物移动流程
MoveMonster → 遍历 monsters → 根据类型调用 UpdateMonsterPosition(受地形阻挡)或 UpdateMonsterPositionignore(无视地形)→ 更新坐标和朝向 → 渲染动画。
· 攻击流程
· 怪物攻击:UpdateAttrack 生成攻击光球并移动 → MonsterAttact 检测光球或怪物是否与玩家碰撞 → 返回伤害值。
· 玩家攻击:AttackMonster 检测玩家攻击范围是否命中怪物 → 扣除生命值 → 生命值为 0 时掉落物品并添加到背包(Inventory 类)。
· 等级提升流程
IncreaseLevel → 提升 monsterLevel → 重新生成更高等级的怪物(需手动调用,如玩家进入新关卡)。
3. 钓鱼系统
· 玩家操作:
· 按住空格键:控制条上移(速度 10 像素 / 帧)
· 松开空格键:控制条下移(速度 20 像素 / 帧)
· 成功判定:
· 控制条覆盖鱼的位置时,successCount增加
· 否则减少
· 当successCount达到 50 时,游戏成功,随机生成一种鱼并添加到背包
· 当successCount低于 - 30 时,游戏失败
与其他系统的关联
与Inventory的交互:
inventory.AddItem(fishs);
钓鱼成功后,创建一个Item对象并添加到玩家背包。
与游戏状态的交互:
游戏结束后,重置游戏状态为NOTALL。
4. 玩家系统
与其他系统的交互
1. 与 MiningSystem 的关联:
player.UseTool(x, y, miningSystem, inventory);
·
调用挖矿系统的 TryMine 方法进行矿石挖掘。
· 与 CombatSystem 的关联:
player.TakeDamage(x, y); // 调用战斗系统的 MonsterAttact
player.UseTool(x, y, ...); // 调用战斗系统的 AttackMonster
·
处理玩家受到的伤害和对怪物的攻击。
· 与 Inventory 的关联:
player.AddToInventory(item);
·
将物品添加到背包系统。
· 与 Fishing.h 的关联:
通过 fishingLevel 和 fishingEXP 影响钓鱼小游戏的难度和奖励。
5. 存档读档系统
6. 时间系统
7. 背包系统
8. Npc系统
Npc移动逻辑
· 对话系统:
随机显示预设的对话内容,增加 1 点好感度。
· 送礼系统:
根据物品喜好度调整好感度(-5 到 5),最大好感度为 100。
好感度系统
四、程序的运行结果
主页:
创建页面:
读档页面
地图:
家:
农场:
车站:
小镇
森林:
海边:
矿场:
小路:
矿洞:
矿层1:
矿层2:
矿层3:
矿层4:
时间系统
睡觉:
半夜不睡觉,在野外会随机掉落物品
打怪系统:
死亡界面
Npc系统:
交互界面
Npc好感界面:
钓鱼系统:
玩家系统:
五、总结与心得
通过对系列代码文件的分析,深入理解了游戏开发中核心系统的设计逻辑与实现方式,以下从技术实现、系统设计、优化方向三方面总结体会:
一、技术实现:模块化与 Windows API 的结合
1. 数据持久化与二进制操作
o 通过GameSaveManager实现存档系统,利用二进制读写(ofstream/ifstream)保存玩家、背包、时间、NPC 等数据,版本号机制为后续兼容性扩展奠定基础。
o 关键点:存档时需注意数据顺序与类型匹配(如reinterpret_cast的正确使用),避免读档时出现解析错误。
2. Windows 图形界面开发
o 使用 GDI + 绘制 UI 元素(如RoundRect绘制圆角矩形、BitBlt渲染位图),通过HDC和双缓冲技术(bufdc/mdc)实现界面平滑刷新,减少闪烁。
o 资源加载(如LoadImage)需处理路径转换(string转wstring)和错误处理,避免程序崩溃。
3. 状态机与交互逻辑
o 通过枚举(Direction、AppState)管理 NPC 移动方向和场景状态,结合随机算法(rand())实现 NPC 随机移动与转向,增强真实感。
o 交互处理:鼠标点击检测(PtInRect)与键盘事件(GetAsyncKeyState)分离,确保交互响应的准确性。
二、系统设计:功能解耦与数据驱动
1. 核心系统模块化
o 将游戏拆分为存档(GameSaveManager)、时间(TimeSystem)、背包(Inventory)、NPC 等模块,各模块通过头文件依赖实现低耦合。
o 示例:Inventory类封装物品管理、UI 绘制和数据持久化,通过AddItem/RemoveItem接口与其他模块交互。
2. 面向对象设计实践
o NPC类封装角色属性(位置、好感度)、行为(移动、对话、送礼)和资源(头像、图像),通过虚函数或纯虚函数预留扩展点(如未来可派生特殊 NPC)。
o 不足:部分全局变量(如npcs、inventory)可能导致命名空间污染,可考虑单例模式或管理器类封装。
3. UI 与逻辑分离
o SaveLoadUI和TimeUI类负责界面渲染,逻辑层(如GameSaveManager)处理数据操作,符合 MVC 设计思想。
o 优化点:UI 绘制中重复代码(如按钮边框、文本渲染)可提取为公共函数,减少冗余。
三、优化方向:性能、扩展与体验
1. 性能优化
o 资源管理:未释放的HBITMAP等 GDI 对象可能导致内存泄漏,需在析构函数中调用DeleteObject。
o 碰撞检测:NPC 移动时的场景合法性检查(CanMoveToz等)可结合空间索引(如网格划分)提升效率。
2. 功能扩展
o 内容丰富性:当前 NPC 对话和礼物偏好较为简单,可增加对话树(根据好感度分支)、节日事件、特殊物品交互等。
o 系统联动:时间系统(TimeSystem)可影响 NPC 日程(如夜晚回家)、物品出现概率(如季节限定鱼类)。
3. 用户体验
o 反馈机制:送礼后增加音效或视觉反馈(如粒子效果),提升交互沉浸感。
o 界面优化:背包格子支持拖拽排序、好感度面板添加搜索功能,减少用户操作成本。
总结:从代码到游戏的系统性思维
通过分析这些代码,体会到游戏开发需平衡功能实现与架构设计:
· 技术层面:熟练掌握 Windows API、文件操作和图形渲染是基础,需注意资源管理与错误处理。
· 设计层面:模块化、面向对象和状态机设计能提升代码可维护性,数据驱动(如配置文件)可降低内容扩展成本。
· 迭代思维:当前代码在性能、体验和内容上仍有优化空间,需通过测试和用户反馈持续改进。