跳轉到內容

使用 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

華夏公益教科書