3.3記錄錯誤資訊
調試代碼非常複雜,特別是渲染迴圈出錯了,但您卻得不到任何異常。只設定幾個調試斷點並不夠,尤其是當遊戲運行一段時間之後出現了錯誤,調試並不是合適的選擇。您或許想知道每一幀都發生了什麼,但又不想一步步地跟蹤它。對於這類問題,您可以給控制台輸出一些資訊,不過這隻能在Visual Studio中使用,而且當下次啟動項目時這些資訊就沒了。
在我做過的比較大型的項目中,有一個類非常重要,那就是Log類,它用來往一個文字檔中記錄訊息、警告、錯誤或者調試資訊。這個類本身很簡短,也很簡單,但如果正確地使用它,會給您的調試和測試帶來很大的樂趣。另外還有其他很多更加進階的日誌記錄類和架構(logging classes and
frameworks)可以用,比如Log4Net,可以在這裡得到:http://logging.apache.org/log4net
。日誌並非僅僅記錄幾行資訊那麼簡單,您可以使用一個WebService來遠程擷取使用者使用您的應用程式時的日誌資訊,可以啟用Windows錯誤事件,還可以做很多其他事情。本書並沒有過多地討論,因為這是一個很複雜的話題。對於本書中的簡單遊戲,使用Log類就足夠了。
先看一看Log類的實現(在Breakout遊戲中有一個更複雜的版本):
public class Log
{
#region Variables
private static StreamWriter writer = null;
private const string LogFilename = "Log.txt";
#endregion
它使用一個Log.txt檔案來儲存所有訊息,並使用一個靜態StreamWriter對象,以便可以方便地在靜態方法中訪問。當這個類第一次被調用的時候,就會通過其靜態構造器被初始化:
#region Static constructor to create log file
static Log()
{
// Open file
FileStream file = new FileStream(
LogFilename, FileMode.OpenOrCreate,
FileAccess.Write, FileShare.ReadWrite);
writer = new StreamWriter(file);
// Go to end of file
writer.BaseStream.Seek(0, SeekOrigin.End);
// Enable auto flush (always be up to date when reading!)
writer.AutoFlush = true;
// Add some info about this session
writer.WriteLine("/// Session started at: " +
StringHelper.WriteIsoDateAndTime(DateTime.Now));
} // Log()
#endregion
枚舉值FileShare.ReadWrite可以確保在遊戲啟動並執行時候從外部讀寫檔案。除了這個還要把writer的位置設定到檔案的末尾,啟用屬性AutoFlush可以確保新資料會被立即寫入記錄檔中,最後再添加某次操作開始的時間資訊。要記錄會話發生的時間還需要使用輔助類StringHelper的一個方法,稍後將介紹。
最後,是這個類的最重要、也是您將一直調用的唯一的一個方法:
#region Write log entry
static public void Write(string message)
{
DateTime ct = DateTime.Now;
string s = "[" + ct.Hour.ToString("00") + ":" +
ct.Minute.ToString("00") + ":" +
ct.Second.ToString("00") + "] " +
message;
writer.WriteLine(s);
#if DEBUG
// In debug mode write that message to the console as well!
System.Console.WriteLine(s);
#endif
} // Write(message)
#endregion
首先,在訊息的前面加上一個時間戳記,然後把訊息寫入Log.txt檔案中,最後如果在調試項目,把訊息輸出到控制台。現在,您可以為Breakout遊戲添加日誌功能,每當您升級的時候在Log.txt檔案的最後添加一行升級訊息,如下所示:
Log.Write("Level " + level + " completed.");