从零开发游戏需要学习的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 Color[24 * 24];

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

coinTexture.SetData(coinData);

// 敌人

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

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

for (int i = 0; i < enemyData.Length; i++) enemyData[i] = 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)coins[i].X, (int)coins[i].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)enemies[i].X - 20, (int)enemies[i].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;  // 恢复

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

相关推荐
心中有国也有家14 小时前
hixl:昇腾分布式推理的「快递专线」
人工智能·经验分享·笔记·分布式·学习·算法
爱睡懒觉的焦糖玛奇朵21 小时前
【从视频到数据集:焦糖玛奇朵的魔法工具使用说明】
人工智能·python·深度学习·学习·算法·yolo·音视频
夏天想1 天前
人类将从“执行者“变为“总导演”,学习Ai知识
人工智能·学习
晓梦林1 天前
Baji1靶场学习笔记
笔记·学习
wanhengidc1 天前
私有云的作用都有哪些?
运维·服务器·网络·游戏·智能手机
希冀1231 天前
【CSS学习第十一篇】
前端·css·学习
魔法阵维护师1 天前
从零开发游戏需要学习的c#模块,第十六章(安装 MonoGame 并创建第一个窗口)
学习·游戏·c#·monogame
xian_wwq1 天前
【学习笔记】大模型备案到底要交什么材料
笔记·学习
吴可可1231 天前
用Teigha修改并保存CAD文件
数据库·算法·c#