便捷建造模组开发详细过程
EasyBuildMod是一个便捷建造模组,它包含了三个物品:物块放置助手可以快速将物块或墙壁放置在一个矩形区域、物块摧毁助手可以快速摧毁矩形区域内的物块或墙壁、物品拾取磁铁则可用于快速拾取摧毁后掉落的物品。
制作这个模组主要是因为自己在游戏中想挖空或建造地形进行建造战斗场地时,直接手动挖空或放置非常耗时,而自己尝试过某些模组但都不太能满足自己需要,比如Fargo的“城市克星”,摧毁范围大但是墙壁无法破坏,还有“更好的体验”模组,放置和摧毁物块的效率并不算太高。暂时也没找到其他模组(如果有欢迎提出)。所以就自己动手写了一个。
2.模组物品制作
本模组包含三个物品,物品拾取磁铁、物块放置助手和物块摧毁助手。定义了一个全局的EasyBuildModPlayer
类继承自ModPlayer
,来控制使用某些物品或拥有某些效果时玩家的行为改变。
2.1物品拾取磁铁
ItemGrabMagnet,该物品借鉴了懒人模组中的战利品磁铁和ItemMagnetPlus模组。希望达到的效果是使用后玩家拥有“物品拾取”的Buff,可以扩大拾取范围,再次使用则可以关闭。
首先是ItemGrabMagnet的代码。这部分的代码比较简单,就是在玩家使用物品时判断是否已经拥有Buff,如果没有则添加Buff,如果有则移除Buff。
有几个细节的地方:由于想要的是使用磁铁后buff时间无限长,在Buff中设置剩余时间不可见,在给Buff时设置足够长的时间即可。
还有一个要注意的地方就是CombatText.NewText
会默认对所有玩家触发,也就是玩家A在使用时,玩家B也能看到CombatText.NewText
的讯息,所以CombatText.NewText
的第一个参数不能用Main.LocalPlayer,否则其他人使用时也会显示在自己这里。
public class ItemGrabBuff : ModBuff
{ public override void SetStaticDefaults()
{
Main.buffNoTimeDisplay[Type] = true;
Main.debuff[Type] = false;
} public override void Update(Player player, ref int buffIndex)
{
player.GetModPlayer<EasyBuildModPlayer>().ItemGrabBuff = true;
}
}
public class ItemGrabMagnet : ModItem
{ internal static string GetText(string str, params object[] args)
{ return Language.GetTextValue($"Mods.EasyBuildMod.Content.Items.ItemGrabMagnet.{str}", args);
} public override string Texture => "EasyBuildMod/Content/Items/ItemGrabMagnet"; public bool IsMagnetOn; public override void SetStaticDefaults()
{
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
} public override void SetDefaults()
{
Item.width = 30;
Item.height = 30;
Item.maxStack = 1;
Item.value = Item.sellPrice(gold: 1);
Item.rare = ItemRarityID.Blue;
Item.useAnimation = 15;
Item.useTime = 20;
Item.useStyle = ItemUseStyleID.HoldUp;
Item.consumable = false;
IsMagnetOn = false;
} public override void AddRecipes()
{ // 20个铁锭/铅锭
CreateRecipe()
.AddRecipeGroup("IronBar", 20)
.AddTile(TileID.Anvils)
.Register();
} public override bool? UseItem(Player player)
{
IsMagnetOn = !player.HasBuff(ModContent.BuffType<Buffs.ItemGrabBuff>()); if (IsMagnetOn)
{
CombatText.NewText(player.Hitbox, Color.Green, GetText("OnTooltip"));
player.AddBuff(ModContent.BuffType<Buffs.ItemGrabBuff>(), 2592000);
SoundEngine.PlaySound(SoundID.MenuTick);
} else
{
CombatText.NewText(player.Hitbox, Color.Red, GetText("OffTooltip"));
player.ClearBuff(ModContent.BuffType<Buffs.ItemGrabBuff>());
SoundEngine.PlaySound(SoundID.MenuClose);
} return true;
} public override void ModifyTooltips(List<TooltipLine> tooltips)
{ string color = IsMagnetOn ? "00FF00" : "FF0000"; string tooltop = IsMagnetOn ? GetText("OnTooltip") : GetText("OffTooltip"); var line = new TooltipLine(Mod, GetText("StatusName"), $"[c/{color}:{tooltop}]");
tooltips.Add(line);
}
}
然后是物品拾取范围扩大的实现。新定义EasyBuildModGlobalItem
继承自GlobalItem
,重写其中的GrabRange方法。注意格子数与游戏实际距离的换算是乘除16。
public class EasyBuildModGlobalItem : GlobalItem
{ public override void GrabRange(Item item, Player player, ref int grabRange)
{ if (player.GetModPlayer<EasyBuildModPlayer>().ItemGrabBuff)
{
grabRange = ModContent.GetInstance<EasyBuildModConfig>().MagnetRange * 16;
}
}
}
至此便基本实现了ItemGrabMagnet的功能。效果如下:


2.2物块放置与摧毁助手基类
ItemPlaceHelper与ItemDestroyHelper二者都有共同的特点,一个是可以通过右键调出菜单进行选择,一个是左键可以框选区域进行放置或破坏。自己最开始是先写了ItemPlaceHelper,而后写另一个的时候才意识到有大量重复的逻辑。为了避免过多重复代码,这里就二者的共同特点提取出一个抽象基类。
这里分成了三部分,物品自身、菜单和区域选择。
2.2.1Item实现
主要就是定义了物品的基本行为,如右键调出菜单,左键进行框选。调出菜单在重写CanUseItem
中进行实现,选择区域则是在UseItem
,这样处理更为方便。这种情况下,ItemPlaceHelper
与ItemDestroyHelper
只需重写StartAction
方法即可。