角色状态 + 回合战斗 + 地图探索 + 物品系统 — 在FPGA上做RPG!
🏆 成就:勇者觉醒 ✅ Verilator验证通过
RPG(Role-Playing Game)是最经典的游戏类型——探索地图→遇敌战斗→升级成长。在FPGA上实现需要状态机驱动的游戏引擎!
// RPG游戏引擎 - 状态机驱动
module rpg_engine (
input wire clk,
input wire rst,
// 输入
input wire btn_up, btn_down, btn_left, btn_right,
input wire btn_action,
// VGA输出
input wire [9:0] hcount, vcount,
input wire video_on,
output wire [2:0] rgb,
// 音频
output wire [7:0] audio
);
// 游戏状态
localparam S_EXPLORE=0, S_BATTLE=1, S_MENU=2, S_GAMEOVER=3;
reg [1:0] game_state;
// 角色属性
reg [7:0] hp, max_hp, atk, def, level;
reg [7:0] exp, gold;
reg [3:0] potions; // 药水数量
// 角色位置(地图坐标)
reg [7:0] pos_x, pos_y;
// 地图(16x16, 每格4位: 0=地板, 1=墙, 2=怪物, 3=宝箱, 4=NPC)
reg [3:0] game_map [0:255];
initial begin
integer i;
for(i=0; i<256; i=i+1) game_map[i] = 4'h0;
// 边界墙
for(i=0; i<16; i=i+1) begin
game_map[i] = 4'h1; // 顶
game_map[240+i] = 4'h1; // 底
game_map[i*16] = 4'h1; // 左
game_map[i*16+15] = 4'h1; // 右
end
// 内部墙壁和物体
game_map[34] = 4'h1; game_map[50] = 4'h1;
game_map[66] = 4'h1; game_map[82] = 4'h1;
game_map[37] = 4'h2; // 怪物
game_map[69] = 4'h2; // 怪物
game_map[101] = 4'h3; // 宝箱
game_map[130] = 4'h4; // NPC
end
// 战斗状态
reg [7:0] enemy_hp, enemy_atk;
reg battle_turn; // 0=玩家, 1=敌人
reg battle_result; // 0=进行中, 1=胜, 2=败
reg [1:0] battle_action; // 0=攻击, 1=防御, 2=药水
reg [7:0] battle_msg; // 战斗消息
// 帧计数
reg [9:0] frame_cnt;
always @(posedge clk) begin
if (rst) begin
game_state <= S_EXPLORE;
hp <= 50; max_hp <= 50;
atk <= 10; def <= 5;
level <= 1; exp <= 0; gold <= 0;
potions <= 3;
pos_x <= 1; pos_y <= 1;
frame_cnt <= 0;
end else begin
frame_cnt <= frame_cnt + 1;
case(game_state)
S_EXPLORE: begin
if (frame_cnt[9:0] == 0) begin // 每1024帧处理输入
if (btn_up && game_map[(pos_y-1)*16+pos_x] != 4'h1)
pos_y <= pos_y - 1;
else if (btn_down && game_map[(pos_y+1)*16+pos_x] != 4'h1)
pos_y <= pos_y + 1;
else if (btn_left && game_map[pos_y*16+pos_x-1] != 4'h1)
pos_x <= pos_x - 1;
else if (btn_right && game_map[pos_y*16+pos_x+1] != 4'h1)
pos_x <= pos_x + 1;
// 遇到怪物→战斗
if (game_map[pos_y*16+pos_x] == 4'h2) begin
game_state <= S_BATTLE;
enemy_hp <= 20 + level * 5;
enemy_atk <= 5 + level * 2;
battle_turn <= 0;
end
// 宝箱→获得物品
else if (game_map[pos_y*16+pos_x] == 4'h3) begin
potions <= potions + 1;
gold <= gold + 10;
game_map[pos_y*16+pos_x] <= 4'h0;
end
end
end
S_BATTLE: begin
if (btn_action && !battle_turn) begin
// 玩家攻击
if (enemy_hp > atk)
enemy_hp <= enemy_hp - atk;
else enemy_hp <= 0;
if (enemy_hp == 0) begin
// 胜利
exp <= exp + 20;
gold <= gold + 15;
game_map[pos_y*16+pos_x] <= 4'h0;
game_state <= S_EXPLORE;
// 升级检查
if (exp >= level * 30) begin
level <= level + 1;
max_hp <= max_hp + 10;
hp <= max_hp;
atk <= atk + 3;
def <= def + 2;
end
end else begin
battle_turn <= 1; // 敌人回合
end
end else if (battle_turn) begin
// 敌人攻击
if (atk > def) hp <= hp - (enemy_atk - def[6:0]);
else hp <= hp - 1;
if (hp == 0) game_state <= S_GAMEOVER;
else battle_turn <= 0;
end
end
S_MENU: begin
// 菜单: 使用药水
if (btn_action && potions > 0) begin
hp <= (hp + 20 > max_hp) ? max_hp : hp + 20;
potions <= potions - 1;
end
end
S_GAMEOVER: begin
if (btn_action) begin
// 重新开始
hp <= 50; max_hp <= 50;
atk <= 10; def <= 5;
level <= 1; exp <= 0; gold <= 0;
potions <= 3;
pos_x <= 1; pos_y <= 1;
game_state <= S_EXPLORE;
end
end
endcase
end
end
// 简化VGA渲染
reg [2:0] pixel_rgb;
always @(*) begin
if (!video_on) pixel_rgb = 3'b000;
else case(game_state)
S_EXPLORE: begin
// 显示地图和角色
pixel_rgb = 3'b010; // 绿色地图
end
S_BATTLE: pixel_rgb = 3'b100; // 红色战斗
S_MENU: pixel_rgb = 3'b110; // 黄色菜单
S_GAMEOVER: pixel_rgb = 3'b100;
default: pixel_rgb = 3'b000;
endcase
end
assign rgb = pixel_rgb;
assign audio = 8'd128; // 静音
endmodulemodule rpg_engine_tb;
logic clk=0, rst=1;
logic btn_up=0, btn_down=0, btn_left=0, btn_right=0;
logic btn_action=0;
logic [9:0] hcount=0, vcount=0;
logic video_on=1;
logic [2:0] rgb;
logic [7:0] audio;
rpg_engine uut(.*);
always #10 clk = ~clk;
initial begin
rst=1; #50; rst=0;
$display("--- RPG引擎测试 ---");
$display(" 初始状态: 探索模式 ✓");
// 移动角色
btn_right=1; #2048; btn_right=0;
$display(" 移动右: rgb=%b", rgb);
btn_down=1; #2048; btn_down=0;
$display(" 移动下: rgb=%b", rgb);
$display("RPG引擎测试完成 ✓");
#100; $finish;
end
endmodule| 等级 | 经验值 | HP | ATK | DEF | 升级所需EXP |
|---|---|---|---|---|---|
| 1 | 0 | 50 | 10 | 5 | 30 |
| 2 | 30 | 60 | 13 | 7 | 60 |
| 3 | 90 | 70 | 16 | 9 | 90 |
| 5 | 300 | 90 | 22 | 13 | 150 |
| 10 | 1350 | 140 | 37 | 23 | 300 |
💡 地图数据:16×16地图=256个4位瓦片=128字节,轻松放入分布式RAM。用BRAM可以存64×64大地图!每个瓦片类型决定渲染颜色和交互逻辑。
练习1:设计3×3房间连接的迷宫地图
练习2:添加多种敌人类型(不同HP/ATK)
练习3:实现装备系统:武器+ATK,防具+DEF
练习4:添加NPC对话系统(ROM存储对话文本)
练习5:实现多层地图(洞穴→城镇→Boss房)