💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
## 太空工程师编程笔记2 - 获取和控制其他块 ### 游戏中的块对象 游戏中,我们会用到各种块,从大小上直观分为大船块和小船块。 在游戏内部的表示,其实是一些不同的具有继承关系的类,然后各类具体的块是子类。 常见的继承关系为: IMyEntity->IMyCubeBlock->IMyTerminalBlock->IMyFunctionalBlock->具体的块类 但也可能并不继承某些接口,比如装甲块就只继承到IMyCubeBlock,具体继承关系要看具体定义。 游戏内编程对块操作基本上是获取继承了这些接口的块,然后通过接口对块进行操作。 #### 具体块继承的基本接口 IMyEntity是游戏世界中的实体,比如块、陨石、导弹等等都可以算是实体,这个接口比较底层,贴近游戏引擎。利用这个接口可以得到块的基础信息。 ~~~csharp public interface IMyEntity { // Methods IMyInventory GetInventory(); IMyInventory GetInventory(int index); Vector3D GetPosition(); // Properties MyEntityComponentContainer Components { get; } long EntityId { get; } string Name { get; } string DisplayName { get; } bool HasInventory { get; } int InventoryCount { get; } BoundingBoxD WorldAABB { get; } BoundingBoxD WorldAABBHr { get; } MatrixD WorldMatrix { get; } BoundingSphereD WorldVolume { get; } BoundingSphereD WorldVolumeHr { get; } } ~~~ IMyCubeBlock是方块,各类方块,包括装甲块在内,都属于IMyCubeBlock。利用这个接口可以得到块的各类状态信息。 ~~~csharp public interface IMyCubeBlock : IMyEntity { // Methods string GetOwnerFactionTag(); [Obsolete("GetPlayerRelationToOwner() is useless ingame. Mods should use the one in ModAPI.IMyCubeBlock")] MyRelationsBetweenPlayerAndBlock GetPlayerRelationToOwner(); MyRelationsBetweenPlayerAndBlock GetUserRelationToOwner(long playerId); [Obsolete] void UpdateIsWorking(); [Obsolete] void UpdateVisual(); // Properties SerializableDefinitionId BlockDefinition { get; } bool CheckConnectionAllowed { get; } IMyCubeGrid CubeGrid { get; } string DefinitionDisplayNameText { get; } float DisassembleRatio { get; } string DisplayNameText { get; } bool IsBeingHacked { get; } bool IsFunctional { get; } bool IsWorking { get; } Vector3I Max { get; } float Mass { get; } Vector3I Min { get; } int NumberInGrid { get; } MyBlockOrientation Orientation { get; } long OwnerId { get; } Vector3I Position { get; } } ~~~ IMyTerminalBlock是终端方块,即在终端界面有界面的,能进行互动。可以操纵名字一类的信息,并且可以利用编程块互动。 ~~~csharp public interface IMyTerminalBlock : IMyCubeBlock, IMyEntity { // Methods void GetActions(List<ITerminalAction> resultList, Func<ITerminalAction, bool> collect = null); ITerminalAction GetActionWithName(string name); void GetProperties(List<ITerminalProperty> resultList, Func<ITerminalProperty, bool> collect = null); ITerminalProperty GetProperty(string id); bool HasLocalPlayerAccess(); bool HasPlayerAccess(long playerId); void SearchActionsOfName(string name, List<ITerminalAction> resultList, Func<ITerminalAction, bool> collect = null); [Obsolete("Use the setter of Customname")] void SetCustomName(string text); [Obsolete("Use the setter of Customname")] void SetCustomName(StringBuilder text); // Properties string CustomName { get; set; } string CustomNameWithFaction { get; } string DetailedInfo { get; } string CustomInfo { get; } string CustomData { get; set; } bool ShowOnHUD { get; set; } bool ShowInTerminal { get; set; } bool ShowInToolbarConfig { get; set; } bool ShowInInventory { get; set; } } ~~~ IMyFunctionalBlock是功能方块,简单来说就是能开关的方块。可以用代码开关。 ~~~csharp public interface IMyFunctionalBlock : IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods [Obsolete("Use the setter of Enabled")] void RequestEnable(bool enable); // Properties bool Enabled { get; set; } } ~~~ #### 具体块 游戏中有数十种块,对应不同的类。 编程块可操作的列表如下: ~~~csharp public interface IMyAdvancedDoor : IMyDoor, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyAirtightDoorBase : IMyDoor, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyAirtightHangarDoor : IMyAirtightDoorBase, IMyDoor, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyAirtightSlideDoor : IMyAirtightDoorBase, IMyDoor, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyAssembler : IMyProductionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyAttachableTopBlock : IMyCubeBlock, IMyEntity public interface IMyBatteryBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyBeacon : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyBlockGroup public interface IMyCameraBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyCargoContainer : IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyCockpit : IMyShipController, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyCollector : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyConveyor : IMyCubeBlock, IMyEntity public interface IMyConveyorSorter : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyConveyorTube : IMyCubeBlock, IMyEntity public interface IMyCryoChamber : IMyCockpit, IMyShipController, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyDecoy : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyDoor : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyExtendedPistonBase : IMyPistonBase, IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyFunctionalBlock : IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyGasGenerator : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyGasTank : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyGridProgramRuntimeInfo public interface IMyGridTerminalSystem public interface IMyGyro : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyJumpDrive : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyLargeTurretBase : IMyUserControllableGun, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyLaserAntenna : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyLightingBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyMechanicalConnectionBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyMotorAdvancedRotor : IMyMotorRotor, IMyAttachableTopBlock, IMyCubeBlock, IMyEntity public interface IMyMotorAdvancedStator : IMyMotorStator, IMyMotorBase, IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyMotorBase : IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyMotorRotor : IMyAttachableTopBlock, IMyCubeBlock, IMyEntity public interface IMyMotorStator : IMyMotorBase, IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyMotorSuspension : IMyMotorBase, IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyOreDetector : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity [Obsolete("Use IMyGasGenerator")] public interface IMyOxygenGenerator : IMyGasGenerator, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity [Obsolete("Use IMyGasTank")] public interface IMyOxygenTank : IMyGasTank, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyPassage : IMyCubeBlock, IMyEntity public interface IMyPistonBase : IMyMechanicalConnectionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyPistonTop : IMyAttachableTopBlock, IMyCubeBlock, IMyEntity public interface IMyProductionBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyProgrammableBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyProjector : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyRadioAntenna : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyReactor : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyRefinery : IMyProductionBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyReflectorLight : IMyLightingBlock, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyRemoteControl : IMyShipController, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMySensorBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipConnector : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipController : IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipDrill : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipGrinder : IMyShipToolBase, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipToolBase : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyShipWelder : IMyShipToolBase, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMySmallGatlingGun : IMyUserControllableGun, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMySmallMissileLauncher : IMyUserControllableGun, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMySmallMissileLauncherReload : IMySmallMissileLauncher, IMyUserControllableGun, IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyTerminalBlock : IMyCubeBlock, IMyEntity public interface IMyTextPanel : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyThrust : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyUpgradableBlock : IMyCubeBlock, IMyEntity public interface IMyUpgradeModule : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyUserControllableGun : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyWarhead : IMyTerminalBlock, IMyCubeBlock, IMyEntity public interface IMyWheel : IMyMotorRotor, IMyAttachableTopBlock, IMyCubeBlock, IMyEntity ~~~ 这些具体块也会有一定继承关系,比如说组装机和精炼厂都继承自IMyProductionBlock,利用这个接口可以控制生产。 ~~~csharp public interface IMyProductionBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Methods void AddQueueItem(MyDefinitionId blueprint, decimal amount); void AddQueueItem(MyDefinitionId blueprint, double amount); void AddQueueItem(MyDefinitionId blueprint, MyFixedPoint amount); bool CanUseBlueprint(MyDefinitionId blueprint); void ClearQueue(); void GetQueue(List<MyProductionItem> items); void InsertQueueItem(int idx, MyDefinitionId blueprint, decimal amount); void InsertQueueItem(int idx, MyDefinitionId blueprint, double amount); void InsertQueueItem(int idx, MyDefinitionId blueprint, MyFixedPoint amount); void MoveQueueItemRequest(uint queueItemId, int targetIdx); void RemoveQueueItem(int idx, decimal amount); void RemoveQueueItem(int idx, double amount); void RemoveQueueItem(int idx, MyFixedPoint amount); // Properties IMyInventory InputInventory { get; } IMyInventory OutputInventory { get; } bool IsProducing { get; } bool IsQueueEmpty { get; } uint NextItemId { get; } bool UseConveyorSystem { get; set; } } ~~~ ### 获取和操作块 获取块主要是通过编程块中GridTerminalSystem对象来进行。 **获取块** ~~~csharp int tick=0; public Program() { // The constructor, called only once every session and // always before any other method is called. Use it to // initialize your script. // // The constructor is optional and can be removed if not // needed. // // It's recommended to set RuntimeInfo.UpdateFrequency // here, which will allow your script to run itself without a // timer block. Runtime.UpdateFrequency = UpdateFrequency.Update1; } public void Main(string argument, UpdateType updateSource) { // The main entry point of the script, invoked every time // one of the programmable block's Run actions are invoked, // or the script updates itself. The updateSource argument // describes where the update came from. // // The method itself is required, but the arguments above // can be removed if not needed. Echo("Running "+tick++); //第一种获取方式 IMyTerminalBlock block=(IMyTerminalBlock)GridTerminalSystem.GetBlockWithName("testBlock"); if(block!=null)Echo("GetBlockWithName: "+block.ToString()); //第二种获取方式 List<IMyBatteryBlock> blocks=new List<IMyBatteryBlock>(); GridTerminalSystem.GetBlocksOfType<IMyBatteryBlock>(blocks); if(blocks.Count>0){ Echo("GetBlocksOfType: "+blocks[0].ToString()); //获取电池块的状态 Echo("电池是否处于单工模式:"+blocks[0].SemiautoEnabled); } } ~~~ **执行结果** 将电池命名为“testBlock”后,终端显示当前运行次数和两个电池ToString信息 MyBatteryBlock{块id}testBlock 说明两种方式均成功获取到电池块。 同时,能够显示电池的属性。 **本次使用功能** GridTerminalSystem ~~~csharp public interface IMyGridTerminalSystem { // Methods void GetBlockGroups(List<IMyBlockGroup> blockGroups, Func<IMyBlockGroup, bool> collect = null); IMyBlockGroup GetBlockGroupWithName(string name); void GetBlocks(List<IMyTerminalBlock> blocks); void GetBlocksOfType<T>(List<IMyTerminalBlock> blocks, Func<IMyTerminalBlock, bool> collect = null) where T: class; void GetBlocksOfType<T>(List<T> blocks, Func<T, bool> collect = null) where T: class; IMyTerminalBlock GetBlockWithId(long id); IMyTerminalBlock GetBlockWithName(string name); void SearchBlocksOfName(string name, List<IMyTerminalBlock> blocks, Func<IMyTerminalBlock, bool> collect = null); } ~~~ 电池块 ~~~csharp public interface IMyBatteryBlock : IMyFunctionalBlock, IMyTerminalBlock, IMyCubeBlock, IMyEntity { // Properties bool HasCapacityRemaining { get; } float CurrentStoredPower { get; } float MaxStoredPower { get; } float CurrentInput { get; } float MaxInput { get; } float CurrentOutput { get; } float MaxOutput { get; } bool IsCharging { get; } bool OnlyRecharge { get; set; } bool OnlyDischarge { get; set; } bool SemiautoEnabled { get; set; } } ~~~ #### 对块进行操作 对块进行操作有两种方式,一种是直接调用或赋值,另一种是“动作”。 **先来看动作** ~~~csharp public void Main(string argument, UpdateType updateSource) { //先获取块 IMyTerminalBlock block=(IMyTerminalBlock)GridTerminalSystem.GetBlockWithName("testBlock"); if(block!=null)Echo("GetBlockWithName: "+block.ToString()); //获取该块可以进行的动作 List<ITerminalAction> resultList=new List<ITerminalAction>(); block.GetActions(resultList); //在终端输出 Echo("testBlock可进行的动作如下:"); foreach (var item in resultList) { Echo(item.Id+" -> "+item.Name.ToString()); } } ~~~ **执行结果** 按下run之后,打印了电池可进行的动作,如下: ~~~ OnOff -> Toggle block On/Off OnOff_On -> Toggle block On OnOff_Off -> Toggle block Off Recharge -> Recharge On/Off Discharge -> Discharge On/Off SemiAuto -> Semi-auto On/Off ~~~ 各块具体动作有哪些可参考https://spaceengineerswiki.com/Programming_Guide/Action_List **执行动作** ~~~csharp public void Main(string argument, UpdateType updateSource) { //先获取块 IMyTerminalBlock block=(IMyTerminalBlock)GridTerminalSystem.GetBlockWithName("testBlock"); if(block!=null)Echo("GetBlockWithName: "+block.ToString()); //获取该块可以进行的动作(这里采用第二种方法) //List<ITerminalAction> resultList=new List<ITerminalAction>(); //block.GetActions(resultList); ITerminalAction action=block.GetActionWithName("SemiAuto"); action.Apply(block); } ~~~ **执行结果** 每点击一次run,电池的单双工状态就被切换一次。