XNA用のシンプルなGUI

良い一日。 この記事では、プログラミングの新しい側面を紹介することはせず、問題を解決するクールな方法については説明しません。 さびた古いバイクですが、外出先では、長い道のりです...







だから


XNAで最初の「深刻な」ゲームを書き始めたとき、このエンジンに標準のGUIがないという問題がありました。 私は学んでいるので、あまり経験がなく、独自のインターフェースシステムを作成することに決めました。 既製のツールを使用する代わりに。 基礎は、過去のエンジンHGEで知られている実装から取られました。 そこには革命的なものは何もありませんでした。Guiクラス、GuiObjectクラス、さまざまなボタン、リストなどは後者から継承されます。



基本コード
class Gui { public GuiObject elements[]; public Gui() { elements = new GuiObject[6]; } } class GuiObject { public Rectangle rect; //    , ,  .. public bool lpressed; //     public bool rpressed; public bool lclick;//      public bool rclick; public GameState drawstate; //    ,    public bool darktransparency; //    ,    public bool lighttransparency; public string text; public bool undercursor; public GuiObject(Rectangle rec, bool dtr, bool ltr, GameState st, UpdateFunction f,DrawFunction f2, string text = "") { rect = rec; lpressed = false; rpressed = false; enable = true; lclick = false; rclick = false; darktransparency = dtr; lighttransparency = ltr; drawstate = st; this.text = text; updateFunction = f; drawFunction = f2; } } public enum GameState { Any, MainMenu, Game }
      
      







これで、基地の準備が整いました。 次の問題はイベント処理です。 このコードを書く少し前に、大学は私たちに代表者について話しました。 知らない関数を呼び出すことができるのは、かなり良い能力です。 それらにこだわることが決定されました。 その他の点では、C#のWindowsフォームアプリケーションでボタンを作成するために使用されるデリゲートです。 次のコードがGuiObjectに追加されました。



デリゲートを使用したコード
  public delegate void UpdateFunction(ref GuiObject me); public delegate void DrawFunction(Texture2D line, Texture2D darkbackground, Texture2D lightbackground, ref GuiObject me); public DrawFunction drawFunction; public UpdateFunction updateFunction; /*           . , ,   */ /* line, darkbackground, lightbackground -   ,   */
      
      







ここで、ハンドラー自体を作成する必要がありました。 処理はGuiクラスによって行われます。 すべての要素を反復処理し、要素のdrawstateが渡されたstate引数と一致する場合、処理を続行します。 今からお見せします。



処理中
 //Gui.cs public void Update(MouseState mstate,GameState state,GameTime gameTime) { for (int i = 0; i < elements.Length; i++) { if (elements[i].drawstate == state&&elements[i].enable) { elements[i].Update(mstate); elements[i].updateFunction(ref elements[i]); } } } /*   foreach  for,         */ /*   ?      ( click  pressed),          ( ).*/ // GuiObject.cs public void Update(MouseState state) { lclick = false; rclick = false; if (rect.Contains(new Point(state.X, state.Y))) { if (state.LeftButton == ButtonState.Pressed) if (!lpressed) { lclick = true; lpressed = true; } if (lpressed && state.LeftButton == ButtonState.Released) lpressed = false; if (state.RightButton == ButtonState.Pressed) if (!rpressed) { rclick = true; rpressed = true; } if (rpressed && state.RightButton == ButtonState.Released) rpressed = false; undercursor = true; } else undercursor = false; }
      
      







処理を理解しましたが、レンダリングだけが残っていました。 GameStateにはAnyアイテムがありますか? ボタンを常に...にしたい場合は、他のものが見えます。



描画
 //Gui.cs public void Draw(Texture2D line, Texture2D darkbackground, Texture2D lightbackground, GameState state) { for (int i = 0; i < elements.Length; i++) { if ((elements[i].drawstate == GameState.Any || elements[i].drawstate == state)&&elements[i].enable) elements[i].drawFunction(line, darkbackground, lightbackground, ref elements[i]); } }
      
      







これで、コードの主要部分の準備ができました。 次に、ボタンを作成し、そのボタンのハンドラーとドラフトマンを作成し、コンパイラーを介して無限の実行ループに送信するだけです。 ゲームでは(少なくとも私にとっては)、同じ要素(背景、ストローク、テキスト)を描く必要があります。 したがって、それらのドラフトマンは普遍的ですが、処理は要素ごとに個別に説明する必要があります。



開発したゲームのコードを使用した恐ろしい例
 // void Init() state = GameState.MainMenu; gui = new Gui(); gui.elements[0] = new GuiObject(new Rectangle(0, 0, width-205, height), false, false, GameState.Game, Main, MapGuiDraw); gui.elements[1] = new GuiObject(new Rectangle(width - 205, 0, 205, height), false, false, GameState.Game, RightPanel, RightPanelDraw); gui.elements[2] = new GuiObject(new Rectangle(width - 205, 0, 205, 39), false, false, GameState.Game, GameMenuButton, GameMenuButtonDraw); gui.elements[3] = new GuiObject(new Rectangle((width - 150) / 2, height / 2, 150, 30), false, false, GameState.MainMenu, StartGameButton, StandartButtonDraw, "Start game"); gui.elements[4] = new GuiObject(new Rectangle((width - 150) / 2, height / 2 + 50, 150, 30), false, false, GameState.StartGameMenu, GenerateButton, StandartButtonDraw, "Generate"); //Draw Functions Example void StandartGuiDraw( Texture2D line, Texture2D darkbackground, Texture2D lightbackground, ref GuiObject me) { if (me.darktransparency) DrawTexturedRect( darkbackground, me.rect); if (me.lighttransparency) DrawTexturedRect( lightbackground, me.rect); DrawOutLine(line, me.rect); if (me.text != "") { Vector2 size = font.MeasureString(me.text); spriteBatch.DrawString(font, me.text, new Vector2((int)(me.rect.X + me.rect.Width / 2 - size.X / 2), (int)(me.rect.Y + me.rect.Height / 2 - size.Y / 2)), Color.White); } }
      
      







写真の仕事の例
ゲームタウンズマン(開発中)

メニュー:



マップジェネレーターメニュー:



ゲーム画面:



ゲーム古代帝国

メニュー:



マップエディターメニュー:



マップエディター:





仕事の特徴


このアプローチの主な欠点は、Guiに新しい要素を追加するときに、クラスに登って配列のサイズを変更する必要があることです。 リストを使用して解決されます。



一般に、これが私が話したかったことのすべてです。 ご清聴ありがとうございました。



ゲームについて
素材について:私のゲーム、Townsmanはまだ執筆中です。すぐに仕上げて、それについてお知らせします。

古代の帝国はex.uaまたはgoogleでたくさんの小さなゲームで見つけることができます。



PSあなたが好きではなかったものを書いてください。 説明のない短所は受け入れられません。 :)



All Articles