I enabled SpriteSortMode.FrontToBack in my drawing callback:
/// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { Resolution.BeginDraw(); spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, null, null, RasterizerState.CullCounterClockwise, null, Resolution.getTransformationMatrix()); m_ScrManager.Draw(); spriteBatch.End(); //Reset device to defaults before rendering... GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap; GraphicsDevice.Viewport = new Viewport(0, 0, GlobalSettings.Default.ScreenWidth, GlobalSettings.Default.ScreenHeight); GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 0.5f, 1); m_ScrManager.Draw3D(); HitVM.Step(); base.Draw(gameTime); }
Then, in my UIScreen.Draw method, I did:
public virtual void Draw() { foreach (KeyValuePair<string, UIElement> KVP in m_Elements) { try { if (KVP.Value is UIDialog || KVP.Value is WillWrightDiag) KVP.Value.Draw(m_SBatch, UIElement.GetLayerDepth(LayerDepth.DialogLayer)); else if (KVP.Value is UIButton) KVP.Value.Draw(m_SBatch, UIElement.GetLayerDepth(LayerDepth.ButtonLayer)); else if (KVP.Value is UIImage) KVP.Value.Draw(m_SBatch, UIElement.GetLayerDepth(LayerDepth.ImageLayer)); else KVP.Value.Draw(m_SBatch, UIElement.GetLayerDepth(LayerDepth.Default)); } catch(Exception) { continue; } } }
Here is UIElement.GetLayerDepth:
/// <summary> /// Gets the value of the corresponding layer depth. /// </summary> /// <param name="Depth">The depth for which to retrieve a value.</param> /// <returns>The value of the specified depth.</returns> public static float GetLayerDepth(LayerDepth Depth) { switch(Depth) { case LayerDepth.Default: return 0.0f; case LayerDepth.ImageLayer: return 0.8f; case LayerDepth.ButtonLayer: return 0.9f; case LayerDepth.DialogLayer: return 0.10f; default: return 0.0f; } }
Then in Credits.cs, I added the WillWrightDiag to my list of elements to be drawn by UIScreen.Elements, as such:
m_WillWrightDiag = new WillWrightDiag(WillImage, this, new Vector2(100, 100)); m_WillWrightDiag.IsDrawn = false; m_Elements.Add("WillWrightDiag", m_WillWrightDiag);
Here's how I draw a UIDialog:
public override void Draw(SpriteBatch SBatch, float? LayerDepth) { float Depth; if (LayerDepth != null) Depth = (float)LayerDepth; else Depth = 0.10f; if (IsDrawn) { Image.DrawTextureTo(SBatch, null, Image.Slicer.TLeft, Image.Position + Vector2.Zero, Depth); Image.DrawTextureTo(SBatch, Image.Slicer.TCenter_Scale, Image.Slicer.TCenter, Image.Position + new Vector2(Image.Slicer.LeftPadding, 0), Depth); Image.DrawTextureTo(SBatch, null, Image.Slicer.TRight, Image.Position + new Vector2(Image.Slicer.Width - Image.Slicer.RightPadding, 0), Depth); Image.DrawTextureTo(SBatch, Image.Slicer.CLeft_Scale, Image.Slicer.CLeft, Image.Position + new Vector2(0, Image.Slicer.TopPadding), null); Image.DrawTextureTo(SBatch, Image.Slicer.CCenter_Scale, Image.Slicer.CCenter, Image.Position + new Vector2(Image.Slicer.LeftPadding, Image.Slicer.TopPadding), Depth); Image.DrawTextureTo(SBatch, Image.Slicer.CRight_Scale, Image.Slicer.CRight, Image.Position + new Vector2(Image.Slicer.Width - Image.Slicer.RightPadding, Image.Slicer.TopPadding), Depth); int BottomY = Image.Slicer.Height - Image.Slicer.BottomPadding; Image.DrawTextureTo(SBatch, null, Image.Slicer.BLeft, Image.Position + new Vector2(0, BottomY), null); Image.DrawTextureTo(SBatch, Image.Slicer.BCenter_Scale, Image.Slicer.BCenter, Image.Position + new Vector2(Image.Slicer.LeftPadding, BottomY), Depth); Image.DrawTextureTo(SBatch, null, Image.Slicer.BRight, Image.Position + new Vector2(Image.Slicer.Width - Image.Slicer.RightPadding, BottomY), Depth); if (m_HasExitBtn) { m_CloseBtnBack.Draw(SBatch, null, Depth); m_CloseButton.Draw(SBatch, Depth); } } }
And here's how I draw a WillWrightDiag, which inherits from UIDialog:
public override void Draw(SpriteBatch SBatch, float? LayerDepth) { float Depth; if (LayerDepth != null) Depth = (float)LayerDepth; else Depth = 0.10f; if (IsDrawn) SBatch.Draw(m_WillWrightImg.Texture, m_WillWrightImg.Position, null, null, new Vector2(0.0f, 0.0f), 0.0f, null, Color.White, SpriteEffects.None, Depth); base.Draw(SBatch, LayerDepth); }
Despite this, I still get this weird case where the Maxis-button is drawn on top of the dialog and the exit button is occasionally not drawn.
Why? :\
Is there a better, less error-prone way to achieve depth sorting?
Here is the entire code for Credits.cs if it helps:
using System; using System.Timers; using System.Collections.Generic; using System.Text; using Gonzo; using Gonzo.Elements; using Files.Manager; using Files.IFF; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace GonzoTest { public class CreditsScreen : UIScreen { private UIImage BackgroundImg, TSOLogoImage, BackButtonIndentImage, WillImage; private UIButton MaxisButton; private Iff m_Credits; private List<string> m_CreditsStrings = new List<string>(); private UIControl m_CreditsArea; private float m_CreditsY = 0; //Upwards position of credits text. private float m_CreditsCenterX = 0; //Center of credits area. private Timer m_CreditsTimer; //Timer for controlling text scroll. private WillWrightDiag m_WillWrightDiag; public CreditsScreen(ScreenManager Manager, SpriteBatch SBatch) : base(Manager, "Credits", SBatch, new Vector2(0, 0), new Vector2(GlobalSettings.Default.ScreenWidth, GlobalSettings.Default.ScreenHeight), GlobalSettings.Default.StartupPath + "\\" + "gamedata\\uiscripts\\credits.uis") { BackgroundImg = (UIImage)m_Elements["\"BackgroundImage\""]; TSOLogoImage = m_Controls["\"TSOLogoImage\""].Image; BackButtonIndentImage = m_Controls["\"BackButtonIndentImage\""].Image; WillImage = (UIImage)m_Elements["\"WillImage\""]; MaxisButton = (UIButton)m_Elements["\"MaxisButton\""]; MaxisButton.OnButtonClicked += MaxisButton_OnButtonClicked; m_WillWrightDiag = new WillWrightDiag(WillImage, this, new Vector2(100, 100)); m_WillWrightDiag.IsDrawn = false; m_Elements.Add("WillWrightDiag", m_WillWrightDiag); m_Credits = FileManager.GetIFF("credits.iff"); m_CreditsArea = (UIControl)m_Controls["\"CreditsArea\""]; m_CreditsY = m_CreditsArea.Size.Y; foreach(TranslatedString TStr in m_Credits.GetSTR(163).GetStringList(LanguageCodes.EngUS)) { foreach (string Str in TStr.TranslatedStr.Split('\n')) m_CreditsStrings.Add(Str); } m_CreditsTimer = new Timer(300); m_CreditsTimer.Elapsed += M_CreditsTimer_Elapsed; m_CreditsTimer.Start(); } private void M_CreditsTimer_Elapsed(object sender, ElapsedEventArgs e) { m_CreditsY -= 1.5f; } private void MaxisButton_OnButtonClicked(UIButton ClickedButton) { m_WillWrightDiag.IsDrawn = true; } public override void Update(InputHelper Input) { m_WillWrightDiag.Update(Input); base.Update(Input); } public override void Draw() { BackgroundImg.Draw(m_SBatch, null, 0.0f); TSOLogoImage.Draw(m_SBatch, null, 0.0f); BackButtonIndentImage.Draw(m_SBatch, null, 0.0f); float Separation = 1.0f; foreach (string Str in m_CreditsStrings) { m_CreditsCenterX = (m_CreditsArea.Size.X / 2) - (Manager.Font12px.MeasureString(Str).X / 2); if ((m_CreditsY + Separation) > m_CreditsArea.Position.Y && (m_CreditsY + Separation) < m_CreditsArea.Size.Y) { m_SBatch.DrawString(Manager.Font12px, Str, new Vector2(m_CreditsArea.Position.X + m_CreditsCenterX, m_CreditsY + Separation), Color.Wheat); } Separation += 15.0f; } base.Draw(); } } }
Also, why is the chat down? :\ There's a much higher signal to noise ratio in the chat.