注:前面的篇章基本上将基础都讲完了,那么现在我们开始真正步入主题——讲一讲如何实现 获取游戏内方块 的操作。
这是编写脚本最核心的能力之一,几乎所有自动化逻辑都离不开它。
获取方块有多种方法,而且也分获取 单个方块 还是 多个方块,这里我们只讲最常用的几种(剩下的可以自行查询 API 文档)。
主要分为:
这种方式就是根据游戏中显示的 方块名称 来获取对象。
⚠️ 注意:
GridTerminalSystem.GetBlockWithName("目标方块名字");
返回类型:
IMyTerminalBlock
通常需要 强制转换为具体类型1 才能使用。
因为程序只知道获取指定方块名的方块,但是不清楚这个方块的具体类型是什么。比如我获取的方块名字叫 门 但它可能实际上是一个转子(?)虽然这种情况一般不会发生(但愿吧)但是计算机是不知道的,所以它会给我们返回一个笼统的类型—— IMyTerminalBlock 接口,该接口是 所有有功能的方块 都具有的接口。
现在你可能意识到了一个问题 IMyTerminalBlock 接口既然是所有有功能方块都具有的接口,那么它们之间的功能怎么区分呢?诶!这你就问到点子上了,正因为它是一个笼统的接口所以它不具备具体方块的具体功能。
而现在我们需要门方块的具体功能,那么这个时候我们就需要使用 as 关键字来进行强制将 IMyTerminalBlock具体化为我们的需要的 IMyDoor 类型,也就是如下代码:
myDoor = GridTerminalSystem.GetBlockWithName("门") as IMyDoor;
// 使用 as 关键字强制让IMyTerminalBlock转为我们的IMyDoor类
我们以一个滑动门为例:
PS:此处代码省略类和命名空间等,可以直接复制进游戏内使用
IMyDoor myDoor;
public Program()
{
Runtime.UpdateFrequency = UpdateFrequency.Update10;
// 获取方块并转换类型
myDoor = GridTerminalSystem.GetBlockWithName("门") as IMyDoor;
}
public void Main(string argument, UpdateType updateSource)
{
Echo($"当前门的状态是:{myDoor.Status}");
}
如果名称写错:
myDoor = null;
调用时会直接报错。
建议养成检测习惯:
if (myDoor == null)
{
Echo("没有找到门!");
return;
}
当需要一次控制 多个方块 时,最常用的方法就是使用编组。
例如:
GridTerminalSystem.GetBlockGroupWithName("编组名称");
返回类型:
IMyBlockGroup
不能直接使用,需要再取出其中的方块。
IMyBlockGroup lightGroup;
List<IMyLightingBlock> lights = new List<IMyLightingBlock>();
public Program()
{
Runtime.UpdateFrequency = UpdateFrequency.Update10;
// 获取编组
lightGroup = GridTerminalSystem.GetBlockGroupWithName("照明系统");
// 将编组内的灯加入列表
lightGroup.GetBlocksOfType(lights);
}
public void Main(string arg, UpdateType source)
{
foreach (var light in lights)
{
light.Enabled = !light.Enabled; // 切换开关状态
}
}
获取编组 → 获取其中的方块 → 操作方块
List<IMyLightingBlock> lights; // 会报错
必须写成:
new List<IMyLightingBlock>();
一定要判空:
if (lightGroup == null)
{
Echo("未找到编组!");
return;
}
这是最常用的方式之一
GridTerminalSystem.GetBlocksOfType<T>(列表);
List<IMyBatteryBlock> batteries = new List<IMyBatteryBlock>();
public Program()
{
Runtime.UpdateFrequency = UpdateFrequency.Update100;
GridTerminalSystem.GetBlocksOfType(batteries);
}
public void Main(string arg, UpdateType source)
{
float totalPower = 0;
foreach (var battery in batteries)
{
totalPower += battery.CurrentStoredPower;
}
Echo($"总电量:{totalPower} MWh");
}
可以加入过滤器:
GridTerminalSystem.GetBlocksOfType(
batteries,
b => b.CustomName.Contains("主电池")
);
这样只获取 名称包含指定字符 的方块。
| 方法 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|
| 按名字获取 | 最简单 | 只能单个 | 只控制单一方块 |
| 按编组获取 | 灵活 | 需要手动编组 | 系统控制 |
| 按类型获取 | 自动化最强 | 需要筛选 | 自动化脚本 |
错误写法:
public void Main(...)
{
GridTerminalSystem.GetBlocksOfType(batteries);
}
这会严重影响性能
只在构造函数中获取一次:
public Program()
{
GridTerminalSystem.GetBlocksOfType(batteries);
}
或定期刷新:
if (tick % 600 == 0)
{
batteries.Clear();
GridTerminalSystem.GetBlocksOfType(batteries);
}
GetBlockWithName() 返回的是通用类型 IMyTerminalBlock,必须强制转换为具体接口(如 IMyDoor)后,才能访问该方块特有的属性和方法;若类型不匹配,转换结果会是 null。↩