news 2026/5/22 4:27:05

从零开发游戏需要学习的c#模块,第十九章(在游戏画面里显示文字 —— FontStashSharp)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开发游戏需要学习的c#模块,第十九章(在游戏画面里显示文字 —— FontStashSharp)

本节课我们要学习的内容是

  1. 安装字体渲染库

  2. 加载系统字体文件

  3. 在游戏画面里直接显示分数、金币数等信息

第一步:安装 NuGet 包

  1. 在 Visual Studio 右侧“解决方案资源管理器”里,右键你的项目名(不是解决方案)

  2. 选择“管理 NuGet 程序包”

  3. 点击“浏览”标签

  4. 搜索FontStashSharp.MonoGame

  5. 找到后点击安装

第二步:准备字体文件

  1. 打开 Windows 的文件资源管理器,地址栏输入C:\Windows\Fonts,回车

  2. 找一个你喜欢的.ttf字体(比如consola.ttfsimhei.ttf黑体等)

  3. 复制这个文件

  4. 粘贴到你项目的Content文件夹里

  5. 在 VS 里,右键这个.ttf文件 →属性

  6. “复制到输出目录”改成“如果较新则复制”

第三步:完整代码

Game1.cs完整替换为:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.IO;
using FontStashSharp;

namespace MY_FIRST_GAME
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;

// 玩家
private Texture2D playerTexture;
private Vector2 playerPosition;
private float playerSpeed = 200f;

// 金币
private Texture2D coinTexture;
private List<Vector2> coins;
private Random rng;
private int score;

// ★ 字体
private SpriteFontBase font;

public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}

protected override void Initialize()
{
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
_graphics.ApplyChanges();

playerPosition = new Vector2(400, 300);
rng = new Random();
coins = new List<Vector2>();
score = 0;

SpawnCoins(5);

base.Initialize();
}

protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);

// 加载玩家图片
using var stream = File.OpenRead("Content/player.png");
playerTexture = Texture2D.FromStream(GraphicsDevice, stream);

// 创建金币纹理
coinTexture = new Texture2D(GraphicsDevice, 32, 32);
Color[] data = new Color[32 * 32];
for (int i = 0; i < data.Length; i++)
data[i] = Color.Gold;
coinTexture.SetData(data);

// ★ 加载字体(直接用 .ttf 文件,不需要编译)
var fontSystem = new FontSystem();
fontSystem.AddFont(File.ReadAllBytes("Content/consola.ttf"));
font = fontSystem.GetFont(18);
}

private void SpawnCoins(int count)
{
for (int i = 0; i < count; i++)
{
float x = rng.Next(50, 750);
float y = rng.Next(50, 550);
coins.Add(new Vector2(x, y));
}
}

protected override void Update(GameTime gameTime)
{
KeyboardState keyboard = Keyboard.GetState();
float speed = playerSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up))
playerPosition.Y -= speed;
if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down))
playerPosition.Y += speed;
if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left))
playerPosition.X -= speed;
if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right))
playerPosition.X += speed;

playerPosition.X = Math.Clamp(playerPosition.X, 32, 768);
playerPosition.Y = Math.Clamp(playerPosition.Y, 32, 568);

CheckCoinCollision();

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

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

base.Update(gameTime);
}

private void CheckCoinCollision()
{
Rectangle playerRect = new Rectangle(
(int)playerPosition.X - 32,
(int)playerPosition.Y - 32,
64, 64
);

for (int i = coins.Count - 1; i >= 0; i--)
{
Rectangle coinRect = new Rectangle((int)coins[i].X, (int)coins[i].Y, 32, 32);

if (playerRect.Intersects(coinRect))
{
coins.RemoveAt(i);
score += 10;
}
}
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

_spriteBatch.Begin();

// 画金币
foreach (Vector2 coinPos in coins)
{
_spriteBatch.Draw(coinTexture, coinPos, Color.White);
}

// 画玩家
_spriteBatch.Draw(
playerTexture,
playerPosition,
null,
Color.White,
0f,
new Vector2(playerTexture.Width / 2, playerTexture.Height / 2),
1f,
SpriteEffects.None,
0f
);

// ★ 画文字
_spriteBatch.DrawString(font, $"分数:{score}", new Vector2(10, 10), Color.White);
_spriteBatch.DrawString(font, $"金币:{coins.Count}", new Vector2(10, 35), Color.Gold);
_spriteBatch.DrawString(font, "WASD/方向键 移动 | ESC 退出", new Vector2(10, 570), Color.LightGray);

_spriteBatch.End();

base.Draw(gameTime);
}
}
}

本节课新内容

加载字体(FontStashSharp 方式):

var fontSystem = new FontSystem(); fontSystem.AddFont(File.ReadAllBytes("Content/consola.ttf")); font = fontSystem.GetFont(18);
  • 只需要三行代码,直接读.ttf文件

  • 不需要.spritefont文件

  • 不需要 MGCB Editor

  • 字号18可以随便改

画文字

_spriteBatch.DrawString(font, "内容", new Vector2(X, Y), Color.White);

最后使用F5运行。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 4:26:22

Octopress草稿管理终极指南:如何高效使用publish和unpublish命令

Octopress草稿管理终极指南&#xff1a;如何高效使用publish和unpublish命令 【免费下载链接】octopress Octopress 3.0 – Jekylls Ferrari 项目地址: https://gitcode.com/gh_mirrors/oct/octopress Octopress草稿管理功能是博客写作工作流中的重要组成部分&#xff0…

作者头像 李华
网站建设 2026/5/22 4:22:17

Istio安全防护完全手册:认证授权与证书管理最佳实践

Istio安全防护完全手册&#xff1a;认证授权与证书管理最佳实践 【免费下载链接】istio-handbook Istio服务网格进阶实战 项目地址: https://gitcode.com/gh_mirrors/is/istio-handbook 在微服务架构中&#xff0c;网络通信的安全性至关重要。Istio作为强大的服务网格解…

作者头像 李华
网站建设 2026/5/22 4:21:58

Hover服务集成指南:HoverMenuService的使用与优化终极教程

Hover服务集成指南&#xff1a;HoverMenuService的使用与优化终极教程 【免费下载链接】hover A floating menu library for Android. 项目地址: https://gitcode.com/gh_mirrors/hover5/hover HoverMenuService是Android浮动菜单库Hover的核心组件&#xff0c;它为开发…

作者头像 李华
网站建设 2026/5/22 4:18:59

Broccoli实战案例:仿钉钉考勤界面占位符效果实现

Broccoli实战案例&#xff1a;仿钉钉考勤界面占位符效果实现 【免费下载链接】Broccoli &#x1f4df;An Android library that shows the placeholder of the view. 项目地址: https://gitcode.com/gh_mirrors/bro/Broccoli Broccoli是一款强大的Android占位符库&#…

作者头像 李华
网站建设 2026/5/22 4:15:55

Wedding-website图片库与相册功能:展示精美婚礼照片的最佳实践

Wedding-website图片库与相册功能&#xff1a;展示精美婚礼照片的最佳实践 【免费下载链接】wedding-website Our Wedding Website &#x1f46b; 项目地址: https://gitcode.com/gh_mirrors/we/wedding-website 婚礼是人生中最珍贵的时刻之一&#xff0c;而如何将这些美…

作者头像 李华