当前位置: 首页 > 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.zskr.cn/news/1437269.html

相关文章:

  • 2026年5月热门的昆山老酒回收排行榜厂家推荐榜,贵州茅台整箱回收、年份老酒、五粮液、洋酒、礼品酒厂家选择指南 - 海棠依旧大
  • 2026年5月市面上海南医疗消毒电磁蒸汽发生器型号排行厂家推荐榜:YFL系列、RSD系列、FRL系列等主流型号厂家选择指南 - 海棠依旧大
  • 重庆400多分初三生:重庆中考400多分可以读哪些高中、重庆公办普高、重庆公办高中、重庆公办高中学校、重庆普通高中学校选择指南 - 优质品牌商家
  • 层级式多Agent协作是什么?
  • 2026北京小程序平台推荐——本地商家数字化选型全维度解析
  • 2026年5月热门的泰州市工业洗衣机设备源头厂家怎么选择厂家推荐榜:全自动洗脱机、工业烘干机、烫平机厂家选择指南 - 海棠依旧大
  • Arduino红外遥控库完整实践指南:从零到精通的10个技巧
  • 2026年5月口碑好的比较大的木工铣床销售厂家怎么选?数控木工铣床、重型木工铣床、五轴木工铣床厂家选择指南 - 海棠依旧大
  • 2026乐山装修公司排行:九木堂装饰联系/乐山哪家自建房修建公司好/乐山哪家装修公司靠谱/乐山好的装修设计公司/选择指南 - 优质品牌商家
  • Buzz:基于Whisper的离线音频转录工具如何重构本地语音处理体验
  • SpringBoot整合MyBatis:高效持久层解决方案
  • 提示工程(Prompt_Engineering)
  • 终极ESP32 Arduino开发指南:从零开始快速上手物联网项目
  • 终极指南:如何免费解锁WeMod完整功能 - Wand-Enhancer开源解决方案
  • langchain的消息类型有哪些?如何发送消息?我们可以发送图片给大模型吗?多模态是什么?一文详解
  • 2026年佛山洋酒回收权威机构排行:佛山名酒回收电话、佛山茅台酒回收、佛山茅台酒回收电话、佛山附近上门回收名酒选择指南 - 优质品牌商家
  • Harness 持续交付平台深度评测:从参数解析到实战边界
  • 电动抽沙船哪家靠谱 - 舒雯文化
  • 【Gemini舆情分析黄金标准】:基于172家头部客户数据验证的4类误判模式及修正公式
  • 2026年哈氏合金N生产商排名,哪家交货期快? - myqiye
  • NLP预处理失效?Gemini评论情感极性误判率高达43.7%,这4个校准动作必须立刻执行
  • 基于Arduino与行为心理学的智能闹钟:硬件设计与状态机实现
  • 如何评估数字员工的效果:系统化评估框架与实践指南
  • 谷歌Gemini 2.5 Pro最新能力解析(未公开API调用技巧首次披露)
  • 2026年适配知网降AIGC工具横评:亲测8款工具,将AIGC特征彻底弱化淡化
  • 口碑好的玉兰灯厂家排名 - mypinpai
  • 基于联邦卡尔曼滤波Federated、集中式滤波、分布式卡尔曼滤波DKF研究附Matlab代码
  • 如何用抖音批量下载工具轻松收集无水印视频:完整指南
  • 绩效评估
  • 回归预测 | Matlab实现NGO-HKELM北方苍鹰算法优化混合核极限学习机多变量回归预测