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

从零开发游戏需要学习的c#模块,第三十四章(设置界面)

本节课学习目标

  1. 标题画面增加“设置”选项

  2. 设置界面:音量滑块、全屏开关

  3. 设置保存到 JSON 文件

  4. 暂停菜单中也能打开设置

第一步:扩展存档数据

打开SaveManager.cs,在SaveData类里加两个字段:

public class SaveData
{
public int HighScore { get; set; }
public int TotalCoinsCollected { get; set; }
public int TotalEnemiesDefeated { get; set; }
public float MusicVolume { get; set; } = 0.5f; // ★ 音量 0~1
public bool IsFullscreen { get; set; } = false; // ★ 是否全屏
}

第二步:创建设置界面类

右键项目 →添加,文件名SettingsMenu.cs

using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using FontStashSharp; using System.Collections.Generic; namespace MY_FIRST_GAME { public class SettingsMenu { private List<string> options; private int selectedIndex; private KeyboardState previousKeyboard; private KeyboardState currentKeyboard; private bool adjustingVolume; // 正在调节音量 public float Volume { get; set; } public bool IsFullscreen { get; set; } public SettingsMenu(float volume, bool isFullscreen) { Volume = volume; IsFullscreen = isFullscreen; options = new List<string> { "音量", "全屏", "返回" }; selectedIndex = 0; adjustingVolume = false; } // 返回值:-1=还在设置, 0=返回, 1=音量变化, 2=全屏切换 public int Update() { previousKeyboard = currentKeyboard; currentKeyboard = Keyboard.GetState(); if (adjustingVolume) { if (IsKeyJustPressed(Keys.Left) || IsKeyJustPressed(Keys.A)) { Volume = MathHelper.Max(0, Volume - 0.1f); return 1; } if (IsKeyJustPressed(Keys.Right) || IsKeyJustPressed(Keys.D)) { Volume = MathHelper.Min(1, Volume + 0.1f); return 1; } if (IsKeyJustPressed(Keys.Enter) || IsKeyJustPressed(Keys.Escape)) { adjustingVolume = false; } return -1; } if (IsKeyJustPressed(Keys.W) || IsKeyJustPressed(Keys.Up)) { selectedIndex--; if (selectedIndex < 0) selectedIndex = options.Count - 1; } if (IsKeyJustPressed(Keys.S) || IsKeyJustPressed(Keys.Down)) { selectedIndex++; if (selectedIndex >= options.Count) selectedIndex = 0; } if (IsKeyJustPressed(Keys.Enter) || IsKeyJustPressed(Keys.Space)) { switch (selectedIndex) { case 0: // 音量 adjustingVolume = true; break; case 1: // 全屏 IsFullscreen = !IsFullscreen; return 2; case 2: // 返回 return 0; } } if (IsKeyJustPressed(Keys.Escape)) return 0; return -1; } private bool IsKeyJustPressed(Keys key) { return currentKeyboard.IsKeyDown(key) && previousKeyboard.IsKeyUp(key); } public void Draw(SpriteBatch spriteBatch, SpriteFontBase font, GraphicsDevice device) { Texture2D overlay = new Texture2D(device, 1, 1); overlay.SetData(new[] { new Color(0, 0, 0, 200) }); spriteBatch.Draw(overlay, new Rectangle(0, 0, 800, 600), Color.White); string title = "- 设置 -"; Vector2 titleSize = font.MeasureString(title); spriteBatch.DrawString(font, title, new Vector2(400 - titleSize.X / 2, 100), Color.White); // 音量选项 Color volColor = (selectedIndex == 0) ? Color.Gold : Color.LightGray; string volText = (selectedIndex == 0) ? "> 音量 <" : " 音量 "; spriteBatch.DrawString(font, volText, new Vector2(400 - font.MeasureString(volText).X / 2, 200), volColor); // 音量条 DrawSlider(spriteBatch, device, 250, 230, 300, 20, Volume); // 音量数值 string volValue = $"{(int)(Volume * 100)}%"; spriteBatch.DrawString(font, volValue, new Vector2(560, 230), Color.White); // 全屏选项 Color fsColor = (selectedIndex == 1) ? Color.Gold : Color.LightGray; string fsText = (selectedIndex == 1) ? "> 全屏 <" : " 全屏 "; spriteBatch.DrawString(font, fsText, new Vector2(400 - font.MeasureString(fsText).X / 2, 300), fsColor); string fsValue = IsFullscreen ? "开" : "关"; spriteBatch.DrawString(font, fsValue, new Vector2(560, 300), IsFullscreen ? Color.LimeGreen : Color.Gray); // 返回选项 Color backColor = (selectedIndex == 2) ? Color.Gold : Color.LightGray; string backText = (selectedIndex == 2) ? "> 返回 <" : " 返回 "; spriteBatch.DrawString(font, backText, new Vector2(400 - font.MeasureString(backText).X / 2, 400), backColor); string hint = "↑↓ 选择 | 回车 确认 | ←→ 调节 | ESC 返回"; spriteBatch.DrawString(font, hint, new Vector2(400 - font.MeasureString(hint).X / 2, 500), Color.Gray); } private void DrawSlider(SpriteBatch spriteBatch, GraphicsDevice device, int x, int y, int width, int height, float value) { Texture2D pixel = new Texture2D(device, 1, 1); pixel.SetData(new[] { Color.White }); // 背景 spriteBatch.Draw(pixel, new Rectangle(x, y, width, height), Color.DarkSlateGray); // 边框 spriteBatch.Draw(pixel, new Rectangle(x, y, width, 2), Color.White); spriteBatch.Draw(pixel, new Rectangle(x, y + height - 2, width, 2), Color.White); spriteBatch.Draw(pixel, new Rectangle(x, y, 2, height), Color.White); spriteBatch.Draw(pixel, new Rectangle(x + width - 2, y, 2, height), Color.White); // 填充 int fillWidth = (int)((width - 4) * value); spriteBatch.Draw(pixel, new Rectangle(x + 2, y + 2, fillWidth, height - 4), Color.Gold); // 滑块 int sliderX = x + 2 + fillWidth - 5; spriteBatch.Draw(pixel, new Rectangle(sliderX, y - 4, 10, height + 8), Color.White); } public void Reset() { selectedIndex = 0; adjustingVolume = false; } } }

第三步:改造Game1.cs

1. 添加字段:

csharp

private SettingsMenu settingsMenu = default!; private bool inSettings = false;

2. 在Initialize里创建设置菜单:

csharp

settingsMenu = new SettingsMenu(saveData.MusicVolume, saveData.IsFullscreen); // 应用保存的设置 ApplySettings();

3. 添加应用设置的方法:

csharp

private void ApplySettings() { SoundEffect.MasterVolume = saveData.MusicVolume; _graphics.IsFullScreen = saveData.IsFullscreen; _graphics.ApplyChanges(); }

4. 在标题画面加“设置”选项:

把标题画面的空格触发改成菜单选择。简单做法:在UpdateTitle状态里加:

csharp

case SceneType.Title: if (keyboard.IsKeyDown(Keys.Enter)) { inSettings = true; settingsMenu = new SettingsMenu(saveData.MusicVolume, saveData.IsFullscreen); settingsMenu.Reset(); } if (keyboard.IsKeyDown(Keys.Space) && !inSettings) { // 开始游戏... } break;

5. 处理设置更新:

Update开头(暂停检查之后)加:

csharp

if (inSettings) { int result = settingsMenu.Update(); if (result == 1) // 音量变化 { saveData.MusicVolume = settingsMenu.Volume; SoundEffect.MasterVolume = settingsMenu.Volume; } else if (result == 2) // 全屏切换 { saveData.IsFullscreen = settingsMenu.IsFullscreen; _graphics.IsFullScreen = settingsMenu.IsFullscreen; _graphics.ApplyChanges(); } else if (result == 0) // 返回 { SaveManager.Save(saveData); inSettings = false; } }

6. 在Draw里画设置界面:

在所有绘制之后加:

csharp

if (inSettings) { _spriteBatch.Begin(); settingsMenu.Draw(_spriteBatch, font, GraphicsDevice); _spriteBatch.End(); }

本节课学习到此结束,我叫魔法阵维护师,关注我,下期更精彩!

http://www.jsqmd.com/news/925938/

相关文章:

  • WorkshopDL跨平台Steam创意工坊下载实战指南
  • 2026年5月热门的昆山老酒回收排行榜厂家推荐榜,贵州茅台整箱回收、年份老酒、五粮液、洋酒、礼品酒厂家选择指南 - 海棠依旧大
  • 2026年5月市面上海南医疗消毒电磁蒸汽发生器型号排行厂家推荐榜:YFL系列、RSD系列、FRL系列等主流型号厂家选择指南 - 海棠依旧大
  • 2026年Q2收缩膜包装机厂家实测评测:全自动智能切角机厂家/开箱机厂家/收缩膜包装机厂家/热收缩机厂家/热收缩膜厂家/选择指南 - 优质品牌商家
  • 复相分离技术的P92钢相分析应用方案【附资料】
  • GTNH中文汉化:解锁百万字专业翻译,让格雷科技不再难懂
  • 东阳专业心理咨询机构排行:东阳哪里有好的心理咨询师/东阳家庭矛盾厉害的咨询师/东阳本地靠谱心理老师/东阳正规心理咨询师/选择指南 - 优质品牌商家
  • 解读《Effective Python 3rd Edition》:从练气到老魔(第一章 Item 7 - 9)
  • 2026北京小程序平台推荐——本地商家数字化选型全维度解析
  • Arduino红外遥控库完整实践指南:从零到精通的10个技巧
  • 2026年5月热门的泰州市工业洗衣机设备源头厂家怎么选择厂家推荐榜:全自动洗脱机、工业烘干机、烫平机厂家选择指南 - 海棠依旧大
  • 2026宜宾商用中央空调回收服务商核心维度实测评测:宜宾二手空调回收/宜宾夜宵店设备打包回收/宜宾工厂整体回收/选择指南 - 优质品牌商家
  • 重庆400多分初三生:重庆中考400多分可以读哪些高中、重庆公办普高、重庆公办高中、重庆公办高中学校、重庆普通高中学校选择指南 - 优质品牌商家
  • 层级式多Agent协作是什么?
  • 智慧职教刷课脚本终极指南:3分钟实现自动学习,解放你的宝贵时间
  • 2026年6月行业内谷歌广告投流外贸推广被骗怎么办找哪家厂家推荐榜:谷歌广告代投、独立站建站、SEO优化、社媒运营、全链路出海服务商选择指南 - 海棠依旧大
  • 碧蓝航线视觉体验优化:Perseus原生库技术实现与应用指南
  • 后端技术栈的安全考量:构建安全可靠的后端系统
  • 2026年5月行业内广东整体家居公司哪家好厂家推荐榜,整装/全屋定制/高端定制厂家选择指南 - 海棠依旧大
  • 6款论文降AIGC工具横评:键清零AI痕迹,这款性价比封神
  • 2026年5月口碑好的比较大的木工铣床销售厂家怎么选?数控木工铣床、重型木工铣床、五轴木工铣床厂家选择指南 - 海棠依旧大
  • 2026乐山装修公司排行:九木堂装饰联系/乐山哪家自建房修建公司好/乐山哪家装修公司靠谱/乐山好的装修设计公司/选择指南 - 优质品牌商家
  • 2026新乡红酒回收机构TOP5排行:新乡附近上门回收名酒/新乡新乡名酒回收电话/新乡新乡老酒回收/新乡新乡茅台酒回收/选择指南 - 优质品牌商家
  • Salesforce Prompt Builder:告别提示词工程痛点,让AI真正赋能企业业务!
  • Buzz:基于Whisper的离线音频转录工具如何重构本地语音处理体验
  • SpringBoot整合MyBatis:高效持久层解决方案
  • 开源CodeStats核心模块:手撕代码分析工具,设计模式+高并发+依赖分析完整实现!
  • 2026年至今,佛山名酒回收市场格局解析与高价值变现选择指南 - 2026年企业资讯
  • 2026高铁站一体化消防泵站厂家评测:成都二次供水设备/成都体育中心二次供水设备/成都公园不锈钢水箱/成都公园雨水收集系统/选择指南 - 优质品牌商家
  • 少走弯路:盘点2026年行业天花板级的的AI智能降重工具 - 降AI小能手