从零开发游戏需要学习的c#模块,第二十二章(音效与背景音乐)

本节课学习目标

  1. 加载并播放背景音乐(循环)

  2. 收集金币时播放音效

  3. 碰到敌人时播放音效

  4. 用 MonoGame 内置音频系统实现

第一步:准备音频文件

去这些网站下载免费音效:

需要三个文件:

文件 用途
coin.wav 吃金币音效
hit.wav 碰敌人音效
bgm.wavbgm.mp3 背景音乐

MonoGame 支持的格式.wav.mp3.ogg

下载后放到 Content 文件夹,属性设为 "如果较新则复制"

第二步:完整代码

Game1.cs 完整替换为:

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;

using Microsoft.Xna.Framework.Audio;

using Microsoft.Xna.Framework.Media;

using System;

using System.Collections.Generic;

using System.IO;

using FontStashSharp;

namespace MY_FIRST_GAME

{

public enum GameState { Exploring, Battling }

public class Game1 : Game

{

private GraphicsDeviceManager _graphics;

private SpriteBatch _spriteBatch;

private Player player = default!;

private Texture2D playerSpriteSheet;

private Texture2D coinTexture;

private List<Vector2> coins;

private Random rng;

private int score;

private Texture2D enemyTexture;

private List<Vector2> enemies;

private SpriteFontBase font;

private GameState state = GameState.Exploring;

// ★ 音频

private SoundEffect coinSound = default!;

private SoundEffect hitSound = default!;

private Song bgm = default!;

public Game1()

{

_graphics = new GraphicsDeviceManager(this);

Content.RootDirectory = "Content";

IsMouseVisible = true;

// ★ 背景音乐必须通过 MGCB Editor 加载

// 如果 MGCB 不能用,这里会跳过音乐加载

}

protected override void Initialize()

{

_graphics.PreferredBackBufferWidth = 800;

_graphics.PreferredBackBufferHeight = 600;

_graphics.ApplyChanges();

rng = new Random();

coins = new List<Vector2>();

enemies = new List<Vector2>();

score = 0;

SpawnCoins(5);

SpawnEnemies(3);

base.Initialize();

}

protected override void LoadContent()

{

_spriteBatch = new SpriteBatch(GraphicsDevice);

// 玩家图集

using var stream = File.OpenRead("Content/player_spritesheet.png");

playerSpriteSheet = Texture2D.FromStream(GraphicsDevice, stream);

player = new Player(playerSpriteSheet, new Vector2(400, 300));

// 金币

coinTexture = new Texture2D(GraphicsDevice, 24, 24);

Color\[\] coinData = new Color24 \* 24;

for (int i = 0; i < coinData.Length; i++) coinDatai = Color.Gold;

coinTexture.SetData(coinData);

// 敌人

enemyTexture = new Texture2D(GraphicsDevice, 40, 40);

Color\[\] enemyData = new Color40 \* 40;

for (int i = 0; i < enemyData.Length; i++) enemyDatai = Color.Red;

enemyTexture.SetData(enemyData);

// 字体

var fontSystem = new FontSystem();

fontSystem.AddFont(File.ReadAllBytes("Content/consola.ttf"));

font = fontSystem.GetFont(18);

// ★ 加载音效(SoundEffect 可以用 FileStream 直接读)

try

{

using var coinStream = File.OpenRead("Content/coin.wav");

coinSound = SoundEffect.FromStream(coinStream);

using var hitStream = File.OpenRead("Content/hit.wav");

hitSound = SoundEffect.FromStream(hitStream);

// 背景音乐(MediaPlayer 需要 MGCB 编译,直接读文件不支持)

// 暂时用音效替代,把 bgm 循环播放

}

catch (Exception ex)

{

System.Diagnostics.Debug.WriteLine("音效加载失败:" + ex.Message);

}

}

// ★ 开始播放背景音乐(在 Initialize 之后调用)

protected override void BeginRun()

{

base.BeginRun();

// 尝试播放背景音乐(音效作为临时方案)

try

{

// 如果你的 bgm 是 mp3/wav,可以用 SoundEffect 播放

using var bgmStream = File.OpenRead("Content/bgm.wav");

var bgmSound = SoundEffect.FromStream(bgmStream);

SoundEffectInstance bgmInstance = bgmSound.CreateInstance();

bgmInstance.IsLooped = true;

bgmInstance.Volume = 0.3f; // 音量 30%

bgmInstance.Play();

}

catch

{

// 没有音乐文件就跳过

}

}

private void SpawnCoins(int count)

{

for (int i = 0; i < count; i++)

coins.Add(new Vector2(rng.Next(50, 750), rng.Next(50, 550)));

}

private void SpawnEnemies(int count)

{

for (int i = 0; i < count; i++)

enemies.Add(new Vector2(rng.Next(80, 720), rng.Next(80, 520)));

}

protected override void Update(GameTime gameTime)

{

float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

KeyboardState keyboard = Keyboard.GetState();

if (state == GameState.Exploring)

{

player.Update(deltaTime);

CheckCoinCollision();

CheckEnemyCollision();

if (coins.Count == 0) SpawnCoins(5);

if (enemies.Count == 0) SpawnEnemies(3);

}

if (keyboard.IsKeyDown(Keys.M))

{

// ★ 按 M 静音/取消静音

MediaPlayer.IsMuted = !MediaPlayer.IsMuted;

SoundEffect.MasterVolume = SoundEffect.MasterVolume > 0 ? 0f : 1f;

}

if (keyboard.IsKeyDown(Keys.Escape)) Exit();

base.Update(gameTime);

}

private void CheckCoinCollision()

{

Rectangle playerRect = player.GetBounds();

for (int i = coins.Count - 1; i >= 0; i--)

{

Rectangle coinRect = new Rectangle((int)coinsi.X, (int)coinsi.Y, 24, 24);

if (playerRect.Intersects(coinRect))

{

coins.RemoveAt(i);

score += 10;

// ★ 播放吃金币音效

try { coinSound?.Play(); }

catch { }

}

}

}

private void CheckEnemyCollision()

{

Rectangle playerRect = player.GetBounds();

for (int i = enemies.Count - 1; i >= 0; i--)

{

Rectangle enemyRect = new Rectangle(

(int)enemiesi.X - 20, (int)enemiesi.Y - 20, 40, 40);

if (playerRect.Intersects(enemyRect))

{

enemies.RemoveAt(i);

score += 50;

// ★ 播放碰敌人音效

try { hitSound?.Play(); }

catch { }

}

}

}

protected override void Draw(GameTime gameTime)

{

GraphicsDevice.Clear(Color.CornflowerBlue);

_spriteBatch.Begin();

foreach (Vector2 coinPos in coins)

_spriteBatch.Draw(coinTexture, coinPos, Color.White);

foreach (Vector2 enemyPos in enemies)

_spriteBatch.Draw(enemyTexture, enemyPos, null, Color.White,

0f, new Vector2(20, 20), 1f, SpriteEffects.None, 0f);

player.Draw(_spriteBatch);

_spriteBatch.DrawString(font, $"分数:{score}", new Vector2(10, 10), Color.White);

_spriteBatch.DrawString(font, $"金币:{coins.Count}", new Vector2(10, 35), Color.Gold);

_spriteBatch.DrawString(font, $"敌人:{enemies.Count}", new Vector2(10, 60), Color.Red);

_spriteBatch.DrawString(font, $"HP:{player.Hp}/{player.MaxHp}", new Vector2(10, 85), Color.LimeGreen);

_spriteBatch.DrawString(font, "WASD移动 | M静音 | ESC退出", new Vector2(10, 570), Color.LightGray);

_spriteBatch.End();

base.Draw(gameTime);

}

}

}

本节课新内容

cs 复制代码
using var stream = File.OpenRead("Content/coin.wav");
coinSound = SoundEffect.FromStream(stream);
coinSound.Play();  // 播放一次
cs 复制代码
SoundEffectInstance bgmInstance = bgmSound.CreateInstance();
bgmInstance.IsLooped = true;   // 循环播放
bgmInstance.Volume = 0.3f;     // 音量
bgmInstance.Play();
cs 复制代码
SoundEffect.MasterVolume = 0f;  // 所有音效静音
SoundEffect.MasterVolume = 1f;  // 恢复

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

相关推荐
Ricky_Theseus29 分钟前
Trie 字典树:前缀匹配利器
开发语言·c#
峥嵘life33 分钟前
Android GMS 开机向导横竖屏切换配置总结
android·学习
Rauser Mack41 分钟前
Vibe coding游戏实战:零代码编程五子棋小游戏
人工智能·python·游戏·html·prompt
六bring个六1 小时前
链表学习(常规链表)
数据结构·学习·链表
say_fall1 小时前
【Git 精品详解】企业规范:企业级开发模型、Git Flow、发版流程规范、Code Owner 制度、事故应急回滚
大数据·linux·服务器·git·学习·elasticsearch
kgduu1 小时前
react-redux学习笔记
笔记·学习·react.js
诗句藏于尽头1 小时前
Ai-3D音乐播放器-Mineradio -VibeCoding大赏-新增歌词字体自定义上传功能(个人学习)
学习
TE-茶叶蛋2 小时前
Node.js-Phase 1 学习总结:CLI 文件管理系统
学习·node.js
Waay11 小时前
面试口述版:个人对 Prometheus 完整理解
运维·学习·云原生·面试·职场和发展·kubernetes·prometheus
想做后端的前端12 小时前
游戏里的水面是怎么做的
游戏