65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (3投票s)

2014 年 1 月 7 日

CPOL

4分钟阅读

viewsIcon

17378

在本简单的教程中,我们将使用 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 属性根据星星的当前屏幕位置以及 InitialFramewidthheight 来构建一个新的 RectangleUpdate() 方法将精灵的速度添加到精灵的位置。由于速度存储为每秒的变化量,将其乘以 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() 方法中,调用 starFieldDraw() 方法,并将其放置在包含 GameStates.Playing 的 if 块中

starField.Draw (spriteBatch); 

现在运行项目并观察 star field。

最终结果

为了观察最终结果,您可以在 我的 Youtube 频道 上观看视频,或查看 我的博客

© . All rights reserved.