[Robotics Studio] CameraSprite in VSE -- Day27
因為迷宮太難了, 先來學其他比較簡單的東西 - -
話說 Day21 的時候為了看到機器人的 Camera, 費盡辛苦寫了一個視窗, 還要寫一些 code 用來連接 虛擬 Camera 送來的訊息以及將資料轉成 Image 等等...
但是有了 CameraSprite 就變成好簡單...
只要在 虛擬的 Camera Entity 加上一個 CameraSprite (一定要是 Camera Entity 的子物件),
透過 VSE 你就可以在該 Camera 的某個相對位置上看到 Camera 的畫面.
就拿相撲機器人的 SumoCompetition 專案來作範例吧,
首先打開該範例, 切到 SimulatedSumoReferee 專案的 SimulatedSumoReferee.cs, 找到 EntityManager.CreateRobot 函式, 在產生出 Camera Entity 的時候,
生出一個 CameraSprite 在該 Camera 上方 1 公尺處, 大小為 50x50 cm, 如下面的四行 code:
// Add a camera
CameraEntity sumoCam = new CameraEntity(176, 144, (float)(27.0 * Math.PI / 180.0), CameraEntity.CameraModelType.AttachedChild); // 20 degree FOV
sumoCam.State.Name = newRobot.State.Name + "/SumoCam";
sumoCam.State.Pose.Position = new Vector3(0, 0.17f, 0.005f);
sumoCam.Rotation = new xna.Vector3(-8.0f, 0, 0);
sumoCam.State.Assets.Mesh = "WebCam.obj";
sumoCam.IsRealTimeCamera = true;
sumoCam.UpdateInterval = 350; // update less then 3 times per second
//把 CameraSprite 加到 Camera Entity 的子物件當中
CameraSprite camSprite = new CameraSprite(0.5f, 0.5f, SpritePivotType.Center, 0, new Vector3(0, 1, 0));
camSprite.State.Name = newRobot.State.Name + "/camSprite";
camSprite.Flags |= VisualEntityProperties.DisableBackfaceCulling;
sumoCam.InsertEntity(camSprite);
newRobot.InsertEntity(sumoCam);
恩, 就這樣, 雙方的機器人上面都有一個攝影機的畫面啦!
決鬥過程也都可以看到...
這麼簡單就混過一天, 可能會被罵的, 所以我再補一點關於 SpriteEntity 的東西好了,
CameraSprite 是繼承自 SpriteEntity 的, 如果我們要自己做一個簡單的 SpriteEntity, 可以直接用 SpriteEntity, 或繼承一個.
假設我們要作一個 TextSprite (我很奇怪為什麼微軟不幫我們做一個這樣的? 反而做 EntityNameSprite ,只會顯示 parent 物件的名稱?! 這麼狹隘的 class?!)
code 如下 :
public class TextSprite : SpriteEntity
{
private string _fontFamily;
private float _fontSize;
private string _text;
/// <summary>
/// The font family name of the font to use
/// </summary>
[DataMember]
public string FontFamily
{
get { return _fontFamily; }
set { _fontFamily = value; }
}
/// <summary>
/// The font size of the font to use
/// </summary>
[DataMember]
public float FontSize
{
get { return _fontSize; }
set { _fontSize = value; }
}
/// <summary>
/// Default constructor
/// </summary>
public TextSprite() { }
/// <summary>
/// Initialization constructor
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="textureWidth"></param>
/// <param name="textureHeight"></param>
/// <param name="pivot"></param>
/// <param name="initialPos"></param>
/// <param name="family"></param>
/// <param name="fontSize"></param>
public TextSprite(string text, float width, float height, int textureWidth, int textureHeight, SpritePivotType pivot, Vector3 initialPos, string family, float fontSize)
: base(width, height, textureWidth, textureHeight, pivot, initialPos)
{
_text = text;
_fontFamily = family;
_fontSize = fontSize;
}
/// <summary>
/// Initialize
/// </summary>
/// <param name="device"></param>
/// <param name="physicsEngine"></param>
public override void Initialize(Microsoft.Xna.Framework.Graphics.GraphicsDevice device, PhysicsEngine physicsEngine)
{
try
{
InitError = string.Empty;
Font nameFont = new Font(_fontFamily, _fontSize);
base.Initialize(device, physicsEngine);
Bitmap target = GetBitmap();
Graphics g = Graphics.FromImage(target);
g.FillRectangle(Brushes.DarkBlue, 0, 0, target.Width, target.Height);
StringFormat nameFormat = new StringFormat();
nameFormat.Alignment = StringAlignment.Center;
nameFormat.LineAlignment = StringAlignment.Center;
g.DrawString(_text, nameFont, Brushes.White, new Rectangle(0, 0, target.Width, target.Height), nameFormat);
SetBitmap(target);
}
catch (Exception ex)
{
HasBeenInitialized = false;
InitError = ex.ToString();
}
}
}
這樣我們就可以在 VSE 當中產生一片文字 (就像魔獸的人物上面都會掛一塊名牌)
透過在剛剛的 Add CameraSprite 之後再加上:
//加上 TextSprite
TextSprite txtSprite = new TextSprite("Hello! I am "+newRobot.State.Name, 0.5f, 0.0625f, 512, 64, SpritePivotType.Center, new Vector3(0, 0.25f, 0), "Courier", 14);
txtSprite.State.Name = newRobot.State.Name + "/txtSprite";
newRobot.InsertEntity(txtSprite);
這個 TextSprite 比原本的 EntityNameSprite 好用多了, 不但可以顯示任何字 (要考慮字型), 還可以不限定要加在某個 Entity 當中 (直接加到 VSE).
(因為原本的 EntityNameSprite 一定要掛在某個 Entity 下面, 用來顯示該 Entity 的名稱)