Geomystery(幾何迷城)的遊戲引擎設計與實現

 在這裏介紹Geomystery(幾何迷城)的遊戲引擎設計與實現。
 
業務邏輯:
引擎採用模塊化的MVC(Model模型,View視圖,Controller控制)設計方式,這樣有助於運用多種設計模式,便於往後的修改與維護。
M模型座標系中的模型是被操做的對象,模型座標系是被「顯示座標系」顯示的單位。
V視圖(顯示座標系)是模型在用戶屏幕的一個投影,這也和顯卡、顯示器的工做原理有關。
C控制器操做某個邏輯座標系模型A,或者每次操做後由控制器直接通知視圖(顯示座標系)刷新模型A的投影a,或者由「監聽器」(監聽者模式)發現模型A被「更新(改變)」,以後通知視圖(顯示座標系)刷新a。

 


顯卡和顯示器:
WIN2D封裝了DirectX,在屏幕上一個區域(DC)顯示一些靜態內容,或者每隔一段時間(通常是1/60s,即60fps)在屏幕上的一個區域刷新顯示一些內容。因此每次刷新,只須要遍歷V視圖(顯示座標系),把其中的內容呈現給用戶,這樣用戶畫線時的動態過程就能夠被看到,同時用戶改變程序窗口大小(刷新顯示區DC)的操做也不會清空屏幕。
M 邏輯座標系,系統座標系
V 顯示座標系,視圖座標系,用戶座標系,用戶屏幕
C 用戶控制器,操縱桿
「橫當作嶺側成峯,遠近高低各不一樣。不識廬山真面目,只緣身在此山中。」廬山只有一座,而在同一時刻,不一樣的人看廬山,能看到不一樣的廬山。因此對於一個「邏輯的」座標系M,可能對應多個「顯示的」座標系V1V2V3V4,每一個顯示座標系Vn都有本身的「操縱桿」Cn與控制器相連,他們均可以經過本身的操縱桿Cx操做本身看到的(實際上是同一個)邏輯座標系。因而,若是多個用戶同時操做,就可能有衝突,須要使用操做系統學到的同步互斥方法,因爲此次生產實習時間有限,因此這裏簡化一下,只有一個控制器,有一個主「屏幕」(視圖顯示座標系),其餘屏幕都是副屏幕,只能觀察,沒有操做功能。一個娃娃機有先後左右四塊玻璃觀察窗,可是隻有一套操縱桿。

邏輯座標系中的元素
0,幾何元素Geometry。幾何元素有一個座標系內惟一的編號(id),記錄了本身的投影(們),記錄了本身受誰影響rely,記錄了本身影響誰influence。
幾何元素分爲點Point和點集合PointSet。
1,點就是一個邏輯點,關鍵屬性是邏輯座標XY。
2,點集是一個接口(interface),由於這款遊戲是尺規做圖,因此點集只分線(Line)和圓(Circle)
(爲何是Circle而不是Ellipse,由於圓規只能畫圓,這裏涉及到圓的定義方式,因此只提供圓工具,橢圓工具能夠後續添加)
點集接口有一個交點List<Point2> IPointSet.Intersection(IPointSet another)函數須要後續實現
3,線分爲線段射線直線,因此咱們須要一個LineType來記錄線的線型
 1 public enum LineType
 2     {
 3         //
 4         // 摘要:
 5         //     直線
 6         Straight = 0,
 7         //
 8         // 摘要:
 9         //     射線
10         Ray = 1,
11         //
12         // 摘要:
13         //     線段
14         Line = 2
15     }
public enum LineType

可是兩點的定義方式並不夠,(p1是第一個點,p2是第二個點),若是用戶是過線(含延長線)和一點作的垂線,這個邏輯也須要體現,canvas

因此咱們須要一個LineRely來記錄線的構造(生成)方式設計模式

 1 public enum LineRely
 2     {
 3         //
 4         // 摘要:
 5         //     常規方式,p1,p2兩點肯定一條直線
 6         Normal = 0,
 7         //
 8         // 摘要:
 9         //     垂線,依賴列表的一條線加上線上或者線外點p1,過p1做依賴點的垂線
10         Perpendicular = 1,
11         //
12         // 摘要:
13         //     垂直平分線,p1,p2兩點連線的中垂線
14         PerpendicularBisector = 2,
15         //
16         // 摘要:
17         //     垂直平分線,p1,p2兩點連線的中垂線
18         AngleBisector = 3,
19     }
public enum LineRely

與構造方式LineRely配套的須要一些屬性(字段),好比垂線構造(三個點,一點一線),中垂線構造(兩個點,一個線段),角平分線構造(三個點,兩條射線)等方式ide

4,圓的構造就容易不少模塊化

兩個點,一個是圓心,另外一個是圓上的一點函數

(爲何不用半徑,由於用戶依靠鼠標的點擊生成圓周上的點,並且這個點是圓的重要的控制點,因此後續半徑須要計算生成)工具

 

視圖座標系中的元素spa

一條邏輯線在一個座標系中有幾個像?是一個嗎?不是。操作系統

在這個引擎中,視圖座標系中的元素是能夠直接顯示的,若是你畫的線是一個線段(或者是一條射線),一條邏輯線就會有兩個視圖線,一條實線,一條虛線,先畫虛線(延長線),在畫實線。設計

視圖座標系中的元素都是幾何體嗎?不是。(註釋和標籤,待實現)3d

視圖座標系中能夠放置OutputText

 1 /// <summary>
 2     /// 屏幕上的提示文本,或者是屏幕上元素的「名字標籤」
 3     /// </summary>
 4     public class OutputText : ICanOutput
 5     {
 6         /// <summary>
 7         /// 文本內容
 8         /// </summary>
 9         public string text { get; set; }
10 
11         /// <summary>
12         /// 在屏幕上的窗體(canva)中,這個文本「寫」在哪裏
13         /// </summary>
14         public Vector2 viewPoint { get; set; }
15 
16         /// <summary>
17         /// 文字顏色
18         /// </summary>
19         public Color fontColor { get; set; }
20 
21         /// <summary>
22         /// 文字格式
23         /// </summary>
24         public CanvasTextFormat format { get; set; }
25 
26         /// <summary>
27         /// 這個文字是不是某個幾何體的標籤(名字)
28         /// </summary>
29         public Models.Geometry.Geometry rely { get; set; }
30     }
OutputText

文本沒有」原像」(借用數學中函數的概念),可是有依賴,好比這個文本是一個點的標籤,依賴保證了文本的座標始終圍繞在這個點必定範圍周邊,不能被拖動太遠

 

兩個方向的映射:邏輯到顯示,顯示到邏輯。
M邏輯座標系是一張無限大的白紙
V視圖座標系是白紙上的一個矩形框,V有兩個關鍵的屬性,向量vector,單位長度unitlength,
v是這樣一個向量,由邏輯座標系指向視圖(現實)座標系的「中心」
ul是 邏輯座標系的1單位長度至關於多少 DIP(DIP表明「器件獨立像素」。這是能夠與物理像素相同,大於或小於的虛擬化單元。)
 
映射有兩種方式,
「左上角投影」:視圖(現實)座標系的「中心」在「屏幕」左上角,不關心屏幕的長寬
 1 // <summary>
 2         /// 邏輯座標系到屏幕顯示座標系的轉換(左上角模式)
 3         /// </summary>
 4         /// <param name="p2"></param>
 5         /// <returns>v2</returns>
 6         public Vector2 ToVector2Upper_Left_Corner(Point2 p2)
 7         {
 8             float x = p2.X - vector.X;
 9             float y = p2.Y - vector.Y;
10             x = x / unitLength;
11             y = -y / unitLength;
12             Vector2 v2 = new Vector2(x,y);
13             return v2;
14         }
15         /// <summary>
16         /// 屏幕顯示座標系到邏輯座標的轉換(左上角模式)
17         /// </summary>
18         /// <param name="v2"></param>
19         /// <returns>Point2 p2</returns>
20         public Point2 ToPoint2Upper_Left_Corner(Vector2 v2)
21         { 
22             Point2 p2 = new Point2() { X = (v2.X*unitLength+vector.X), Y = -(v2.Y*unitLength+vector.Y) };
23             return p2;
24         }
左上角是中心

 

「中心投影」:視圖(現實)座標系的「中心」在「屏幕」中心,須要知道屏幕的長和寬,而後減半
 1 /// <summary>
 2         /// 邏輯座標系到屏幕顯示座標系的轉換(中心模式)
 3         /// </summary>
 4         /// <param name="p2"></param>
 5         /// <returns>屏幕上的點</returns>
 6         public Vector2 ToVector2(Point2 p2)
 7         {
 8             Vector2 vop = new Vector2() { X = p2.X - vector.X, Y = vector.Y - p2.Y };
 9             //if (WindowHeight <= 0 || WindowWidth <= 0) throw new Exception("中心構造方式須要瞭解canvas畫布的actual寬和高");
10             Vector2 half = new Vector2() { X = WindowWidth / 2, Y = WindowHeight / 2 };
11             Vector2 result = half + vop * unitLength;
12             return result;
13         }
14         /// <summary>
15         /// 屏幕顯示座標系到邏輯座標的轉換(中心模式)
16         /// </summary>
17         /// <param name="v2"></param>
18         /// <returns>邏輯座標系中的點</returns>
19         public Point2 ToPoint2(Vector2 v2)
20         {
21             if (WindowHeight <= 0 || WindowWidth <= 0) throw new Exception("中心構造方式須要瞭解canvas畫布的actual寬和高");
22             Vector2 half = new Vector2() { X = WindowWidth / 2, Y = WindowHeight / 2 };
23             Vector2 vop = (v2 - half) / unitLength;
24             Point2 p2 = new Point2() { X = (vop.X + vector.X), Y = -vop.Y + vector.Y };
25             return p2;
26         }
屏幕中心是中心


四種操做,「 增刪改查」:用戶可能對一個幾何體有定義(建立),移動,變形,刪除等操做,這些操做都會被記錄在操做棧中,這樣用戶能夠撤銷重作。查詢操做主要包含在代碼邏輯中,也是必不可少的。

「繁瑣」的「 綁定」:對於一個引擎的每個「零件」,都應該記錄豐富的信息,這種豐富多是繁瑣多餘的,可是會給操做帶來方便。 邏輯座標系知道有多少用戶在看本身(邏輯座標系綁定顯示座標系(們)),顯示座標系知道本身看的是誰(顯示座標系綁定邏輯座標系),邏輯座標系知道本身裏面有多少邏輯幾何元素,每一個邏輯幾何元素知道本身在哪一個邏輯座標系中,視圖座標系知道本身裏面有多少視圖幾何元素或其餘,每一個視圖幾何元素知道本身位於哪一個視圖座標系中,每一個邏輯幾何元素知道本身有多少個視圖幾何元素,每一個視圖幾何元素知道本身是哪一個邏輯幾何元素的「投影像」。
相關文章
相關標籤/搜索