ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 太空工程师编程笔记4 - 界面与通信 ### 交互 之前程序执行时,均是使用编程块的Terminal界面作为输出,输入也基本是手工进行。其实这并不便捷,程序要实际使用时,就要有更好的输入输出方式了。 简单总结了一下,游戏中程序可获得的输入有这几种: 1、命令行。即main函数运行的参数。可以由人工设定在控制台上,或者直接在run处输入,也可以由其他程序和事件调用。 2、其他块的状态和信息。由程序主动取得并获取输入。例如控制台可以得到鼠标的运动状态,各类其他块上的信息也可以参考。 而输出也基本是这么几类: 1、输出在编程块自己的界面上。 2、输出在其他块上。比如显示屏、比如直接产生运动或者各类操作。 2、调用其它程序。 这里比较有意思的是跨网格程序之间的通信,因为程序只能获取到自身所在网格的块,所以无法直接调用其它网格的编程块中的程序,所以要用专门的跨网格通信机制,这就是天线。 ### 示例 OK,我们直接来看代码。 #### LCD显示字符串 让第一个LCD显示字符串。 ~~~csharp int tick=0; public Program() { Runtime.UpdateFrequency = UpdateFrequency.Update1; } public void Main(string argument, UpdateType updateSource) { //先获取一个TextPanel List<IMyTextPanel> panels=new List<IMyTextPanel>(); GridTerminalSystem.GetBlocksOfType<IMyTextPanel>(panels); Echo("共有LCD个数:"+panels.Count); if(panels.Count<1)return; //取第一个 IMyTextPanel panel=panels[0]; Echo("目标LCD是:"+panel.CustomName); //开启LCD显示 panel.ShowPublicTextOnScreen(); //输出字符 panel.WritePublicText("字符输出实验"); //追加字符 panel.WritePublicText(tick++.ToString(),true); } ~~~ **执行结果** 第一个LCD上显示“字符输出实验”,并且数字快速跳动。 我们还能够观察到LCD上有一些非字符的残余图像,出于这个,我们其实可以合理推测,LCD上显示的其实是根据文本即时绘制的图像。 其实TextPanel也有 *AddImagesToSelection* 、*ClearImagesFromSelection*、*RemoveImageFromSelection*、*ChangeInterval*、*ShowTextureOnScreen*这些接口,应该就是用于显示图像。但是具体怎么用,这里就不做尝试了。 ### Cockpit输入模拟鼠标键盘 尝试从Cockpit获取运动状态来获取鼠标键盘输入,当然,键盘肯定是不全的。 ~~~csharp public Program() { Runtime.UpdateFrequency = UpdateFrequency.Update1; } public void Main(string argument, UpdateType updateSource) { //先获取一个TextPanel List<IMyTextPanel> panels=new List<IMyTextPanel>(); GridTerminalSystem.GetBlocksOfType<IMyTextPanel>(panels); Echo("共有LCD个数:"+panels.Count); if(panels.Count<1)return; //取第一个 IMyTextPanel panel=panels[0]; //再获取名为Mouse&Arrow的驾驶舱 IMyShipController mak=(IMyShipController)GridTerminalSystem.GetBlockWithName("Mouse&Arrow"); if(mak==null){ Echo("Mouse&Arrow not Found."); return; } //通过驾驶舱运动指示来判断鼠标和键盘 Vector2 mousemove=mak.RotationIndicator; string key=getKey(mak); panel.ShowPublicTextOnScreen(); panel.WritePublicText("鼠标X:"+mousemove.X); panel.WritePublicText("\r\n鼠标Y:"+mousemove.Y,true); panel.WritePublicText("\r\n键盘按键:"+key,true); } private string getKey(IMyShipController keyboard){ if(keyboard.MoveIndicator.X==-1)return "A"; if(keyboard.MoveIndicator.X==1)return "D"; if(keyboard.MoveIndicator.Y==-1)return "C"; if(keyboard.MoveIndicator.Y==1)return "Space"; if(keyboard.MoveIndicator.Z==-1)return "W"; if(keyboard.MoveIndicator.Z==1)return "S"; if(keyboard.RollIndicator>0)return "E"; if(keyboard.RollIndicator<0)return "Q"; return ""; } ~~~ **执行结果** 能够基本正确识别和显示鼠标和键盘输入。 这些运动状态除了翻译成鼠标键盘输入外,一般还可直接作为控制输入,用于实现各类运动控制,比如重力引擎。 #### 天线通信 使用天线发送和接收消息,并将消息显示在LCD上。 ~~~csharp public Program() { Runtime.UpdateFrequency = UpdateFrequency.Update1; } int tick=0; int received=0; public void Main(string argument, UpdateType updateSource) { //获取一个屏幕 List<IMyTextPanel> panels=new List<IMyTextPanel>(); GridTerminalSystem.GetBlocksOfType<IMyTextPanel>(panels); Echo("共有LCD个数:"+panels.Count); if(panels.Count<1)return; IMyTextPanel panel=panels[0]; panel.ShowPublicTextOnScreen(); //获取一个IMyRadioAntenna List<IMyRadioAntenna> antennas=new List<IMyRadioAntenna>(); GridTerminalSystem.GetBlocksOfType<IMyRadioAntenna>(antennas); Echo("共有Antenna个数:"+antennas.Count); if(antennas.Count<1)return; IMyRadioAntenna antenna=antennas[0]; //设定广播接收 antenna.AttachedProgrammableBlock=Me.EntityId; //处理通信 if(updateSource==UpdateType.Antenna){ Echo("Receiving..."); Echo(argument); panel.WritePublicText(argument+"\n",received++>0); }else{ if(received>0){Echo("Received "+received);received=0;} Echo("Sending..."); antenna.TransmitMessage(tick++.ToString()); } } ~~~ **执行结果** 将具备LCD和天线的实验网格复制多份,可以看到同时发出和收到多份消息。 说明目前版本的太空工程师允许全双工收发,并且可以多次接收消息。 ### 资料 #### LCD的接口IMyTextPanel ~~~csharp public interface IMyTextPanel : IMyTextSurface, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods void AddImagesToSelection(List<string> ids, bool checkExistence = false); void AddImageToSelection(string id, bool checkExistence = false); void ClearImagesFromSelection(); void GetFonts(List<string> fonts); [Obsolete("LCD private text is deprecated")] string GetPrivateText(); [Obsolete("LCD private text is deprecated")] string GetPrivateTitle(); string GetPublicText(); string GetPublicTitle(); void GetSelectedImages(List<string> output); void ReadPublicText(StringBuilder buffer, bool append = false); void RemoveImageFromSelection(string id, bool removeDuplicates = false); void RemoveImagesFromSelection(List<string> ids, bool removeDuplicates = false); void SetShowOnScreen(ShowTextOnScreenFlag set); [Obsolete("LCD private text is deprecated")] void ShowPrivateTextOnScreen(); void ShowPublicTextOnScreen(); void ShowTextureOnScreen(); [Obsolete("LCD private text is deprecated")] bool WritePrivateText(string value, bool append = false); [Obsolete("LCD private text is deprecated")] bool WritePrivateTitle(string value, bool append = false); [Obsolete("LCD public text is deprecated")] bool WritePublicText(string value, bool append = false); [Obsolete("LCD public text is deprecated")] bool WritePublicText(StringBuilder value, bool append = false); bool WritePublicTitle(string value, bool append = false); // Properties string CurrentlyShownImage { get; } ShowTextOnScreenFlag ShowOnScreen { get; } bool ShowText { get; } float FontSize { get; set; } Color FontColor { get; set; } Color BackgroundColor { get; set; } float ChangeInterval { get; set; } string Font { get; set; } } ~~~ #### IMyTextSurface ~~~csharp public interface IMyTextSurface { // Methods void AddImagesToSelection(List<string> ids, bool checkExistence = false); void AddImageToSelection(string id, bool checkExistence = false); void ClearImagesFromSelection(); MySpriteDrawFrame DrawFrame(); void GetFonts(List<string> fonts); void GetScripts(List<string> scripts); void GetSelectedImages(List<string> output); void GetSprites(List<string> sprites); string GetText(); Vector2 MeasureStringInPixels(StringBuilder text, string font, float scale); void ReadText(StringBuilder buffer, bool append = false); void RemoveImageFromSelection(string id, bool removeDuplicates = false); void RemoveImagesFromSelection(List<string> ids, bool removeDuplicates = false); bool WriteText(StringBuilder value, bool append = false); bool WriteText(string value, bool append = false); // Properties float FontSize { get; set; } Color ScriptForegroundColor { get; set; } Color ScriptBackgroundColor { get; set; } float TextPadding { get; set; } bool PreserveAspectRatio { get; set; } Vector2 TextureSize { get; } Vector2 SurfaceSize { get; } ContentType ContentType { get; set; } string Script { get; set; } TextAlignment Alignment { get; set; } string Font { get; set; } float ChangeInterval { get; set; } byte BackgroundAlpha { get; set; } Color BackgroundColor { get; set; } Color FontColor { get; set; } string Name { get; } string DisplayName { get; } string CurrentlyShownImage { get; } } ~~~ #### IMyShipController ~~~csharp public interface IMyShipController : IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods MyShipMass CalculateShipMass(); Vector3D GetArtificialGravity(); Vector3D GetNaturalGravity(); double GetShipSpeed(); MyShipVelocities GetShipVelocities(); Vector3D GetTotalGravity(); bool TryGetPlanetElevation(MyPlanetElevation detail, out double elevation); bool TryGetPlanetPosition(out Vector3D position); // Properties bool CanControlShip { get; } bool IsUnderControl { get; } bool HasWheels { get; } bool ControlWheels { get; set; } bool ControlThrusters { get; set; } bool HandBrake { get; set; } bool DampenersOverride { get; set; } bool ShowHorizonIndicator { get; set; } Vector3 MoveIndicator { get; } Vector2 RotationIndicator { get; } float RollIndicator { get; } Vector3D CenterOfMass { get; } bool IsMainCockpit { get; set; } } ~~~ #### IMyRadioAntenna ~~~csharp public interface IMyRadioAntenna : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods bool TransmitMessage(string message, MyTransmitTarget target = 3); // Properties float Radius { get; set; } bool ShowShipName { get; set; } bool IsBroadcasting { get; } bool EnableBroadcasting { get; set; } long AttachedProgrammableBlock { get; set; } bool IgnoreAlliedBroadcast { get; set; } bool IgnoreOtherBroadcast { get; set; } } ~~~ #### IMyLaserAntenna ~~~csharp public interface IMyLaserAntenna : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods void Connect(); void SetTargetCoords(string coords); bool TransmitMessage(string message); // Properties bool RequireLoS { get; } Vector3D TargetCoords { get; } bool IsPermanent { get; set; } [Obsolete("Check the Status property instead.")] bool IsOutsideLimits { get; } MyLaserAntennaStatus Status { get; } long AttachedProgrammableBlock { get; set; } float Range { get; set; } } ~~~ #### UpdateType ~~~csharp public enum UpdateType { None = 0, Terminal = 1, Trigger = 2, Antenna = 4, Mod = 8, Script = 0x10, Update1 = 0x20, Update10 = 0x40, Update100 = 0x80, Once = 0x100 } ~~~