使用Xamarin開發移動應用示例——數獨遊戲(五)儲存遊戲進度

尋找無名的特質發表於2022-01-30

專案程式碼可以從Github下載:https://github.com/zhenl/ZL.Shudu 。程式碼隨專案進度更新。

儲存進度是移動應用的基本功能,在應用的使用過程中會有各種各樣的可能導致使用中斷,再次回到應用時,應該恢復到中斷前的狀態。前面我們已經初步完成了數獨遊戲,但還不具備狀態儲存的功能,現在我們增加這個功能,將遊戲進度儲存到本地檔案中。

首先確定在什麼地方儲存和恢復狀態。在Xamarin的View退出時會觸發OnDisappearing事件,在這個事件中可以儲存遊戲的進度。在View再次顯示時,首先判斷是否存在以儲存的進度,如果存在,就恢復狀態,否則建立新的遊戲。

然後確定需要儲存的內容,需要儲存當前已經輸入的數字和位置,還需要儲存輸入的過程以及花費的時間。

還有就是儲存的位置,Xamarin提供了每個應用儲存資料的抽象位置,我們可以使用Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)來獲取路徑而不需要考慮裝置型別。

所有這些確定好之後,就可以編寫相應的邏輯了。

首先是儲存狀態的方法:

      private void Save(string filename)
        {
            try
            {
                var strchess = "";
                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        strchess += chess[i, j].ToString();
                    }
                }
                strchess += " ";
                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        strchess += string.IsNullOrEmpty(buttons[i, j].Text) ? "0" : buttons[i, j].Text;
                    }
                }
                strchess += " ";
                foreach (var str in steps)
                {
                    strchess += str + ";";
                }
                strchess += " ";
                strchess += (DateTime.Now - dtBegin).Ticks.ToString();
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), filename);
                File.WriteAllText(_fileName, strchess);
            }
            catch (Exception ex)
            {

                lbMessage.Text = ex.Message;
            }
        }

在OnDisappearing事件響應中呼叫這個方法:

        protected override void OnDisappearing()
        {
            Save("shudu_current.txt");
        }

恢復狀態的函式如下:

     private bool OpenCurrent()
        {
            try
            {
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shudu_current.txt");
                if (File.Exists(_fileName))
                {
                    var strchess = File.ReadAllText(_fileName);
                    int[,] fchess = new int[9, 9];
                    var arr = strchess.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    for (var i = 0; i < 9; i++)
                    {
                        for (var j = 0; j < 9; j++)
                        {
                            chess[i, j] = int.Parse(arr[0].Substring(i * 9 + j, 1));
                            fchess[i, j] = int.Parse(arr[1].Substring(i * 9 + j, 1));
                        }
                    }
                    for (var i = 0; i < 9; i++)
                    {
                        for (var j = 0; j < 9; j++)
                        {
                            var btn = buttons[i, j];
                            if (chess[i, j] > 0)
                            {
                                btn.Text = chess[i, j].ToString();
                            }
                            else
                            {
                                btn.Text = fchess[i, j] > 0 ? fchess[i, j].ToString() : "";
                            }
                            btn.IsEnabled = chess[i, j] == 0;
                            int m = i / 3;
                            int n = j / 3;

                            var c = new Color(0.9, 0.9, 0.9);
                            if ((m + n) % 2 == 0)
                            {
                                c = new Color(0.7, 0.7, 0.7);
                            }
                            btn.BackgroundColor = c;
                        }
                    }
                    if (arr.Length > 2)
                    {
                        var steparr = arr[2].Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        steps.Clear();
                        foreach(var step in steparr) steps.Push(step);
                    }
                    if (arr.Length > 3)
                    {
                        currentDiffer = long.Parse(arr[3]);
                    }
                    dtBegin = DateTime.Now;
                    return true;
                }
            }
            catch (Exception ex)
            {

                lbMessage.Text = ex.Message;
            }
            return false;
        }

在初始化時呼叫這個函式:

        public Game()
        {
            try
            {
                InitializeComponent();

                SetNumButtons();
                SetLayout();
                if (!OpenCurrent()) SetNewGame();

            }
            catch (Exception ex)
            {
                lbMessage.IsVisible = true;
                rowResult.Height = 40;
                lbMessage.Text = ex.Message;
                //throw;
            }
        }

最後,在遊戲完成時刪除狀態檔案:

            if (IsFinish())
            {
                lbFinish.IsVisible = true;
                lbTime.IsVisible = true;
                rowResult.Height = 40;
                var diff = (DateTime.Now.Ticks - dtBegin.Ticks + currentDiffer) / 10000 / 1000 / 60;
                lbTime.Text = diff + "分鐘";
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shudu_current.txt");
                File.Delete(_fileName);
            }

狀態儲存完成了。下一步,我們引入資料庫,儲存遊戲結果,並增加新遊戲的錄入功能。

相關文章