We use several approaches.
- Obviously, the debugger, but that can fail if the bug you are tracking is so dynamic that debugger stops make the bug go away.
- A popup message method in our Game class that draws a rectangle with a message for a certain number of frames.
- A log error method in our Game class that opens a file for append, writes to it, and closes it. This is great where a developer can email me the file so I can look at it.
- Setting the window title to some message. This is used to constantly show the player Motion State, and the attacked creature Motion state. Very dynamic.
- Writing a long string over the display with error message and stack trace. Ugly but useful.
| public void LogMessage(String m) |
| { |
| #if DEBUG |
| #if !XBOX |
| System.IO.File.AppendAllText("pebblelog.txt", m + "\n"); |
| #endif |
| #endif |
| } |
| |
| public void LogMessage(Exception e) |
| { |
| #if DEBUG |
| String s = ""; |
| s += e.Message; |
| s += "\n"; |
| s += e.StackTrace.ToString(); |
| if (e.InnerException != null && e.InnerException.Message != null) |
| { |
| s += "\n" + e.InnerException.Message; |
| } |
| LogMessage(s); |
| #endif |
| } |
| |
And the popup message code...
| At top of Game... |
| #if DEBUG |
| private String PopMessage = null; |
| private String PopMessage2 = null; |
| int PopMessageFrames = 0; |
| #endif |
| |
| ... And the methods ... |
| /// <summary> |
| /// Default 60 frames, about 1 second. |
| /// </summary> |
| /// <param name="text"></param> |
| public void PopupMessage(String text) |
| { |
| #if DEBUG |
| PopMessage = text; |
| PopMessageFrames = 40; |
| #endif |
| } |
| |
| /// <summary> |
| /// |
| /// </summary> |
| /// <param name="text"></param> |
| /// <param name="frames">We do about 60 frames per second.</param> |
| public void PopupMessage(String text, int frames) |
| { |
| #if DEBUG |
| PopMessage = text; |
| PopMessageFrames = frames; |
| #endif |
| } |
| |
| /// <summary> |
| /// Popup message but tag is the Internationalization resource key. |
| /// </summary> |
| /// <param name="tag"></param> |
| /// <param name="frames"></param> |
| public void PopupMessageI18N(String tag, int frames) |
| { |
| #if DEBUG |
| PopMessage = Pebble.Properties.Resources.ResourceManager.GetString(tag, Pebble.Properties.Resources.Culture).Replace("\\n", Environment.NewLine); |
| PopMessageFrames = frames; |
| #endif |
| } |
| |
| /// <summary> |
| /// Allows for a second line in the popup. |
| /// The second line gets chopped into 50 character chunks of longer than 50. |
| /// </summary> |
| /// <param name="text"></param> |
| /// <param name="textLine2"></param> |
| /// <param name="frames"></param> |
| public void PopupMessage(String text, String textLine2, int frames) |
| { |
| #if DEBUG |
| PopMessage = text; |
| |
| char[ d = new char[1]; |
| d[0] = ' '; |
| String[ s = textLine2.Split(d); |
| String t = ""; |
| int n = 0; |
| foreach (String ss in s) |
| { |
| n += 1 + ss.Length; |
| if (n > 50) |
| { |
| t += "\n"; |
| n = 0; |
| } |
| t += ss; |
| t += " "; |
| } |
| |
| PopMessage2 = t; |
| PopMessageFrames = frames; |
| #endif |
| } |
| |
| .... |
| And near the end of Draw... |
| |
| if (PopMessage != null) |
| { |
| FillRect(new Rectangle(190, 290, 820, 220), Color.DarkGreen); |
| FillRect(new Rectangle(200, 300, 800, 200), Color.LightGreen); |
| DrawText(PopMessage, 310, 310); |
| if (PopMessage2 != null) |
| { |
| DrawText(PopMessage2, 310, 350); |
| } |
| PopMessageFrames--; |
| if (PopMessageFrames <= 0) |
| { |
| PopMessage = null; |
| PopMessage2 = null; |
| } |
| } |
| |
Stack traces can be nice to, without extiting the program...
| private String ErrorMessage = null; |
| private float ErrorMessageTime = 0; |
| |
| ... And the methods... |
| public void SetErrorMessage(String text, Exception e) |
| { |
| #if DEBUG |
| if (e == null) |
| { |
| ErrorMessage = text; |
| } |
| else |
| { |
| ErrorMessage = text + "\n" + e.Message + "\n" + e.StackTrace.ToString(); |
| } |
| ErrorMessageTime = 4.0f; |
| #endif |
| } |
| |
| ... and in Draw... |
| |
| if (ErrorMessage != null) |
| { |
| ErrorMessageTime -= Game1.DeltaT; |
| DrawSmallText(ErrorMessage, 10, 40); |
| if (ErrorMessageTime <= 0) |
| { |
| ErrorMessage = null; |
| } |
| } |
| |
I hope that helps.
P.S. You need this too...
R. Keene
CTO Sandswept Studios LLC
| /// <summary> |
| /// Easy draw text in it's own SpriteBatch in screen coords. |
| /// </summary> |
| /// <param name="t"></param> |
| /// <param name="X"></param> |
| /// <param name="Y"></param> |
| public void DrawText(String t, int X, int Y) |
| { |
| SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, |
| SaveStateMode.None, SpriteScale); |
| SpriteBatch.DrawString(Font, t, new Vector2(X, Y + 1), Color.Black); |
| SpriteBatch.DrawString(Font, t, new Vector2(X, Y), Color.White); |
| SpriteBatch.End(); |
| } |
| |
Inside every complex program is a simple program trying to get out.
Richard Keene - CTO - Sandswept Studios
http://www.sandsweptstudios.net