码迷,mamicode.com
首页 > 移动开发 > 详细

使用 C# 开发智能手机软件:推箱子(十一)

时间:2015-07-26 12:45:59      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

这是“使用 C# 开发智能手机软件:推箱子”系列文章的第十一篇。在这篇文章中,介绍 Common/Env.cs 源程序文件。这个源程序文件中包含表示“工作环境”的密封类 Env 。也就是说,主程序中重要的变量都封装在这个类中,作为整个程序的“工作环境”。她还起着桥梁作用,其中两个字段:

    DataFile db;       // 数据文件
    ConfigFile cfg;    // 配置文件

    正是我们以前介绍过的管理数据文件的密封类 DataFile 和管理配置文件的密封类 ConfigFile 的实例。密封类 Env 中的不少属性和方法是通过这两个字段调用其各自的属性和方法。
    下面对密封类 Env 中的一些方法作点说明:
    GetClientSize 方法用来计算当使用标准箱子尺寸时主窗体客户区的尺寸。该方法仅当程序运行在计算机上时才会被调用,使主窗体的尺寸根据当前关的尺寸自动调整。程序运行在智能手机时是不会被调用的,因为在智能手机上本程序并不改变主窗体的尺寸。
    SetBoxInfo 方法的作用是根据客户区尺寸计算箱子的尺寸,并相应设定要显示的图形单元。图形单元共有 24x24、20x20、16x16 和 12x12 四种尺寸,如下所示:

技术分享

技术分享

技术分享  

技术分享

    如果使用 12x12 的图形单元还不能在客户区完整显示地图的话,可能这一关的游戏就无法玩了。
    Draw 方法用来更新主窗体客户区,也就是在主窗体客户区画出本关的地图,并根据玩家的动作随时更新地图。
    Design 方法实现在设计模式下,当鼠标点击时要采取的动作。
    StepIt 方法实现工人往指定方向前进一步(可能推着箱子)。
    Back 方法实现工人后退一步(可能连带箱子一起后退)。
    GetMoveInfo 方法寻找一条将工人移动到鼠标点击的位置的路线。她调用我们以前介绍过的静态类 FindPath 的 Seek 方法来寻找最短路线。
    GetPushInfo 方法给出将箱子推动到鼠标点击的位置所需的信息。
    到此为止,Common 目录下所有源程序文件都介绍完了,这些源程序文件中包含的类是实现整个程序功能的基础。在随后的文章中将介绍 Windows 目录下的源程序文件,她们包含的类实现整个程序的用户界面。
    下面就是密封类 Env 的源程序代码,虽然稍微长了一点,但是里面的注释比较详细,应该不难理解。
  1技术分享using System;
  2技术分享using System.Drawing;
  3技术分享using System.Collections.Generic;
  4技术分享
  5技术分享namespace Skyiv.Ben.PushBox.Common
  6技术分享{
  7技术分享  /// <summary>
  8技术分享  /// 工作环境
  9技术分享  /// </summary>

 10技术分享  sealed class Env : IDisposable
 11技术分享  {
 12技术分享    DataFile db;       // 数据文件
 13技术分享    ConfigFile cfg;    // 配置文件
 14技术分享    string errorMsg;   // 错误信息
 15技术分享    string debugMsg;   // 调试信息
 16技术分享    bool isReplay;     // 是否正在回放
 17技术分享    Action active;     // 模式: 正常 新建 编辑 删除
 18技术分享    byte pen;          // 设计时的笔
 19技术分享    Bitmap img;        // 图形单元, 横向被均匀分为八份
 20技术分享    Stack<Step> stack; // 历史路线, 用于后退功能
 21技术分享    Size clientSize;   // 工作区域尺寸(以像素为单位)
 22技术分享    Size boxSize;      // 图形元素尺寸(以像素为单位)
 23技术分享    Point toPixel;     // 将要到达的位置(以像素为单位)
 24技术分享    Point worker;      // 当前工人位置(以单元格为单位)
 25技术分享    int pushSteps;     // 推动着箱子走的步数
 26技术分享    int levelOem;      // 原来的关数,仅用于“菜单 -> 数据 -> 设计 -> 新建”放弃后恢复现场
 27技术分享
 28技术分享    public string ErrorMsg get return errorMsg; } }
 29技术分享    public string DebugMsg get return debugMsg; } }
 30技术分享    public string[] Groups get return cfg.Groups; } }
 31技术分享    public int Group get return cfg.Group; } set { cfg.Group = value; } }
 32技术分享    public int Level get return cfg.Levels[Group]; } set { cfg.Levels[Group] = value; } }
 33技术分享    public int LeveLOem get return levelOem; } }
 34技术分享    public int MaxLevel get return db.MaxLevel; } }
 35技术分享    public string Steps get return cfg.Steps; } }
 36技术分享    public Size LevelSize get return db.LevelSize; } }
 37技术分享    public Size ClientSize set { clientSize = value; } }
 38技术分享    public Point ToPixel set { toPixel = value; } }
 39技术分享    public int MaxLevelSize get return cfg.MaxLevelSize; } set { cfg.MaxLevelSize = value; } }
 40技术分享    public int StepDelay get return cfg.StepDelay; } set { cfg.StepDelay = value; } }
 41技术分享    public int ReplayDelay get return cfg.ReplayDelay; } set { cfg.ReplayDelay = value; } }
 42技术分享    public Action Active get return active; } set { active = value; } }
 43技术分享    public byte Pen get return pen; } set { pen = value; } }
 44技术分享    public bool HasError get return !string.IsNullOrEmpty(errorMsg); } }
 45技术分享    public bool HasWorker get return db.HasWorker; } }
 46技术分享    public bool CanUndo get return stack.Count != 0; } }
 47技术分享    public bool CanReplay get return db.IsFinished && !CanUndo; } }
 48技术分享    public bool IsSave get return cfg.IsSave; } set { cfg.IsSave = value; } }
 49技术分享    public bool IsFinish get return db.Tasks == db.Boths; } }
 50技术分享    public bool IsReplay get return isReplay; } set { isReplay = value; } }
 51技术分享    public bool IsDesign get return active != Action.None; } }
 52技术分享
 53技术分享    public Env()
 54技术分享    {
 55技术分享      stack = new Stack<Step>();
 56技术分享      cfg = new ConfigFile();
 57技术分享      db = new DataFile();
 58技术分享      Init();
 59技术分享    }

 60技术分享
 61技术分享    /// <summary>
 62技术分享    /// 状态栏信息
 63技术分享    /// </summary>

 64技术分享    public string StatusMessage
 65技术分享    {
 66技术分享      get
 67技术分享      {
 68技术分享        return HasError ? "请点击“菜单 -> 帮助 -> 错误信息”" : string.Format(
 69技术分享          "{0} {1}/{2} {3} {4} {5} [{6}] {7}",
 70技术分享          (active == Action.Create) ? + : (active == Action.Edit) ? = : isReplay ? "|/-\\"[stack.Count % 4] : >,
 71技术分享          Level + 1, MaxLevel, Pub.ToString(LevelSize),
 72技术分享          IsDesign ? string.Format("{0}={1}", db.Boxs, db.Slots) : string.Format("{0}/{1}", db.Boths, db.Tasks),
 73技术分享          IsDesign ? Block.GetPenName(pen) : string.Format("{0}({1})", stack.Count, pushSteps),
 74技术分享          IsDesign ? (active == Action.Create ? "新建" : "编辑") : db.IsFinished ? 
 75技术分享          string.Format("{0}({1})", db.MovedSteps, db.PushedSteps) : string.Empty,
 76技术分享          db.GroupName);
 77技术分享      }

 78技术分享    }

 79技术分享
 80技术分享    public void Dispose()
 81技术分享    {
 82技术分享      db.Dispose();
 83技术分享    }

 84技术分享
 85技术分享    public void Init()
 86技术分享    {
 87技术分享      active = Action.None;
 88技术分享      pen = Block.Land;
 89技术分享      stack.Clear();
 90技术分享      SetExceptionMessage(null);
 91技术分享    }

 92技术分享
 93技术分享    void SetExceptionMessage(Exception ex)
 94技术分享    {
 95技术分享      errorMsg = Pub.GetMessage(ex, false);
 96技术分享      debugMsg = Pub.GetMessage(ex, true);
 97技术分享    }

 98技术分享
 99技术分享    /// <summary>
100技术分享    /// 计算当使用标准箱子尺寸时主窗体客户区的尺寸
101技术分享    /// </summary>
102技术分享    /// <param name="statusBarHeight">状态条的高度</param>
103技术分享    /// <returns>客户区的尺寸</returns>

104技术分享    public Size GetClientSize(int statusBarHeight)
105技术分享    {
106技术分享      int width = (Properties.Resources.PushBox24.Width / 8* LevelSize.Width;
107技术分享      int height = Properties.Resources.PushBox24.Height * LevelSize.Height + statusBarHeight;
108技术分享      if (width < 240) width = 240;
109技术分享      if (height < 48) height = 48;
110技术分享      if (width > 1008) width = 1008;
111技术分享      if (height > 672) height = 672;
112技术分享      return new Size(width, height);
113技术分享    }

114技术分享
115技术分享    /// <summary>
116技术分享    /// 根据客户区尺寸,计算箱子的尺寸,并相应设定要显示的图形单元
117技术分享    /// </summary>

118技术分享    public void SetBoxInfo()
119技术分享    {
120技术分享      if (HasError) return;
121技术分享      if (LevelSize.IsEmpty) return;
122技术分享      int rX = clientSize.Width / LevelSize.Width;
123技术分享      int rY = clientSize.Height / LevelSize.Height;
124技术分享      int r = Math.Min(rX, rY);
125技术分享      if (r >= 24) img = Properties.Resources.PushBox24;
126技术分享      else if (r >= 20) img = Properties.Resources.PushBox20;
127技术分享      else if (r >= 16) img = Properties.Resources.PushBox16;
128技术分享      else img = Properties.Resources.PushBox12;
129技术分享      boxSize = new Size(img.Height, img.Width / 8);
130技术分享    }

131技术分享
132技术分享    /// <summary>
133技术分享    /// 装入配置文件
134技术分享    /// </summary>

135技术分享    public void LoadConfig()
136技术分享    {
137技术分享      if (HasError) return;
138技术分享      try
139技术分享      {
140技术分享        cfg.LoadConfig();
141技术分享      }

142技术分享      catch (Exception ex)
143技术分享      {
144技术分享        SetExceptionMessage(ex);
145技术分享      }

146技术分享    }

147技术分享
148技术分享    /// <summary>
149技术分享    /// 保存组信息到配置文件
150技术分享    /// </summary>
151技术分享    /// <param name="groups">组信息</param>

152技术分享    public void SaveConfig(string[] groups)
153技术分享    {
154技术分享      if (HasError) return;
155技术分享      try
156技术分享      {
157技术分享        cfg.SaveConfig(groups);
158技术分享      }

159技术分享      catch (Exception ex)
160技术分享      {
161技术分享        SetExceptionMessage(ex);
162技术分享      }

163技术分享    }

164技术分享
165技术分享    /// <summary>
166技术分享    /// 保存当前选项及当前走法到配置文件
167技术分享    /// </summary>

168技术分享    public void SaveConfig()
169技术分享    {
170技术分享      if (HasError) return;
171技术分享      try
172技术分享      {
173技术分享        cfg.SaveConfig(stack.ToArray());
174技术分享      }

175技术分享      catch (Exception ex)
176技术分享      {
177技术分享        SetExceptionMessage(ex);
178技术分享      }

179技术分享    }

180技术分享
181技术分享    /// <summary>
182技术分享    /// 装入当前组信息
183技术分享    /// </summary>

184技术分享    public void LoadGroup()
185技术分享    {
186技术分享      if (HasError) return;
187技术分享      try
188技术分享      {
189技术分享        db.LoadGroup(Groups[Group]);
190技术分享      }

191技术分享      catch (Exception ex)
192技术分享      {
193技术分享        SetExceptionMessage(ex);
194技术分享      }

195技术分享    }

196技术分享
197技术分享    /// <summary>
198技术分享    /// 装入当前关信息
199技术分享    /// </summary>

200技术分享    public void LoadLevel()
201技术分享    {
202技术分享      active = Action.None;
203技术分享      if (HasError) return;
204技术分享      try
205技术分享      {
206技术分享        db.LoadLevel(Level);
207技术分享        worker = db.Worker;
208技术分享        stack.Clear();
209技术分享        pushSteps = 0;
210技术分享        isReplay = false;
211技术分享      }

212技术分享      catch (Exception ex)
213技术分享      {
214技术分享        SetExceptionMessage(ex);
215技术分享      }

216技术分享    }

217技术分享
218技术分享    /// <summary>
219技术分享    /// 新建一关
220技术分享    /// </summary>
221技术分享    /// <param name="isCopy">是否复制当前关</param>
222技术分享    /// <param name="size">新建关的尺寸</param>

223技术分享    public void NewLevel(bool isCopy, Size size)
224技术分享    {
225技术分享      if (HasError) return;
226技术分享      try
227技术分享      {
228技术分享        levelOem = Level;
229技术分享        Level = MaxLevel;
230技术分享        db.NewLevel(isCopy, size);
231技术分享      }

232技术分享      catch (Exception ex)
233技术分享      {
234技术分享        SetExceptionMessage(ex);
235技术分享      }

236技术分享    }

237技术分享
238技术分享    /// <summary>
239技术分享    /// 给出通关步骤
240技术分享    /// </summary>
241技术分享    /// <returns>通关步骤</returns>

242技术分享    public string GetSteps()
243技术分享    {
244技术分享      string steps = "";
245技术分享      if (!HasError)
246技术分享      {
247技术分享        try
248技术分享        {
249技术分享          steps = db.GetSteps(Level);
250技术分享        }

251技术分享        catch (Exception ex)
252技术分享        {
253技术分享          SetExceptionMessage(ex);
254技术分享        }

255技术分享      }

256技术分享      return steps;
257技术分享    }

258技术分享
259技术分享    /// <summary>
260技术分享    /// 记录通关步骤
261技术分享    /// </summary>

262技术分享    public void Record()
263技术分享    {
264技术分享      if (HasError) return;
265技术分享      try
266技术分享      {
267技术分享        db.SaveLevel(Level, stack.ToArray(), pushSteps);
268技术分享      }

269技术分享      catch (Exception ex)
270技术分享      {
271技术分享        SetExceptionMessage(ex);
272技术分享      }

273技术分享    }

274技术分享
275技术分享    /// <summary>
276技术分享    /// 保存设计数据
277技术分享    /// </summary>

278技术分享    public void SaveDesign()
279技术分享    {
280技术分享      if (HasError) return;
281技术分享      try
282技术分享      {
283技术分享        db.SaveDesign(active == Action.Create, Level);
284技术分享      }

285技术分享      catch (Exception ex)
286技术分享      {
287技术分享        SetExceptionMessage(ex);
288技术分享      }

289技术分享    }

290技术分享
291技术分享    /// <summary>
292技术分享    /// 删除最后一关
293技术分享    /// </summary>

294技术分享    public void DeleteLastLevel()
295技术分享    {
296技术分享      if (HasError) return;
297技术分享      try
298技术分享      {
299技术分享        db.DeleteLastLevel(Level);
300技术分享      }

301技术分享      catch (Exception ex)
302技术分享      {
303技术分享        SetExceptionMessage(ex);
304技术分享      }

305技术分享    }

306技术分享
307技术分享    /// <summary>
308技术分享    /// 更新主窗体客户区
309技术分享    /// </summary>
310技术分享    /// <param name="dc">画布</param>
311技术分享    /// <param name="rectangle">要在其中绘画的矩形</param>

312技术分享    public void Draw(Graphics dc, Rectangle rectangle)
313技术分享    {
314技术分享      if (HasError) return;
315技术分享      Rectangle box = PixelToBox(rectangle);
316技术分享      Rectangle box2 = new Rectangle(box.Left, box.Top, box.Width + 1, box.Height + 1);
317技术分享      for (int i = 1; i <= LevelSize.Height; i++)
318技术分享      {
319技术分享        for (int j = 1; j <= LevelSize.Width; j++)
320技术分享        {
321技术分享          if (!box2.Contains(j, i)) continue;
322技术分享          DrawBox(dc, j, i);
323技术分享        }

324技术分享      }

325技术分享    }

326技术分享
327技术分享    /// <summary>
328技术分享    /// 绘制一个单元格
329技术分享    /// </summary>
330技术分享    /// <param name="dc">画布</param>
331技术分享    /// <param name="x">单元格的横坐标</param>
332技术分享    /// <param name="y">单元格的纵坐标</param>

333技术分享    void DrawBox(Graphics dc, int x, int y)
334技术分享    {
335技术分享      DrawBox(dc, db.Map[y, x], (x - 1* boxSize.Width, (y - 1* boxSize.Height);
336技术分享    }

337技术分享
338技术分享    /// <summary>
339技术分享    /// 绘制一个单元格
340技术分享    /// </summary>
341技术分享    /// <param name="dc">画布</param>
342技术分享    /// <param name="idx">单元格的类型: 地 槽 墙 砖 箱子 工人</param>
343技术分享    /// <param name="x">单元格的横坐标</param>
344技术分享    /// <param name="y">单元格的纵坐标</param>

345技术分享    void DrawBox(Graphics dc, int idx, int x, int y)
346技术分享    {
347技术分享      dc.DrawImage(img, x, y, new Rectangle(idx * boxSize.Width, 0, boxSize.Width, boxSize.Height), GraphicsUnit.Pixel);
348技术分享    }

349技术分享
350技术分享    /// <summary>
351技术分享    /// 将单元格换算为像素
352技术分享    /// </summary>
353技术分享    /// <param name="box">单元格矩形</param>
354技术分享    /// <returns>像素矩形</returns>

355技术分享    Rectangle BoxToPixel(Rectangle box)
356技术分享    {
357技术分享      return new Rectangle((box.Left - 1* boxSize.Width, (box.Top - 1* boxSize.Height,
358技术分享        (box.Width + 1* boxSize.Width, (box.Height + 1* boxSize.Height);
359技术分享    }

360技术分享
361技术分享    /// <summary>
362技术分享    /// 将像素换算为单元格
363技术分享    /// </summary>
364技术分享    /// <param name="pixel">像素矩形</param>
365技术分享    /// <returns>单元格矩形</returns>

366技术分享    Rectangle PixelToBox(Rectangle pixel)
367技术分享    {
368技术分享      int x0 = pixel.Left / boxSize.Width + 1;
369技术分享      int y0 = pixel.Top / boxSize.Height + 1;
370技术分享      int x1 = (pixel.Right - 1/ boxSize.Width + 1;
371技术分享      int y1 = (pixel.Bottom - 1/ boxSize.Height + 1;
372技术分享      return new Rectangle(x0, y0, x1 - x0, y1 - y0);
373技术分享    }

374技术分享
375技术分享    /// <summary>
376技术分享    /// 根据指定的对角顶点创建矩形
377技术分享    /// </summary>
378技术分享    /// <param name="a">顶点</param>
379技术分享    /// <param name="b">对角的顶点</param>
380技术分享    /// <returns>所需要的矩形</returns>

381技术分享    Rectangle GetRectangle(Point a, Point b)
382技术分享    {
383技术分享      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));
384技术分享    }

385技术分享
386技术分享    /// <summary>
387技术分享    /// 设计模式下,当鼠标点击时要采取的动作
388技术分享    /// </summary>
389技术分享    /// <param name="invalid">输出:要重绘的区域</param>
390技术分享    /// <returns>是否发生动作</returns>

391技术分享    public bool Design(out Rectangle invalid)
392技术分享    {
393技术分享      invalid = Rectangle.Empty;
394技术分享      Point to;
395技术分享      if (!ValidClick(out to)) return false;
396技术分享      db.UpdateCounts(to.X, to.Y, false);
397技术分享      Block.Update(ref db.Map[to.Y, to.X], pen);
398技术分享      db.UpdateCounts(to.X, to.Y, true);
399技术分享      if (pen == Block.Man0 && HasWorker) pen = Block.Box0;
400技术分享      invalid = BoxToPixel(GetRectangle(to, to));
401技术分享      return true;
402技术分享    }

403技术分享
404技术分享    /// <summary>
405技术分享    /// 工人往指定方向前进一步(可能推着箱子)
406技术分享    /// </summary>
407技术分享    /// <param name="dir">前进的方向</param>
408技术分享    /// <param name="isStop">“撤销”时是否停留</param>
409技术分享    /// <param name="invalid">输出:要重绘的区域</param>
410技术分享    /// <returns>是否成功</returns>

411技术分享    public bool StepIt(Direction dir, bool isStop, out Rectangle invalid)
412技术分享    {
413技术分享      invalid = Rectangle.Empty;
414技术分享      if (HasError) return false;
415技术分享      if (Direction.None == dir) return false;
416技术分享      Point p1 = worker; // 工人前进方向一步的位置
417技术分享      Point p2 = worker; // 箱子前进方向一步的位置
418技术分享      switch (dir)
419技术分享      {
420技术分享        case Direction.East: p1.X++; p2.X += 2break;
421技术分享        case Direction.South: p1.Y++; p2.Y += 2break;
422技术分享        case Direction.West: p1.X--; p2.X -= 2break;
423技术分享        case Direction.North: p1.Y--; p2.Y -= 2break;
424技术分享      }

425技术分享      byte b1 = db.Map[p1.Y, p1.X]; // 工人前进方向一步位置上的东西
426技术分享      bool isBox = Block.IsBox(b1); // 是否推着箱子前进
427技术分享      if (!isBox && !Block.IsBlank(b1)) return false// 如果没有推着箱子且前方不是空地则失败
428技术分享      if (isBox && !Block.IsBlank(db.Map[p2.Y, p2.X])) return false// 如果推着箱子且箱子前方不是空地则失败
429技术分享      invalid = BoxToPixel(GetRectangle(worker, isBox ? p2 : p1)); // 要重绘的区域
430技术分享      stack.Push(new Step(dir, isBox, isStop)); // 记录走法步骤
431技术分享      Block.ManOut(ref db.Map[worker.Y, worker.X]); // 工人离开当前位置
432技术分享      Block.ManIn(ref db.Map[p1.Y, p1.X]); // 工人进入前方位置
433技术分享      if (isBox)
434技术分享      {
435技术分享        pushSteps++// 更新推箱子步数
436技术分享        db.Boths += (db.Map[p2.Y, p2.X] - Block.Land) - (b1 - Block.Box0); // 更新已完成任务数
437技术分享        Block.BoxOut(ref db.Map[p1.Y, p1.X]); // 箱子离开当前位置
438技术分享        Block.BoxIn(ref db.Map[p2.Y, p2.X]); // 箱子进入前方位置
439技术分享      }

440技术分享      worker = p1; // 更新工人位置
441技术分享      return true// 工人成功前进一步(可能推着条子)
442技术分享    }

443技术分享
444技术分享    /// <summary>
445技术分享    /// 工人后退一步(可能连带箱子一起后退)
446技术分享    /// </summary>
447技术分享    /// <param name="invalid">输出:要重绘的区域</param>
448技术分享    /// <returns>是否完成“撤消”</returns>

449技术分享    public bool Back(out Rectangle invalid)
450技术分享    {
451技术分享      invalid = Rectangle.Empty;
452技术分享      if (HasError) return true;
453技术分享      if (stack.Count == 0return true;
454技术分享      Step step = stack.Pop(); // 当前步骤
455技术分享      Point p1 = worker; // 工人后退方向一步的位置
456技术分享      Point p2 = worker; // 箱子的当前位置
457技术分享      switch (step.Direct)
458技术分享      {
459技术分享        case Direction.East: p1.X--; p2.X++break;
460技术分享        case Direction.South: p1.Y--; p2.Y++break;
461技术分享        case Direction.West: p1.X++; p2.X--break;
462技术分享        case Direction.North: p1.Y++; p2.Y--break;
463技术分享      }

464技术分享      invalid = BoxToPixel(GetRectangle(p1, step.IsBox ? p2 : worker)); // 要重绘的区域
465技术分享      Block.ManOut(ref db.Map[worker.Y, worker.X]); // 工人离开当前位置
466技术分享      Block.ManIn(ref db.Map[p1.Y, p1.X]); // 工人进入后退方向一步的位置
467技术分享      if (step.IsBox)
468技术分享      {
469技术分享        Block.BoxOut(ref db.Map[p2.Y, p2.X]); // 箱子离开当前位置
470技术分享        Block.BoxIn(ref db.Map[worker.Y, worker.X]); // 箱子进入工人原来的位置
471技术分享        db.Boths += (db.Map[worker.Y, worker.X] - Block.Box0) - (db.Map[p2.Y, p2.X] - Block.Land); // 更新已完成任务数
472技术分享        pushSteps--// 更新推箱子步数
473技术分享      }

474技术分享      worker = p1; // 更新工人位置
475技术分享      return step.IsStop; // 是否完成“撤消”
476技术分享    }

477技术分享
478技术分享    /// <summary>
479技术分享    /// 寻找一条将工人移动到鼠标点击的位置的路线
480技术分享    /// </summary>
481技术分享    /// <returns>移动的路线</returns>

482技术分享    public Queue<Direction> GetMoveInfo()
483技术分享    {
484技术分享      Point to;
485技术分享      if (!CanTo(out to)) return null;
486技术分享      return FindPath.Seek(db.Map, worker, to);
487技术分享    }

488技术分享
489技术分享    /// <summary>
490技术分享    /// 给出将箱子推动到鼠标点击的位置所需的信息
491技术分享    /// </summary>
492技术分享    /// <param name="dir">输出:工人移动的方向</param>
493技术分享    /// <returns>工人移动的步数</returns>

494技术分享    public int GetPushInfo(out Direction dir)
495技术分享    {
496技术分享      dir = Direction.None;
497技术分享      if (HasError) return 0;
498技术分享      Point to; // 目的地
499技术分享      if (!CanTo(out to)) return 0// 无效的目的地
500技术分享      if (to.Y != worker.Y && to.X != worker.X) return 0// 目的地和工人不在同一条直线上
501技术分享      int z0 = (to.Y == worker.Y) ? worker.X : worker.Y;
502技术分享      int z9 = (to.Y == worker.Y) ? to.X : to.Y;
503技术分享      if (to.Y == worker.Y) dir = (z9 > z0) ? Direction.East : Direction.West;
504技术分享      else dir = (z9 > z0) ? Direction.South : Direction.North;
505技术分享      int i0 = Math.Min(z9, z0);
506技术分享      int i9 = Math.Max(z9, z0);
507技术分享      int steps = i9 - i0; // 目的地和工人之间的距离
508技术分享      int boxs = 0;
509技术分享      for (int i = i0 + 1; i < i9; i++)
510技术分享      {
511技术分享        byte bi = (to.Y == worker.Y) ? db.Map[worker.Y, i] : db.Map[i, worker.X];
512技术分享        if (Block.IsBox(bi)) boxs++// 计算工人和目的地之间的箱子的个数
513技术分享        else if (!Block.IsBlank(bi)) boxs += 2// “墙”和“砖”折算为两个箱子
514技术分享      }

515技术分享      if (boxs > 1return 0// 最多只能推着一个箱子前进
516技术分享      return steps - boxs; // 工人移动的步数
517技术分享    }

518技术分享
519技术分享    /// <summary>
520技术分享    /// 检查鼠标点击位置是否可达, 并将像素换算为单元格
521技术分享    /// </summary>
522技术分享    /// <param name="to">输出:换算后的位置</param>
523技术分享    /// <returns>是否可达</returns>

524技术分享    bool CanTo(out Point to)
525技术分享    {
526技术分享      if (!ValidClick(out to)) return false;
527技术分享      if (!Block.IsMan(db.Map[worker.Y, worker.X])) throw new Exception("内部错误:工人的位置上不是工人");
528技术分享      if (!Block.IsBlank(db.Map[to.Y, to.X])) return false// 目的地必须是“地”或“槽”
529技术分享      if (to.Y == worker.Y && to.X == worker.X) return false// 目的地不能是工人当前的位置
530技术分享      return true// 目的地可达
531技术分享    }

532技术分享
533技术分享    /// <summary>
534技术分享    /// 检查鼠标点击位置是否有效, 并将像素换算为单元格
535技术分享    /// </summary>
536技术分享    /// <param name="to">输出:换算后的位置</param>
537技术分享    /// <returns>是否有效位置</returns>

538技术分享    bool ValidClick(out Point to)
539技术分享    {
540技术分享      to = Point.Empty;
541技术分享      if (HasError) return false;
542技术分享      to.Y = toPixel.Y / boxSize.Height + 1;
543技术分享      to.X = toPixel.X / boxSize.Width + 1;
544技术分享      if (toPixel.X >= boxSize.Width * LevelSize.Width || toPixel.Y >= boxSize.Height * LevelSize.Height)
545技术分享        return false// 目的地超出当前关的有效范围
546技术分享      return true// 目的地有效
547技术分享    }

548技术分享  }

549技术分享}

550技术分享

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

使用 C# 开发智能手机软件:推箱子(十一)

标签:

原文地址:http://blog.csdn.net/u013141940/article/details/47066445

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!