| 類型 | 表現層 | 邏輯層 | 代表作 |
| 偽斜度 | 斜視角美術 | 正方形網格 | 早期 2.5D RPG |
| 真斜度 (α 地圖) | 斜視角美術 | 菱形/等軸測網格 | 夢幻西遊、大話西遊、傳奇類 |
真斜度地圖中,遊戲邏輯座標系 (G) 與視窗座標系 (W) 存在旋轉縮放關係,夾角 α 通常為 60° 或 45°。本章以 α=60° 為例完整推導座標雙向轉換公式並實作。
座標系幾何關係推導
設 G 座標系軸向:Gx 向右下、Gy 向左下,夾角 α。W 座標系為標準屏幕座標(X 向右、Y 向下)。幾何推導得雙向轉換公式:
W(x) = (G(x) - G(y)) * sin α
W(y) = (G(x) + G(y)) * cos α
G(x) = (W(y)*sin α + W(x)*cos α) / (2*sin α*cos α)
G(y) = (W(y)*sin α - W(x)*cos α) / (2*sin α*cos α)
α = 60° 代入數值
- sin 60° = √3/2 ≈ 0.866,cos 60° = 0.5
- sin α / 2 = 0.433,但程式碼中採用
1/1.732 ≈ 0.577 為 tan 30°,實際對應不同推導路徑,結果等價。
C# 實作雙向轉換方法
int GridSize = 20;
// 視窗座標 → 遊戲邏輯座標 (縮小)
private Point GetGamePosition(double x, double y)
{
return new Point(
(int)((y + x / 1.732) / GridSize),
(int)((y - x / 1.732) / GridSize)
);
}
// 遊戲邏輯座標 → 視窗座標 (放大)
private Point GetWindowPosition(double x, double y)
{
return new Point(
(x - y) * 0.886 * GridSize, // 0.886 ≈ sin60/2
(x + y) * 0.5 * GridSize // 0.5 = cos60
);
}
預先計算三角函數常數避免重複呼叫 Math.Sin/Cos,大幅提升效能。
菱形障礙物視覺化構建
for (int x = 10; x < 20; x++)
for (int y = 1; y < 10; y++)
{
Matrix[x, y] = 0; // 邏輯障礙物
var rect = new Rectangle
{
Fill = Brushes.GreenYellow,
Opacity = 0.3,
Stroke = Brushes.Gray,
Width = GridSize,
Height = GridSize + 2
};
// 套用 Skew + Rotate 變換產生菱形視覺
var tg = new TransformGroup();
tg.Children.Add(new SkewTransform(-10, -25));
tg.Children.Add(new RotateTransform(54));
rect.RenderTransform = tg;
Carrier.Children.Add(rect);
Point p = GetWindowPosition(x, y);
Canvas.SetLeft(rect, p.X);
Canvas.SetTop(rect, p.Y);
}
RenderTransform 不影響佈局佔用空間,僅改變視覺呈現,邏輯碰撞仍以矩陣 Matrix[x,y] 判定。
滑鼠點擊觸發 A* 尋路座標轉換整合
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(Carrier);
// 起點:角色腳底視窗座標 → 遊戲座標
Point start = GetGamePosition(
Canvas.GetLeft(Spirit) + SpiritCenterX,
Canvas.GetTop(Spirit) + SpiritCenterY);
Start = new System.Drawing.Point((int)start.X, (int)start.Y);
// 終點:滑鼠點擊視窗座標 → 遊戲座標
Point end = GetGamePosition(p.X, p.Y);
End = new System.Drawing.Point((int)end.X, (int)end.Y);
// ... A* 尋路取得 path ...
// 關鍵幀座標集:遊戲座標 → 視窗座標
Point[] framePosition = new Point[path.Count];
for (int i = path.Count - 1; i >= 0; i--)
framePosition[path.Count - 1 - i] = GetWindowPosition(path[i].X, path[i].Y);
// ... 建立 Storyboard 綁定 Spirit.X/Y ...
// 軌跡點同樣轉換
for (int i = path.Count - 1; i >= 0; i--)
{
Point target = GetWindowPosition(path[i].X, path[i].Y);
// 加入白點...
}
}
驗證與對比
- 運行程式,點擊菱形障礙物區域外,角色沿菱形網格斜向移動繞行,軌跡完全吻合視覺菱形。
- 將菱形障礙物改回正方形(移除 Transform),同樣邏輯座標下視覺呈現為直角網格,證明座標轉換核心正確,視覺表現可換裝。
- 負邏輯座標區域(Gx<0 或 Gy<0)點擊提示「路徑不存在」,符合座標系定義。
實務建議
- α 角度在專案中全域常數化,嚴禁硬編碼散落各處。
- 座標轉換方法集中於工具類,嚴禁在業務邏輯中內聯計算。
- 美術素材製作時需嚴格對齊網格錨點,否則視覺與邏輯誤差將累積。
下章預告
下一章實作遮罩層,解決斜度地圖中高大物體遮擋角色的視覺問題,完成斜度地圖引擎的視覺閉環。
- 上一篇文章: WPF/Silverlight 遊戲開發教程 (11):地圖遮罩層實作 — 半透明遮擋物與畫家演算法 ZIndex 動態管理
- 下一篇文章: WPF/Silverlight 遊戲開發教程 (9):2D 角色在地圖上移動 — 真實腳底定位、直線與 A* 雙模式移動
Copyright ©
程式碼之家 All Rights Reserved