当前位置: 首页 > news >正文

从零开发游戏需要学习的c#模块,第十五章(一个完整的可以运行的小游戏)

这是这个系列的最后一课,如果你认真学习了之前的内容,关于c#游戏开发要学习的代码就差不多了。今天我们来进行最后的收尾,往我们之前的代码中加入一个开幕界面,保证保存和加载内容正常运行。

只用修改game.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading;

namespace MyGame
{
class Game
{
private static Game? instance;
public static Game Instance
{
get
{
if (instance == null)
instance = new Game();
return instance;
}
}

private Game() { }

private bool isRunning;
private Player player = default!;
private GameMap map = default!;
private InputHandler input = default!;
private GameUI ui = default!;
private BattleManager battleManager = default!;

private List<Coin> coins = default!;
private int score;
private int totalCoins = 5;

private List<Enemy> enemies = default!;
private int totalEnemies = 3;

private Inventory inventory = default!;
private AchievementSystem achievement = default!;
private SoundSystem sound = default!;

private string saveFilePath = "gamesave.json";

// ===== ★ 入口 =====
public void Start()
{
Console.CursorVisible = false;
Console.Title = "控制台RPG";

// 显示主菜单
ShowMainMenu();
}

// ===== ★ 主菜单 =====
private void ShowMainMenu()
{
Console.Clear();
string title = @"
╔══════════════════════════╗
║ 🗡️ 控制台 RPG 🛡️ ║
╚══════════════════════════╝
";

Console.WriteLine(title);
Console.WriteLine(" [1] 新游戏");
Console.WriteLine(" [2] 继续游戏");
Console.WriteLine(" [3] 退出");
Console.Write("\n 请选择:");

bool hasSave = File.Exists(saveFilePath);
if (hasSave)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\n 📁 检测到存档文件");
Console.ResetColor();
}

while (true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.KeyChar)
{
case '1':
NewGame();
return;
case '2':
if (hasSave)
{
LoadAndStart();
return;
}
else
{
Console.SetCursorPosition(0, 9);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(" 没有存档文件!按任意键返回...");
Console.ResetColor();
Console.ReadKey(true);
ShowMainMenu();
return;
}
case '3':
return; // 直接退出程序
}
}
Thread.Sleep(30);
}
}

// ===== ★ 新游戏 =====
private void NewGame()
{
Console.Clear();
Console.Write("请输入你的名字:");
string name = Console.ReadLine();
if (string.IsNullOrWhiteSpace(name))
name = "勇者";

InitGame();
player = new Player(map.Width / 2, map.Height / 2);
player.Hp = player.MaxHp;
score = 0;
inventory = new Inventory();

Console.Clear();
Console.WriteLine("欢迎," + name + "!冒险开始了...");
Thread.Sleep(800);

RunGameLoop();
}

// ===== ★ 读档并开始 =====
private void LoadAndStart()
{
Console.Clear();
Console.WriteLine("正在读取存档...");
Thread.Sleep(500);

InitGame();
player = new Player(map.Width / 2, map.Height / 2);

if (!LoadGame())
{
Console.WriteLine("存档读取失败,开始新游戏...");
Thread.Sleep(1000);
player.Hp = player.MaxHp;
score = 0;
inventory = new Inventory();
}

RunGameLoop();
}

// ===== 初始化组件 =====
private void InitGame()
{
map = new GameMap(40, 20);
input = new InputHandler();
ui = new GameUI(map.Height);
battleManager = new BattleManager();
achievement = new AchievementSystem();
sound = new SoundSystem();
coins = new List<Coin>();
enemies = new List<Enemy>();
SpawnCoins(totalCoins);
SpawnEnemies(totalEnemies);
isRunning = true;
}

// ===== 游戏主循环 =====
private void RunGameLoop()
{
Console.Clear();
Console.CursorVisible = false;
map.Draw();
DrawAllStaticObjects();

while (isRunning && player.Hp > 0)
{
Update();
Render();
Thread.Sleep(30);
}

// 游戏结束自动存档
SaveGame();

Console.SetCursorPosition(0, map.Height + 4);
if (player.Hp <= 0)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("💀 你倒下了...游戏结束。");
Console.ResetColor();
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("游戏结束!进度已保存。");
Console.ResetColor();
}

Console.WriteLine("按任意键返回主菜单...");
Console.ReadKey(true);
ShowMainMenu(); // 返回主菜单
}

// ===== 存档 =====
private void SaveGame()
{
try
{
GameSaveData data = new GameSaveData
{
PlayerX = player.X,
PlayerY = player.Y,
PlayerHp = player.Hp,
PlayerMaxHp = player.MaxHp,
Score = score,
InventoryItems = inventory.GetAllItems()
};
string json = JsonSerializer.Serialize(data);
File.WriteAllText(saveFilePath, json);
}
catch { }
}

// ===== 读档(返回 true 表示成功)=====
private bool LoadGame()
{
if (!File.Exists(saveFilePath)) return false;

try
{
string json = File.ReadAllText(saveFilePath);
GameSaveData? data = JsonSerializer.Deserialize<GameSaveData>(json);
if (data == null) return false;

player.X = data.PlayerX;
player.Y = data.PlayerY;
player.Hp = data.PlayerHp;
score = data.Score;
inventory = new Inventory();
if (data.InventoryItems != null)
{
foreach (string item in data.InventoryItems)
inventory.AddItemSilent(item);
}
coins.Clear();
enemies.Clear();
SpawnCoins(totalCoins);
SpawnEnemies(totalEnemies);
return true;
}
catch
{
return false;
}
}

// ===== 以下不变 ===== private void SpawnCoins(int count) { Random rng = new Random(); for (int i = 0; i < count; i++) { int x = rng.Next(1, map.Width - 1); int y = rng.Next(1, map.Height - 1); coins.Add(new Coin(x, y)); } } private void SpawnEnemies(int count) { Random rng = new Random(); for (int i = 1; i <= count; i++) { int x = rng.Next(1, map.Width - 1); int y = rng.Next(1, map.Height - 1); Slime slime = new Slime("绿色史莱姆" + i, 25 + i * 5, 6 + i, "史莱姆粘液"); slime.X = x; slime.Y = y; slime.IsActive = true; slime.OnEnemyKilled += achievement.OnEnemyKilled; slime.OnEnemyKilled += sound.OnEnemyKilled; slime.OnEnemyKilled += (Enemy e) => { inventory.AddItem(e.DropItem); }; enemies.Add(slime); } } private void DrawAllStaticObjects() { foreach (Coin coin in coins) coin.Draw(); foreach (Enemy enemy in enemies) DrawEnemy(enemy); } private void DrawEnemy(Enemy enemy) { if (!enemy.IsActive) return; Console.SetCursorPosition(enemy.X, enemy.Y); Console.ForegroundColor = ConsoleColor.Red; Console.Write("S"); Console.ResetColor(); } private void EraseEnemy(Enemy enemy) { Console.SetCursorPosition(enemy.X, enemy.Y); Console.Write(" "); } private void Update() { InputHandler.Command cmd = input.GetCommand(); switch (cmd) { case InputHandler.Command.MoveUp: player.Move(0, -1, 1, 1, map.Width - 2, map.Height - 2); break; case InputHandler.Command.MoveDown: player.Move(0, 1, 1, 1, map.Width - 2, map.Height - 2); break; case InputHandler.Command.MoveLeft: player.Move(-1, 0, 1, 1, map.Width - 2, map.Height - 2); break; case InputHandler.Command.MoveRight: player.Move(1, 0, 1, 1, map.Width - 2, map.Height - 2); break; case InputHandler.Command.Save: SaveGame(); ShowSaveMessage(); break; case InputHandler.Command.Load: LoadGame(); ShowLoadMessage(); break; case InputHandler.Command.Quit: isRunning = false; break; } CheckCoinCollision(); CheckEnemyCollision(); if (GetActiveCoinCount() == 0) SpawnCoins(totalCoins); if (GetActiveEnemyCount() == 0) SpawnEnemies(totalEnemies); } private void ShowSaveMessage() { Console.SetCursorPosition(2, map.Height + 3); Console.Write(new string(' ', 30)); Console.SetCursorPosition(2, map.Height + 3); Console.ForegroundColor = ConsoleColor.Green; Console.Write("✅ 已保存!"); Console.ResetColor(); } private void ShowLoadMessage() { Console.SetCursorPosition(2, map.Height + 3); Console.Write(new string(' ', 30)); Console.SetCursorPosition(2, map.Height + 3); Console.ForegroundColor = ConsoleColor.Cyan; Console.Write("📂 已加载!"); Console.ResetColor(); } private void CheckCoinCollision() { foreach (Coin coin in coins) { if (coin.IsActive && coin.X == player.X && coin.Y == player.Y) { coin.IsActive = false; coin.Erase(); score += coin.Value; inventory.AddItem("金币"); } } } private void CheckEnemyCollision() { foreach (Enemy enemy in enemies) { if (enemy.IsActive && enemy.X == player.X && enemy.Y == player.Y) { EraseEnemy(enemy); bool win = battleManager.StartBattle(player, enemy); if (!win) { isRunning = false; return; } Console.Clear(); map.Draw(); DrawAllStaticObjects(); } } } private int GetActiveCoinCount() { int count = 0; foreach (Coin coin in coins) if (coin.IsActive) count++; return count; } private int GetActiveEnemyCount() { int count = 0; foreach (Enemy enemy in enemies) if (enemy.IsActive) count++; return count; } private void Render() { player.EraseOld(); player.Draw(); ui.Draw(score, GetActiveCoinCount(), inventory.ItemCount, player.Hp, player.MaxHp); } } }
http://www.jsqmd.com/news/848333/

相关文章:

  • 别再手动改PPT了!用Python-pptx库批量生成100份奖状/证书(附完整代码)
  • RTX166实时操作系统初始化与配置实战指南
  • 2026 年 30 个 MCP Server 实测评:Claude Code 集成效果与响应延迟对比数据
  • 潍坊漆面车衣怎么选才合适?
  • 如何利用SOLIDWORKS成形工具简化钣金设计流程
  • 收藏!6种低门槛AI副业,小白也能靠AI月入过万,别错过!
  • AI API 接入实践:从直接调用到统一网关管理的一次整理
  • 百考通助你站在学术前沿,自信开题 ��
  • Sub-agent 协同失效的 3 类边界场景:Claude Code 8.1 机制原理解析
  • idea快速添加测试类——实操
  • 2026年五金配件采购新趋势:为何融创五金制品有限公司成为优选伙伴? - 2026年企业推荐榜
  • 免费开源AMD Ryzen调试神器:ZenStatesDebugTool完整使用指南
  • 武汉假发店TOP5评测|揭秘江城最靠谱假发品牌,打造自然蓬松发型! - 行业深度观察C
  • linux lsmem
  • 2026深圳仿木栏杆优质服务商推荐榜:tcp塑石、人造假山、人造溶洞、仿真假山、仿真大树、仿真树、仿真溶洞、假树选择指南 - 优质品牌商家
  • 告别Telnet和Jmeter!用Apifox 2.3.24一站式搞定Dubbo 3.x接口调试(附Nacos注册中心实战)
  • 英语单词发音MP3音频下载:一键获取119,376个标准发音的终极解决方案
  • 2026年水平生命线怎么选:水平生命线国标、水平生命线标准、钢缆垂直生命线系统、钢缆水平生命线系统、国标垂直生命线选择指南 - 优质品牌商家
  • Path of Building装备制作终极指南:从混沌石到毕业装
  • 2026年浮筒吹塑机技术选型:玩具吹塑机/同发吹塑机/吹塑机价格/吹塑机加工/吹塑机厂/塑料吹塑机/护栏吹塑机/选择指南 - 优质品牌商家
  • 中兴光猫深度管理终极指南:一键开启工厂模式与永久Telnet服务
  • 2026年万通板生产企业排行:中空板周转箱、塑料中空板、万通板、防静电中空板、瓦楞板、PP中空板、中空板选择指南 - 优质品牌商家
  • 2026工业脱盐水技术干货:蒸馏水价格/蒸馏水生产/除盐水/医用蒸馏水/去离子水批发/工业去离子水采购/工业纯水/选择指南 - 优质品牌商家
  • 2026年至今,杭州干燥机备品备件可靠供应商深度解析:日盛工业的硬实力与服务保障 - 2026年企业推荐榜
  • 从Multisim仿真到面包板实测:手把手教你验证戴维宁等效电路的正确性
  • 在 OpenClaw 项目中配置 Taotoken 作为 Agent 任务执行后端
  • 如何在 RabbitMQ 中配置镜像队列实现高可用
  • 2026年脉冲除尘器厂家好评榜/口碑好的脉冲除尘器制造商,高效型脉冲除尘器公司,值得信赖的脉冲除尘器制造商 - 品牌推广大师
  • 为什么你的酒店比价接口在Perplexity上始终掉榜?2024Q2真实A/B测试数据+5个权重因子权重表
  • 2026 GEO 服务商深度盘点:AI 搜索时代品牌增长工具怎么选