跳转到内容

使用 XNA 创建游戏/2D 开发/抬头显示

来自 Wikibooks,为开放世界提供开放书籍

抬头显示

[编辑 | 编辑源代码]

抬头显示 (HUD) 是一种透明的显示器,它可以显示信息,而无需用户将视线从他们通常的视角移开。这个名称的由来是现代飞机飞行员能够将头部“抬起”,向前看,而不是向下倾斜,查看下面的仪器。

虽然 HUD 最初是为军用航空开发的,但现在它们已被用于商业飞机、汽车,甚至今天的游戏设计中。在游戏中,HUD 将信息作为游戏用户界面的一部分传递给玩家。

本文将介绍 HUD 元素的示例和一些基本组件的 XNA 模板。由于好的精灵对于创建外观良好的 HUD 非常重要,因此使用专业图像处理应用程序(如 Gimp 或 Photoshop)设计这些精灵至关重要。本文不包括培养这方面的技能。

可以使用 HUD 显示许多不同类型的信息。以下是视频游戏 HUD 上显示的最重要的统计信息的概述

健康与生命
[编辑 | 编辑源代码]

健康状况极其重要。因此,这是显示在 HUD 上最重要的统计信息之一。它包含有关玩家角色或 NPC(如盟友和敌人)的信息。RTS 游戏(例如星际争霸)通常会显示屏幕上所有可见单位的健康水平。在许多动作导向的游戏(第一人称或第三人称射击游戏)中,屏幕会在玩家受到攻击时短暂闪烁,并显示箭头指示威胁来自的方向。

武器与物品
[编辑 | 编辑源代码]

大多数动作游戏(尤其是第一人称和第三人称射击游戏)会显示有关当前使用的武器、剩余弹药、其他武器、可用物品的信息。

用于不同游戏相关方面的菜单(例如开始游戏、退出游戏或更改设置)。

RTS 游戏 Warzone 2100 的 HUD。

它包含一个向上或向下计数的计时器,用于显示有关某些事件的信息(例如回合结束),记录(例如圈速)或玩家在基于生存的游戏中可以持续的时间。HUD 可以用来显示游戏内时间(游戏中的时间、日期、年份),甚至显示实时时间。

上下文相关信息
[编辑 | 编辑源代码]

它包含仅在必要时或重要时显示的信息(例如教程消息、一次性能力、字幕或动作事件)。

游戏进度
[编辑 | 编辑源代码]

它包含有关玩家当前游戏进度的信息(例如,玩家在特定任务或任务中的进度统计数据、累积的经验值或玩家的当前等级)。它还包括有关玩家当前任务的信息。

小地图、指南针、任务箭头
[编辑 | 编辑源代码]

游戏都是关于实现目标的,因此 HUD 必须清楚地说明目标,无论是指南针形式还是任务箭头形式。地图区域的小地图可以充当雷达,显示地形、盟友和/或敌人、安全屋和商店等位置或街道。

速度计
[编辑 | 编辑源代码]

在大多数包含可驾驶车辆的游戏中使用。通常仅在驾驶这些车辆时显示。

光标与十字准星
[编辑 | 编辑源代码]

十字准星指示玩家瞄准或指向的方向。

  1. 漂亮的游戏 HUD 设计
  2. 游戏中很棒的 HUD
  3. 不使用 HUD 的游戏

少即是多

[编辑 | 编辑源代码]

为了增加真实感,通常使用 HUD 显示的信息可以伪装成场景的一部分或玩家使用的车辆的一部分。例如,当玩家驾驶一辆可以承受一定撞击的汽车时,汽车可能会出现烟雾轨迹或火焰,以指示汽车严重损坏,很快就会发生故障。受伤的角色身上可能会出现伤口和血迹,他们也可能会跛行或呼吸急促,以表明他们受伤了。

在某些情况下,根本不显示 HUD。让玩家解读游戏世界中的听觉和视觉线索,创造出更紧张的气氛。

HUD 中的文本

[编辑 | 编辑源代码]

您计算机上安装的每种字体都可以用来在 HUD 中显示文本。因此,字体必须作为“现有文件”添加到 Visual Studio 中的项目中。之后,您可以在项目的 content 文件夹中找到一个 .spritefont (XML) 文件。在那里,可以轻松配置所有参数,例如样式、大小或字距调整。

加载字体

[编辑 | 编辑源代码]
SpriteFont spriteFont = contentManager.Load<SpriteFont>("Path//Fontname");

显示字体

[编辑 | 编辑源代码]
spriteBatch.DrawString(spriteFont, textLabel + ": " + textValue, position, textColor);

(半)透明度

[编辑 | 编辑源代码]
Color myTransparentColor = new Color(0, 0, 0, 127);
Rectangle rectangle = new Rectangle();
rectangle.Width = spriteFont.MeasureString(text).X + 10;
rectangle.Height = spriteFont.MeasureString(text).Y + 10;

Texture2D texture = new Texture2D(graphicsDevice, 1, 1);
texture.SetData(new Color[] {color});

spriteBatch.Draw(texture, rectangle, color);

HUD 中的图像

[编辑 | 编辑源代码]

由于没有在画布元素上绘制的概念,图像或精灵是创建 HUD 的重要元素。XNA 支持许多不同的图像格式,例如 .jpeg 或 .png(包括透明度)。

加载图像

[编辑 | 编辑源代码]
contentManager.Load<Texture2D>("Path//Filename")

或者你可以试试这个 

contentManager.Load<Texture2D>(@"Path/Filename")

使用这种方法,我们使用默认的“content”文件夹,并且不需要使用“双重”(“//”)斜杠。

显示图像

[编辑 | 编辑源代码]
spriteBatch.Draw(image, position, null, color, 0 , new Vector2(backgroundImage.Width/2, backgroundImage.Height/2), scale, SpriteEffects.None, 0);

以下组件是可立即使用的模板。它们可以轻松定制以满足个人需求。

XNA 游戏中的文字 HUD 组件。

此组件显示一个文本字段。它可以用来显示各种信息,例如时间、分数或目标。为了提高可读性,文本后面会显示一个半透明的背景。

类变量
[编辑 | 编辑源代码]
private SpriteBatch spriteBatch;
private SpriteFont spriteFont;
private GraphicsDevice graphicsDevice;

private Vector3 position;

private String textLabel;
private String textValue;
private Color textColor;

private bool enabled;
构造函数
[编辑 | 编辑源代码]
/// <summary>
/// Creates a new TextComponent for the HUD.
/// </summary>
/// <param name="textLabel">Label text that is displayed before ":".</param>
/// <param name="position">Component position on the screen.</param>
/// <param name="spriteBatch">SpriteBatch that is required to draw the sprite.</param>
/// <param name="spriteFont">Font that will be used to display the text.</param>
/// <param name="graphicsDevice">Graphicsdevice that is required to create the semi transparent background texture.</param>
public TextComponent(String textLabel, Vector2 position, SpriteBatch spriteBatch, SpriteFont spriteFont, GraphicsDevice graphicsDevice)
   {
   this.textLabel = textLabel.ToUpper();
   this.position = position;
            
   this.spriteBatch = spriteBatch;
   this.spriteFont = spriteFont;
   this.graphicsDevice = graphicsDevice;
   }
/// <summary>
/// Sets whether the component should be drawn.
/// </summary>
/// <param name="enabled">enable the component</param>
public void Enable(bool enabled)
   {
   this.enabled = enabled;
   }
/// <summary>
/// Updates the text that is displayed after ":".
/// </summary>
/// <param name="textValue">Text to be displayed.</param>
/// <param name="textColor">Text color.</param>
public void Update(String textValue, Color textColor)
   {
   this.textValue = textValue.ToUpper();
   this.textColor = textColor;
   }
/// <summary>
/// Draws the TextComponent with the values set before.
/// </summary>
public void Draw()
   {
   if (enabled)
      {
      Color myTransparentColor = new Color(0, 0, 0, 127);
      
      Vector2 stringDimensions = spriteFont.MeasureString(textLabel + ": " + textValue);
      float width = stringDimensions.X;
      float height = stringDimensions.Y;

      Rectangle backgroundRectangle = new Rectangle();
      backgroundRectangle.Width = (int)width + 10;
      backgroundRectangle.Height = (int)height + 10;
      backgroundRectangle.X = (int)position.X - 5;
      backgroundRectangle.Y = (int)position.Y - 5;

      Texture2D dummyTexture = new Texture2D(graphicsDevice, 1, 1);
      dummyTexture.SetData(new Color[] { myTransparentColor });

      spriteBatch.Draw(dummyTexture, backgroundRectangle, myTransparentColor);
      spriteBatch.DrawString(spriteFont, textLabel + ": " + textValue, position, textColor);
      }
   }
XNA 游戏中的仪表 HUD 组件。

此组件显示一个圆形仪表。它可以用来显示各种信息,例如速度、弹药、燃料、高度/深度、角度或温度。背景图像显示在传递的位置。指针图像根据最大值和当前值的比率进行旋转。旋转角度经过插值以创建平滑、逼真的效果。

类变量
[编辑 | 编辑源代码]
private SpriteBatch spriteBatch;

private const float MAX_METER_ANGLE = 230;
private bool enabled = false;

private float scale;
private float lastAngle;

private Vector2 meterPosition;
private Vector2 meterOrigin;

private Texture2D backgroundImage;
private Texture2D needleImage;

public float currentAngle = 0;
构造函数
[编辑 | 编辑源代码]
/// <summary>
/// Creates a new TextComponent for the HUD.
/// </summary>
/// <param name="position">Component position on the screen.</param>
/// <param name="backgroundImage">Image for the background of the meter.</param>
/// <param name="needleImage">Image for the neede of the meter.</param>
/// <param name="spriteBatch">SpriteBatch that is required to draw the sprite.</param>
/// <param name="scale">Factor to scale the graphics.</param>
public MeterComponent(Vector2 position, Texture2D backgroundImage, Texture2D needleImage, SpriteBatch spriteBatch, float scale)
   {
   this.spriteBatch = spriteBatch;
   
   this.backgroundImage = backgroundImage;
   this.needleImage = needleImage;
   this.scale = scale;
   
   this.lastAngle = 0;

   meterPosition = new Vector2(position.X + backgroundImage.Width / 2, position.Y + backgroundImage.Height / 2);
   meterOrigin = new Vector2(52, 18);
   }
/// <summary>
/// Sets whether the component should be drawn.
/// </summary>
/// <param name="enabled">enable the component</param>
public void Enable(bool enabled)
   {
   this.enabled = enabled;
   }
/// <summary>
/// Updates the current value of that should be displayed.
/// </summary>
/// <param name="currentValue">Value that to be displayed.</param>
/// <param name="maximumValue">Maximum value that can be displayed by the meter.</param>
public void Update(float currentValue, float maximumValue)
   {
   currentAngle = MathHelper.SmoothStep(lastAngle, (currentValue / maximumValue) * MAX_METER_ANGLE, 0.2f);
   lastAngle = currentAngle;
   }
/// <summary>
/// Draws the MeterComponent with the values set before.
/// </summary>
public void Draw()
   {
   if (enabled)
      {
      spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
      spriteBatch.Draw(backgroundImage, meterPosition, null, Color.White, 0, new Vector2(backgroundImage.Width / 2, backgroundImage.Height / 2), scale, SpriteEffects.None, 0); //Draw(backgroundImage, position, Color.White);
      spriteBatch.Draw(needleImage, meterPosition, null, Color.White, MathHelper.ToRadians(currentAngle), meterOrigin, scale, SpriteEffects.None, 0);
      spriteBatch.End();
      }
   }
XNA 游戏中的雷达 HUD 组件。

此组件显示雷达地图。它可以用来显示各种信息,例如目标或敌人。背景图像显示在传递的位置。代表地图中对象的点根据位置数组显示。

类变量
[编辑 | 编辑源代码]
private SpriteBatch spriteBatch;
GraphicsDevice graphicsDevice;

private bool enabled = false;

private float scale;
private int dimension;

private Vector2 position;

private Texture2D backgroundImage;

public float currentAngle = 0;

private Vector3[] objectPositions;
private Vector3 myPosition;
private int highlight;
构造函数
[编辑 | 编辑源代码]
/// <summary>
/// Creates a new RadarComponent for the HUD.
/// </summary>
/// <param name="position">Component position on the screen.</param>
/// <param name="backgroundImage">Image for the background of the radar.</param>
/// <param name="spriteBatch">SpriteBatch that is required to draw the sprite.</param>
/// <param name="scale">Factor to scale the graphics.</param>
/// <param name="dimension">Dimension of the world.</param>
/// <param name="graphicsDevice">Graphicsdevice that is required to create the textures for the objects.</param>
public RadarComponent(Vector2 position, Texture2D backgroundImage, SpriteBatch spriteBatch, float scale, int dimension, GraphicsDevice graphicsDevice)
   {
   this.position = position;

   this.backgroundImage = backgroundImage;

   this.spriteBatch = spriteBatch;
   this.graphicsDevice = graphicsDevice;

   this.scale = scale;
   this.dimension = dimension;
   }
/// <summary>
/// Sets whether the component should be drawn.
/// </summary>
/// <param name="enabled">enable the component</param>
public void Enable(bool enabled)
   {
   this.enabled = enabled;
   }
/// <summary>
/// Updates the positions of the objects to be drawn and the angle for the rotation of the radar.
/// </summary>
/// <param name="objectPositions">Position of all objects to be drawn.</param>
/// <param name="highlight">Index of the object to be highlighted. Object with a smaller or a 
/// greater index will be displayed in a smaller size and a different color.</param>
/// <param name="currentAngle">Angle for the rotation of the radar.</param>
/// <param name="myPosition">Position of the player.</param>
public void update(Vector3[] objectPositions, int highlight, float currentAngle, Vector3 myPosition)
   {
   this.objectPositions = objectPositions;
   this.highlight = highlight;
   this.currentAngle = currentAngle;
   this.myPosition = myPosition;
   }
/// <summary>
/// Draws the RadarComponent with the values set before.
/// </summary>
public void Draw()
   {
   if (enabled)
      {
      spriteBatch.Draw(backgroundImage, position, null, Color.White,0 , new Vector2(backgroundImage.Width / 2, backgroundImage.Height / 2), scale, SpriteEffects.None, 0);
                
       for(int i = 0; i< objectPositions.Length; i++)
          {
          Color myTransparentColor = new Color(255, 0, 0);
          if (highlight == i)
             {
             myTransparentColor = new Color(255, 255, 0);
             }
          else if(highlight > i)
             {
             myTransparentColor = new Color(0, 255, 0);
             }

          Vector3 temp = objectPositions[i];
          temp.X = temp.X / dimension * backgroundImage.Width / 2 * scale;
          temp.Z = temp.Z / dimension * backgroundImage.Height / 2 * scale;

          temp = Vector3.Transform(temp, Matrix.CreateRotationY(MathHelper.ToRadians(currentAngle)));

          Rectangle backgroundRectangle = new Rectangle();
          backgroundRectangle.Width = 2;
          backgroundRectangle.Height = 2;
          backgroundRectangle.X = (int) (position.X + temp.X);
          backgroundRectangle.Y = (int) (position.Y + temp.Z);

          Texture2D dummyTexture = new Texture2D(graphicsDevice, 1, 1);
          dummyTexture.SetData(new Color[] { myTransparentColor });

          spriteBatch.Draw(dummyTexture, backgroundRectangle, myTransparentColor);
          }

       myPosition.X = myPosition.X / dimension * backgroundImage.Width / 2 * scale;
       myPosition.Z = myPosition.Z / dimension * backgroundImage.Height / 2 * scale;

       myPosition = Vector3.Transform(myPosition, Matrix.CreateRotationY(MathHelper.ToRadians(currentAngle)));

       Rectangle backgroundRectangle2 = new Rectangle();
       backgroundRectangle2.Width = 5;
       backgroundRectangle2.Height = 5;
       backgroundRectangle2.X = (int)(position.X + myPosition.X);
       backgroundRectangle2.Y = (int)(position.Y + myPosition.Z);

       Texture2D dummyTexture2 = new Texture2D(graphicsDevice, 1, 1);
       dummyTexture2.SetData(new Color[] { Color.Pink });

       spriteBatch.Draw(dummyTexture2, backgroundRectangle2, Color.Pink);
       }
   }
XNA 游戏中的条形 HUD 组件。

此组件显示一个条形图。它可以用来显示任何与百分比相关的资讯(例如,燃料、健康状况或到达目标剩余时间)。当前百分比值由彩色条形的长度表示。根据显示的值,颜色从绿色变为黄色再变为红色。

类变量
[编辑 | 编辑源代码]
 private SpriteBatch spriteBatch;
private GraphicsDevice graphicsDevice;

private Vector2 position;
private Vector2 dimension;

private float valueMax;
private float valueCurrent;

private bool enabled;
构造函数
[编辑 | 编辑源代码]
/// <summary>
/// Creates a new Bar Component for the HUD.
/// </summary>
/// <param name="position">Component position on the screen.</param>
/// <param name="dimension">Component dimensions.</param>
/// <param name="valueMax">Maximum value to be displayed.</param>
/// <param name="spriteBatch">SpriteBatch that is required to draw the sprite.</param>
/// <param name="graphicsDevice">Graphicsdevice that is required to create the semi transparent background texture.</param>
public BarComponent(Vector2 position, Vector2 dimension, float valueMax, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
   {
   this.position = position;
   this.dimension = dimension;
   this.valueMax = valueMax;
   this.spriteBatch = spriteBatch;
   this.graphicsDevice = graphicsDevice;
   this.enabled = true;
   }
/// <summary>
/// Sets whether the component should be drawn.
/// </summary>
/// <param name="enabled">enable the component</param>
public void enable(bool enabled)
   {
   this.enabled = enabled;
   }
/// <summary>
/// Updates the text that is displayed after ":".
/// </summary>
/// <param name="valueCurrent">Text to be displayed.</param>
public void update(float valueCurrent)
   {
   this.valueCurrent = valueCurrent;
   }
/// <summary>
/// Draws the BarComponent with the values set before.
/// </summary>
public void Draw()
   {
   if (enabled)
      {
      float percent = valueCurrent / valueMax;

      Color backgroundColor = new Color(0, 0, 0, 128);
      Color barColor = new Color(0, 255, 0, 200);
      if (percent < 0.50)
         barColor = new Color(255, 255, 0, 200);
      if (percent < 0.20)
         barColor = new Color(255, 0, 0, 200);

      Rectangle backgroundRectangle = new Rectangle();
      backgroundRectangle.Width = (int)dimension.X;
      backgroundRectangle.Height = (int)dimension.Y;
      backgroundRectangle.X = (int)position.X;
      backgroundRectangle.Y = (int)position.Y;

      Texture2D dummyTexture = new Texture2D(graphicsDevice, 1, 1);
      dummyTexture.SetData(new Color[] { backgroundColor });

      spriteBatch.Draw(dummyTexture, backgroundRectangle, backgroundColor);

      backgroundRectangle.Width = (int)(dimension.X*0.9);
      backgroundRectangle.Height = (int)(dimension.Y*0.5);
      backgroundRectangle.X = (int)position.X + (int)(dimension.X * 0.05);
      backgroundRectangle.Y = (int)position.Y + (int)(dimension.Y*0.25);

      spriteBatch.Draw(dummyTexture, backgroundRectangle, backgroundColor);

      backgroundRectangle.Width = (int)(dimension.X * 0.9 * percent);
      backgroundRectangle.Height = (int)(dimension.Y * 0.5);
      backgroundRectangle.X = (int)position.X + (int)(dimension.X * 0.05);
      backgroundRectangle.Y = (int)position.Y + (int)(dimension.Y * 0.25);

      dummyTexture = new Texture2D(graphicsDevice, 1, 1);
      dummyTexture.SetData(new Color[] { barColor });

      spriteBatch.Draw(dummyTexture, backgroundRectangle, barColor);
      }
   }
[编辑 | 编辑源代码]

UI 游戏设计

[编辑 | 编辑源代码]
  1. 电子游戏界面设计
  2. 重新思考游戏设计中的 HUD
  3. 关于 HUD 的想法

Photoshop 中的 HUD 设计

[编辑 | 编辑源代码]
  1. 钢铁侠视角界面
  2. 高科技风格的 HUD 环
  1. HUD 的字体

参考资料

[编辑 | 编辑源代码]
  1. XNA 3.0 游戏编程入门:从新手到专业人士;Alexandre Santos Lobão、Bruno Evangelista、José Antonio Leal de Farias、Riemer Grootjans,2009
  2. Microsoft® XNA Game Studio 3.0 Unleashed;Chad Carter;2009
  3. Microsoft® XNA Game Studio 创建者指南:XNA 游戏编程入门;Stephen Cawood、Pat McGee,2007


Christian Höpfner

华夏公益教科书