继之前分享的一篇《Robotics Studio学习教程:第二十四天——DSS System Services》, 我们将继续分享下一篇《Robotics Studio学习教程:第二十五天——让我们开始建造迷宫吧!》,让我继续开始我们学习Visual Programming Language,以及使用Robotics Studio学习开发机器人应用的道路吧。
[Robotics Studio] 开始建造迷宫 -- Day25
话说教会机器人走迷宫是我学习 Robotics Studio 的小小梦想之一.
要学习走迷宫, 第一步需要有迷宫才行.
无奈, 之前的 Visual Simulation Enviroment Express version 的 64 个实体对象吓到我了...
如何用 64 个实体来建造伟大的迷宫, 我一直是觉得很困难的一件事情...
直到, 我发现这个 64 个 Entities 的限制是 -- 直接放入 VSE World 的实体数量.
也就是说, 如果我把整个迷宫看成是一个 Entity 对象, 不就解决这样的问题了吗?!
所以, 可以透过实做 MultiShapeEntity 这个 class 来达成梦想的第一步了!
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using Microsoft.Ccr.Core;
- using Microsoft.Dss.Core.Attributes;
- using Microsoft.Dss.ServiceModel.Dssp;
- using Microsoft.Dss.ServiceModel.DsspServiceBase;
- using W3C.Soap;
- using submgr = Microsoft.Dss.Services.SubscriptionManager;
- using engine = Microsoft.Robotics.Simulation.Engine.Proxy;
- using Microsoft.Robotics.Simulation.Engine;
- using Microsoft.Robotics.Simulation.Physics;
- using Microsoft.Robotics.PhysicalModel;
- namespace MazeGenerator
- {
- public class MazeEntity : MultiShapeEntity
- {
- /// <summary>
- /// Default constructor
- /// </summary>
- public MazeEntity() { }
- /// <summary>
- /// Initialization constructor
- /// </summary>
- /// <param name="shape"></param>
- /// <param name="initialPos"></param>
- public MazeEntity(Vector3 initialPos, byte[,] blocks, float mazeheight, float blocksize)
- {
- for (int x = 0; x < blocks.GetLength(0); x++)
- {
- for (int y = 0; y < blocks.GetLength(1); y++)
- {
- if (blocks[x,y] == 0)
- continue;
- var boxshape = new BoxShape(
- new BoxShapeProperties(
- 1, // mass in kilograms. new Pose(
- new Vector3(
- initialPos.X + x * blocksize,
- initialPos.Y + mazeheight / 2,
- initialPos.Z - y*blocksize)), // relative pose
- new Vector3(blocksize, mazeheight, blocksize)));
- this.BoxShapes.Add(boxshape); // dimensions
- }
- }
- this.State.MassDensity.Mass = blocks.GetLength(0)*blocks.GetLength(1);
- }
- }
- }
上面这个迷宫需要传入一个 2 维 byte 数组,
主要的想法当然还是参考自古早的 RPG Game 都是利用 block 的方式来产生世界的.然后写一个 DSS Service (参考之前的 DSS with VSE 吧), 这次我们加入一个 MazeEntity :
- void AddMaze()
- {
- // create simple movable entity, with a single shape
- maze = new MazeEntity(
- new Vector3(3f, 0f, 3f), new byte[,] {
- {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
- {0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1},
- {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1},
- {1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,1,0,1},
- {1,0,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,1,0,1},
- {1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,0,0,0,1},
- {1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1},
- {1,0,0,1,0,1,0,0,0,0,1,0,1,1,0,1,0,1,0,1},
- {1,0,0,1,0,1,1,1,1,0,1,0,1,0,0,1,0,1,0,1},
- {1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,1,0,1},
- {1,0,0,1,1,1,1,0,1,0,1,0,1,1,1,1,0,1,0,1},
- {1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,1},
- {1,0,1,1,0,1,1,0,1,0,1,0,1,0,0,1,1,1,0,1},
- {1,0,1,0,0,1,1,0,1,1,1,1,1,0,0,0,0,1,0,1},
- {1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,0,1},
- {1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1},
- {1,0,1,1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1},
- {1,0,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1},
- {1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
- {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, }, 3.0f, 3.0f);
- // Name the entity. All entities must have unique names
- maze.State.Name = "maze";
- // Insert entity in simulation.
- SimulationEngine.GlobalInstancePort.Insert(maze);
- }
这样我们就有一个迷宫了耶...
但是这样自己做迷宫会爽吗? -- 不会!!
身为程序设计师, 怎么可以自己画迷宫呢, 当然这种事也是要交给计算机画的, 不然我们会画到榨干...
所以采用简单的迷宫划分法:
于是在 MazeEntity 当中加入了随机数生成迷宫的程序:
- public static byte[,] GenerateMaze(int width, int height)
- {
- byte[,] result = new byte[width, height];
- Random r = new Random();
- for (int x = 0; x < width; x++)
- for (int y = 0; y < height; y++)
- result[x, y] =(byte)
- (((x == 0) ||
- (y == 0) ||
- (x == width - 1) ||
- (y == height - 1)) ? 1 : 0);
- splitMazeChamber(r, result, 0, 0, width - 1, height - 1);
- // dig a hole of left-top, and right-down
- result[0, 1] = 0;
- result[width - 1, height - 2] = 0;
- return result;
- }
- private static void splitMazeChamber
- (Random r, byte[,] maze, int left, int top, int right, int bottom)
- {
- int wallX = 0;
- if (right - left > 3)
- wallX = r.Next(left + 2, right - 1);
- int wallY = 0;
- if (bottom - top > 3)
- wallY = r.Next(top + 2, bottom - 1);
- if ((wallX > 0) && (wallY > 0))
- {
- for (int i = top + 1; i < bottom; i++)
- maze[wallX, i] = 1;
- for (int i = left + 1; i < right; i++)
- maze[i, wallY] = 1;
- List<KeyValuePair<int, int>> holes = new List<KeyValuePair<int, int>>();
- holes.Add(new KeyValuePair<int, int>(wallX, r.Next(top + 1, wallY - 1)));
- holes.Add(new KeyValuePair<int, int>(wallX, r.Next(wallY + 1, bottom - 1)));
- holes.Add(new KeyValuePair<int, int>(r.Next(left + 1, wallX - 1), wallY));
- holes.Add(new KeyValuePair<int, int>(r.Next(wallX + 1, right - 1), wallY));
- holes.RemoveAt(r.Next(0, 4));
- holes.ForEach(hole => maze[hole.Key, hole.Value] = 0);
- splitMazeChamber(r, maze, left, top, wallX, wallY);
- splitMazeChamber(r, maze, wallX, top, right, wallY);
- splitMazeChamber(r, maze, left, wallY, wallX, bottom);
- splitMazeChamber(r, maze, wallX, wallY, right, bottom);
- }
- else if (wallX > 0)
- {
- for (int i = top + 1; i < bottom; i++)
- maze[wallX, i] = 1;
- maze[wallX, r.Next(top + 1, bottom - 1)] = 0;
- splitMazeChamber(r, maze, left, top, wallX, bottom);
- splitMazeChamber(r, maze, wallX, top, right, bottom);
- }
- else if (wallY > 0)
- {
- for (int i = left + 1; i < right; i++)
- maze[i, wallY] = 1;
- maze[r.Next(left + 1, right - 1), wallY] = 0;
- splitMazeChamber(r, maze, left, top, right, wallY);
- splitMazeChamber(r, maze, left, wallY, right, bottom);
- }
- }
先产生一个 10x10 的迷宫吧:
- maze = new MazeEntity(new Vector3(3f, 0, 3f), MazeEntity.GenerateMaze(10,10), 3.0f, 1.0f);
50x50 的迷宫也只要改两个数字:
换 100x100 的迷宫....
这下子虚拟环境变得龟龟的了...
让我们继续一下章教程:
《Robotics Studio学习教程:第二十六天——让我们在迷宫中加入机器人!》