2017年8月13日 星期日

小山的 C# 教學-第43課-五子棋小遊戲(四)-判斷交差點的位置

本課簡介

來到五子棋系列第四課囉!
這課的目標在於讓程式能夠辨識棋盤上的交叉點
讓程式能夠知道玩家是否正在將棋子放到正確的位置上
這對接下來的課程要實作的放棋子以及勝負判斷都很有幫助!

教學影片

注意:影片有高畫質 720P 的選項,可以看得更清楚喔!



重點提示

製作重點

  1. 本課目標:判斷點按的位置是否為交叉點上或附近,並改變游標圖案提示使用者。
  2. 將棋盤的交叉點用二為座標表示。越往右,X 座標越高;越往下,Y 座標越高。
  3. 建議將預計完成的主要目標用註解寫進 method 裡面,再開始撰寫程式碼。
  4. 計算一個位置 X 靠近哪個點的方法如下 (Offset 代表棋盤到邊界的距離,Distance 代表相鄰兩點的距離,R 代表多靠近一個點會被判斷在「附近」):
    1. 首先計算 (X - Offset) ÷ Distance 取得商數與餘數,商數代表左邊的點的編號,餘數代表與左邊的點的距離。
    2. 判斷餘數是否小於等於 R,是的話代表 X 靠近左邊的點,回傳商數。
    3. 判斷餘數是否大於等於 Distance - R,是的話代表靠近右邊的點,回傳商數+1。

製作步驟

  1. 新增一個名為 Board 的 class 用來負責關於棋盤的操作,以下操作都在 Board 內進行。
  2. 新增一個 public method,CanBePlaced(int x, int y),回傳 bool。
  3. 新增一個 private method,FindTheClosetNode(int x, int y),回傳 Point。
  4. 新增一個 private method,FindTheClosetNode(int pos),回傳 int。
  5. 新增三個常數,int OFFSET = 75, int NODE_RADIUS = 10, int NODE_DISTANCE = 75。
  6. 在第 4 步驟新增的 method 中實作「製作重點」第 4 點中的演算法。
  7. 新增一個常數 Point NO_SUCH_NODE = new Point(-1, -1),代表沒有找到符合的交叉點。
  8. 在第 3 步驟新增的 method 中分別計算最靠近 x, y 的交叉點。
  9. 實作第 2 步驟新增的 method。
    1. 利用剛剛寫好的 method 找到最近的交叉點
    2. 沒有的話回傳 false,有的話回傳 true
  10. 在 Form1 中新增一個事件 MouseMove 的 method。
  11. 在 Form 1 新增一個 Board 物件。
  12. 在第 10 步新增的 method 中,藉由呼叫 board.CanBePlaced(x, y) 來判斷是否可以放棋子。
    1. 如果可以的話,將游標設為手。
    2. 如果不行的話,將游標設為預設圖案。
  13. 解決游標在邊界也會變成手的問題。
    • 在 FindTheClosetNode 增加一個判斷,檢查座標是否在 (Offset - R) 之外。如果是的話就直接回傳 -1。

9 則留言:

  1. 小山老師菩薩方便時可否隨附一下您的程式碼好供末學錄至VS研參。感恩感恩 南無阿彌陀佛

    回覆刪除
  2. 祈請小山老師菩薩有空也教教我們如何利用程式畫精準的棋盤吧 感恩感恩 南無阿彌陀佛

    回覆刪除
  3. 非常期待山神接下來五子棋的續集

    回覆刪除
  4. 小山老师好,直接使用鼠标事件的坐标应该是显示屏幕的坐标吧?项目应用的应该是窗体内的坐标,定义的offset =75 也是以窗体为参考系计算的吧?程序里面是怎么设置的?没有看到你的设置,我是这样处理后就正确了oint formPoint = this.PointToClient(Control.MousePosition);//设置窗体控件内的鼠标坐标
    Board board = new Board();
    if (board.CanBePlaced(formPoint.X, formPoint.Y))
    {
    this.Cursor = Cursors.Hand;
    }
    else
    {
    this.Cursor = Cursors.Default;
    }

    回覆刪除
  5. 老師您好,請問return後面的quotient,為什麼顯示錯誤,「無法將類型int,隱含轉換成system.Drawing.point」,上網查詢後只有說要加using System.Drawing,這個我也有加了。

    private Point FindTheClosetNode(int pos)
    {
    pos -= OFFSET;
    int quotient = pos / NODE_DISTRANCE;
    int remainder = pos % NODE_DISTRANCE;

    if (remainder <= NODE_RADIUS)
    return quotient;
    else if (remainder >= NODE_DISTRANCE - NODE_RADIUS)
    return quotient + 1;
    else
    return -1;

    回覆刪除
    回覆
    1. 重新看完影片找到原因了,private Point FindTheClosetNode(int pos),這一段要宣告成int,private int FindTheClosetNode(int pos)。謝謝老師的教學。

      刪除