使用 C# 和 MonoGame 构建基于精灵的滚动星空背景






4.83/5 (3投票s)
在本简单的教程中,我们将使用 Xamarin Studio 和 MonoGame 创建一个滚动精灵动画的星空背景。
引言
在本简单的教程中,我们将使用 Xamarin Studio 和 MonoGame 创建一个滚动精灵动画的星空背景。MonoGame 是 Microsoft XNA 4.x 框架的一个开源实现。 此页面列出了在 Windows 上创建 MonoGame 项目的要求。
创建项目
在本简单的教程中,我们将使用 Xamarin Studio 和 MonoGame 创建一个滚动精灵动画的星空背景。MonoGame 是 Microsoft XNA 4.x 框架的一个开源实现。 此页面列出了在 Windows 上创建 MonoGame 项目的要求。
打开 Xamarin Studio,创建一个名为 TwoDimensionalStarField
的新 MonoGame Windows OpenGL 应用程序项目。打开 Microsoft Paint 或您喜欢的图像编辑器,创建一个 2x2 像素的新图像,并将其填充为白色。将图像另存为 STAR.BMP 到一个临时位置。回到 Xamarin Studio,右键单击“Content”文件夹,然后选择 Add | Add Files。浏览到您创建的图像并单击“Ok”。还将 TitleScreen.PNG 添加到您的项目中。
在 Game1
类中为游戏状态和纹理添加声明
enum GameStates {TitleScreen, Playing};
GameStates gameState = GameStates.TitleScreen;
Texture2D titleScreen;
Texture2D star;
更新 LoadContent()
方法以加载纹理
star = Content.Load(@"STAR");
titleScreen = Content.Load (@"TitleScreen");
在调用 base.Update()
之前,您需要为 Update()
方法添加一个基本模板
switch(gameState)
{
case GameStates.TitleScreen:
if ((Keyboard.GetState ().IsKeyDown (Keys.Space))) {
gameState = GameStates.Playing;
}
break;
case GameStates.Playing:
// ...
break;
}
在调用 base.Draw()
之前,为 Draw()
方法添加一个基本模板,并将其放在 spriteBatch.Begin()
和 spriteBatch.End()
方法之间
if (gameState == GameStates.TitleScreen) {
spriteBatch.Draw (
titleScreen,
new Rectangle(0, 0,
this.Window.ClientBounds.Width,
this.Window.ClientBounds.Height),
Color.White
);
}
if(gameState == GameStates.Playing) {
// ...
}
到目前为止,我们已经创建了 Update()
和 Draw()
方法的骨架。现在您可以执行您的项目(按 Ctrl + F5)来查看标题屏幕是否已显示。
构建 Star 类
向项目中添加一个名为 Star.cs
的新类,然后将以下声明包含到类的 using 区域中
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
将以下属性添加到 Star
类中
private Texture2D Texture { get; set; }
public Color TintColor { get; set; }
public Vector2 Location { get; set; }
private Vector2 Velocity { get; set; }
private Rectangle InitialFrame { get; set; }
TintColor
成员存储每个星星的颜色,该颜色将在绘制星星时使用。星星的位置将通过 Location
向量进行跟踪,而星星移动的速度和方向则存储在 Velocity
中。
Star
类中public Star(
Vector2 location,
Texture2D texture,
Rectangle initialFrame,
Vector2 velocity)
{
Location = location;
Texture = texture;
InitialFrame = initialFrame;
Velocity = velocity;
}
此构造函数仅直接将成员设置为传入的参数值。现在您需要将以下属性和方法添加到 Star
类中
public Rectangle Destination
{
get {
return new Rectangle (
(int)Location.X, (int)Location.Y,
InitialFrame.Width, InitialFrame.Height
);
}
}
public void Update(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
Location += (Velocity * elapsed);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw (
Texture, Destination, InitialFrame, TintColor
);
}
Destination
属性根据星星的当前屏幕位置以及 InitialFrame
的 width
和 height
来构建一个新的 Rectangle
。 Update()
方法将精灵的速度添加到精灵的位置。由于速度存储为每秒的变化量,将其乘以 gameTime.ElapsedGameTime.TotalSeconds
(如果游戏以 60 帧/秒运行,则该值为 1/60 = 0.0166 秒)可以确定单帧的移动距离。 Draw()
方法由一个调用 SpriteBatch.Draw()
方法的调用组成,使用了该方法的第三个重载。
构建 StarField 类
让我们通过创建一个滚动的星空来使用我们的 Star
类。我们可以使用一个空白的白色精灵,结合 SpriteBatch.Draw()
方法的 TintColor
参数来绘制任何我们想要的颜色的方块。这就是我们创建 STAR.BMP 的原因。为了创建星空,我们将创建 300 颗星星并将它们随机放置在屏幕上。它们将具有缓慢向下滚动屏幕的速度。 StarField
类将负责创建星星以及确定它们何时到达屏幕底部。当这种情况发生时,它们将在屏幕顶部以随机位置重新创建。
添加一个名为 StarField
的新类,然后将以下 using
指令添加到类的 using 区域中
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
将以下声明添加到 StarField
类中
private List stars = new List();
private int ScreenWidth { get; set; }
private int ScreenHeight { get; set; }
private Random rand = new Random();
private Color[] colors = {
Color.White, Color.Yellow, Color.Red
};
将构造函数添加到 StarField
类中
public StarField(
int screenWidth,
int screenHeight,
int starCount,
Vector2 starVelocity,
Texture2D texture,
Rectangle initialFrame
)
{
ScreenWidth = screenWidth;
ScreenHeight = screenHeight;
for(int x = 0; x < starCount; x++)
{
stars.Add (
new Star(
new Vector2(rand.Next(0, screenWidth),
rand.Next(0, screenHeight)),
texture,
initialFrame,
starVelocity)
);
}
foreach (Star star in stars) {
star.TintColor = colors[rand.Next(0, colors.Length)];
star.TintColor *= (float)(rand.Next (30, 80) / 100f);
}
}
我们将把每个星星存储在 stars 列表中。这样就可以使用 foreach
循环轻松地更新和绘制它们。当创建星星时,将从 colors 数组中为每个星星随机选择一种颜色。在类构造函数中,我们将创建 300 颗星星,并为每颗星星分配一个随机位置。然后将 TintColors
乘以 0.30f 到 0.79f 之间的随机值,使星星半透明。将 Update()
和 Draw()
方法添加到 StarField
类中
public void Update(GameTime gameTime)
{
foreach (Star star in stars)
{
star.Update (gameTime);
if (star.Location.Y > ScreenHeight) {
star.Location = new Vector2 (rand.Next(0, ScreenWidth),0);
}
}
}
public void Draw(SpriteBatch srriteBatch)
{
foreach(Star star in stars)
{
star.Draw(srriteBatch);
}
}
一个 foreach
循环会更新 stars 列表中的每个星星。然后该方法检查星星的 Location
属性的 Y
值,以确定星星是否已到达屏幕底部。如果发生这种情况,星星的位置将被分配一个新的 Location
,其 X
分量随机,Y
分量为零,将星星放在屏幕顶部的随机位置。 Draw()
方法仅使用一个 foreach
循环,将 spriteBatch
对象传递给 stars 列表中的每个单独的星星。
观看星空效果
将以下声明添加到 Game1
类中
StarField starField;
在 Draw()
方法中,将背景颜色从 Color.CornflowerBlue
更改为 Color.Black
。仍然在 Draw()
方法中,调用 starField
的 Draw()
方法,并将其放置在包含 GameStates.Playing
的 if 块中
starField.Draw (spriteBatch);
现在运行项目并观察 star
field。
最终结果
为了观察最终结果,您可以在 我的 Youtube 频道 上观看视频,或查看 我的博客。