?? env.cs
字號:
/// 保存設計數據
/// </summary>
public void SaveDesign()
{
if (HasError) return;
try
{
db.SaveDesign(active == Action.Create, Level);
}
catch (Exception ex)
{
SetExceptionMessage(ex);
}
}
/// <summary>
/// 刪除最后一關
/// </summary>
public void DeleteLastLevel()
{
if (HasError) return;
try
{
db.DeleteLastLevel(Level);
}
catch (Exception ex)
{
SetExceptionMessage(ex);
}
}
/// <summary>
/// 更新主窗體客戶區
/// </summary>
/// <param name="dc">畫布</param>
/// <param name="rectangle">要在其中繪畫的矩形</param>
public void Draw(Graphics dc, Rectangle rectangle)
{
if (HasError) return;
Rectangle box = PixelToBox(rectangle);
Rectangle box2 = new Rectangle(box.Left, box.Top, box.Width + 1, box.Height + 1);
for (int i = 1; i <= LevelSize.Height; i++)
{
for (int j = 1; j <= LevelSize.Width; j++)
{
if (!box2.Contains(j, i)) continue;
DrawBox(dc, j, i);
}
}
}
/// <summary>
/// 繪制一個單元格
/// </summary>
/// <param name="dc">畫布</param>
/// <param name="x">單元格的橫坐標</param>
/// <param name="y">單元格的縱坐標</param>
void DrawBox(Graphics dc, int x, int y)
{
DrawBox(dc, db.Map[y, x], (x - 1) * boxSize.Width, (y - 1) * boxSize.Height);
}
/// <summary>
/// 繪制一個單元格
/// </summary>
/// <param name="dc">畫布</param>
/// <param name="idx">單元格的類型: 地 槽 墻 磚 箱子 工人</param>
/// <param name="x">單元格的橫坐標</param>
/// <param name="y">單元格的縱坐標</param>
void DrawBox(Graphics dc, int idx, int x, int y)
{
dc.DrawImage(img, x, y, new Rectangle(idx * boxSize.Width, 0, boxSize.Width, boxSize.Height), GraphicsUnit.Pixel);
}
/// <summary>
/// 將單元格換算為像素
/// </summary>
/// <param name="box">單元格矩形</param>
/// <returns>像素矩形</returns>
Rectangle BoxToPixel(Rectangle box)
{
return new Rectangle((box.Left - 1) * boxSize.Width, (box.Top - 1) * boxSize.Height,
(box.Width + 1) * boxSize.Width, (box.Height + 1) * boxSize.Height);
}
/// <summary>
/// 將像素換算為單元格
/// </summary>
/// <param name="pixel">像素矩形</param>
/// <returns>單元格矩形</returns>
Rectangle PixelToBox(Rectangle pixel)
{
int x0 = pixel.Left / boxSize.Width + 1;
int y0 = pixel.Top / boxSize.Height + 1;
int x1 = (pixel.Right - 1) / boxSize.Width + 1;
int y1 = (pixel.Bottom - 1) / boxSize.Height + 1;
return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
/// <summary>
/// 根據指定的對角頂點創建矩形
/// </summary>
/// <param name="a">頂點</param>
/// <param name="b">對角的頂點</param>
/// <returns>所需要的矩形</returns>
Rectangle GetRectangle(Point a, Point b)
{
return Rectangle.FromLTRB(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Max(a.X, b.X), Math.Max(a.Y, b.Y));
}
/// <summary>
/// 設計模式下,當鼠標點擊時要采取的動作
/// </summary>
/// <param name="invalid">輸出:要重繪的區域</param>
/// <returns>是否發生動作</returns>
public bool Design(out Rectangle invalid)
{
invalid = Rectangle.Empty;
Point to;
if (!ValidClick(out to)) return false;
db.UpdateCounts(to.X, to.Y, false);
Block.Update(ref db.Map[to.Y, to.X], pen);
db.UpdateCounts(to.X, to.Y, true);
if (pen == Block.Man0 && HasWorker) pen = Block.Box0;
invalid = BoxToPixel(GetRectangle(to, to));
return true;
}
/// <summary>
/// 工人往指定方向前進一步(可能推著箱子)
/// </summary>
/// <param name="dir">前進的方向</param>
/// <param name="isStop">“撤銷”時是否停留</param>
/// <param name="invalid">輸出:要重繪的區域</param>
/// <returns>是否成功</returns>
public bool StepIt(Direction dir, bool isStop, out Rectangle invalid)
{
invalid = Rectangle.Empty;
if (HasError) return false;
if (Direction.None == dir) return false;
Point p1 = worker; // 工人前進方向一步的位置
Point p2 = worker; // 箱子前進方向一步的位置
switch (dir)
{
case Direction.East: p1.X++; p2.X += 2; break;
case Direction.South: p1.Y++; p2.Y += 2; break;
case Direction.West: p1.X--; p2.X -= 2; break;
case Direction.North: p1.Y--; p2.Y -= 2; break;
}
byte b1 = db.Map[p1.Y, p1.X]; // 工人前進方向一步位置上的東西
bool isBox = Block.IsBox(b1); // 是否推著箱子前進
if (!isBox && !Block.IsBlank(b1)) return false; // 如果沒有推著箱子且前方不是空地則失敗
if (isBox && !Block.IsBlank(db.Map[p2.Y, p2.X])) return false; // 如果推著箱子且箱子前方不是空地則失敗
invalid = BoxToPixel(GetRectangle(worker, isBox ? p2 : p1)); // 要重繪的區域
stack.Push(new Step(dir, isBox, isStop)); // 記錄走法步驟
Block.ManOut(ref db.Map[worker.Y, worker.X]); // 工人離開當前位置
Block.ManIn(ref db.Map[p1.Y, p1.X]); // 工人進入前方位置
if (isBox)
{
pushSteps++; // 更新推箱子步數
db.Boths += (db.Map[p2.Y, p2.X] - Block.Land) - (b1 - Block.Box0); // 更新已完成任務數
Block.BoxOut(ref db.Map[p1.Y, p1.X]); // 箱子離開當前位置
Block.BoxIn(ref db.Map[p2.Y, p2.X]); // 箱子進入前方位置
}
worker = p1; // 更新工人位置
return true; // 工人成功前進一步(可能推著條子)
}
/// <summary>
/// 工人后退一步(可能連帶箱子一起后退)
/// </summary>
/// <param name="invalid">輸出:要重繪的區域</param>
/// <returns>是否完成“撤消”</returns>
public bool Back(out Rectangle invalid)
{
invalid = Rectangle.Empty;
if (HasError) return true;
if (stack.Count == 0) return true;
Step step = stack.Pop(); // 當前步驟
Point p1 = worker; // 工人后退方向一步的位置
Point p2 = worker; // 箱子的當前位置
switch (step.Direct)
{
case Direction.East: p1.X--; p2.X++; break;
case Direction.South: p1.Y--; p2.Y++; break;
case Direction.West: p1.X++; p2.X--; break;
case Direction.North: p1.Y++; p2.Y--; break;
}
invalid = BoxToPixel(GetRectangle(p1, step.IsBox ? p2 : worker)); // 要重繪的區域
Block.ManOut(ref db.Map[worker.Y, worker.X]); // 工人離開當前位置
Block.ManIn(ref db.Map[p1.Y, p1.X]); // 工人進入后退方向一步的位置
if (step.IsBox)
{
Block.BoxOut(ref db.Map[p2.Y, p2.X]); // 箱子離開當前位置
Block.BoxIn(ref db.Map[worker.Y, worker.X]); // 箱子進入工人原來的位置
db.Boths += (db.Map[worker.Y, worker.X] - Block.Box0) - (db.Map[p2.Y, p2.X] - Block.Land); // 更新已完成任務數
pushSteps--; // 更新推箱子步數
}
worker = p1; // 更新工人位置
return step.IsStop; // 是否完成“撤消”
}
/// <summary>
/// 尋找一條將工人移動到鼠標點擊的位置的路線
/// </summary>
/// <returns>移動的路線</returns>
public Queue<Direction> GetMoveInfo()
{
Point to;
if (!CanTo(out to)) return null;
return FindPath.Seek(db.Map, worker, to);
}
/// <summary>
/// 給出將箱子推動到鼠標點擊的位置所需的信息
/// </summary>
/// <param name="dir">輸出:工人移動的方向</param>
/// <returns>工人移動的步數</returns>
public int GetPushInfo(out Direction dir)
{
dir = Direction.None;
if (HasError) return 0;
Point to; // 目的地
if (!CanTo(out to)) return 0; // 無效的目的地
if (to.Y != worker.Y && to.X != worker.X) return 0; // 目的地和工人不在同一條直線上
int z0 = (to.Y == worker.Y) ? worker.X : worker.Y;
int z9 = (to.Y == worker.Y) ? to.X : to.Y;
if (to.Y == worker.Y) dir = (z9 > z0) ? Direction.East : Direction.West;
else dir = (z9 > z0) ? Direction.South : Direction.North;
int i0 = Math.Min(z9, z0);
int i9 = Math.Max(z9, z0);
int steps = i9 - i0; // 目的地和工人之間的距離
int boxs = 0;
for (int i = i0 + 1; i < i9; i++)
{
byte bi = (to.Y == worker.Y) ? db.Map[worker.Y, i] : db.Map[i, worker.X];
if (Block.IsBox(bi)) boxs++; // 計算工人和目的地之間的箱子的個數
else if (!Block.IsBlank(bi)) boxs += 2; // “墻”和“磚”折算為兩個箱子
}
if (boxs > 1) return 0; // 最多只能推著一個箱子前進
return steps - boxs; // 工人移動的步數
}
/// <summary>
/// 檢查鼠標點擊位置是否可達, 并將像素換算為單元格
/// </summary>
/// <param name="to">輸出:換算后的位置</param>
/// <returns>是否可達</returns>
bool CanTo(out Point to)
{
if (!ValidClick(out to)) return false;
if (!Block.IsMan(db.Map[worker.Y, worker.X])) throw new Exception("內部錯誤:工人的位置上不是工人");
if (!Block.IsBlank(db.Map[to.Y, to.X])) return false; // 目的地必須是“地”或“槽”
if (to.Y == worker.Y && to.X == worker.X) return false; // 目的地不能是工人當前的位置
return true; // 目的地可達
}
/// <summary>
/// 檢查鼠標點擊位置是否有效, 并將像素換算為單元格
/// </summary>
/// <param name="to">輸出:換算后的位置</param>
/// <returns>是否有效位置</returns>
bool ValidClick(out Point to)
{
to = Point.Empty;
if (HasError) return false;
to.Y = toPixel.Y / boxSize.Height + 1;
to.X = toPixel.X / boxSize.Width + 1;
if (toPixel.X >= boxSize.Width * LevelSize.Width || toPixel.Y >= boxSize.Height * LevelSize.Height)
return false; // 目的地超出當前關的有效范圍
return true; // 目的地有效
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -