跳至正文

认识ITownNPCProfile

各位读者早午晚上好啊_(:з」∠)_,又是我,霍霍城镇NPC的能手中学生。这一篇我们将好好认识一下ITownNPCProfile以及其使用方法。废话不多说,直接开始!

上一篇教程的传送门在这里~


认识接口

在认识这个东西之前,我们先简单了解一下什么是接口(interface):

举个例子,你开一家制造公司,专门生产“裙子语录机”。但是这个语录机必须遵循某种特定规格,所以你给子公司们下发了图纸,让他们必须比着图纸来造。这个“图纸”就是接口。

(如果你还不明白那就看官方文档去毕竟我也不太能解释的清)

我们今天的主角ITownNPCProfile就是一个接口,它提供了如下几个方法:

这就是一个很标准的接口

当你继承这个接口时,你的类里必须包含以上这些方法。我们后面创建的所有TownNPCProfile都需要比着这个“蓝图”来构建。


TownNPCProfile介绍

它是干啥的?

从这里开始我们直接将其简称为Profile,首先我们当然需要明白这东西是干什么的。

简单来说,Profile的功能就是控制你的NPC被分配到的贴图以及小地图头像还有姓名。普通城镇NPC并不需要太复杂的Profile,如果你的NPC不需要换材质甚至可以不需要Profile,但城镇宠物这种拥有随机外观的会很需要用到。

这一篇我们先介绍其最基础的用法。

它有哪些功能?

无论我们创建何种Profile,都需要继承ITownNPCProfile这个接口,接下来我们就一一介绍上文中提到的那些方法。首先,让我们建立一个Profile并继承该接口:

然后我们会需要在这个类里把上面的那四种方法都填写上。

什么?你懒得打字?没关系,VS会告诉你你的类没有实现这个接口中的哪些方法。只需要将光标放在ITownNPCProfile的后面,使用alt+enter的组合键,再点击“实现接口”,VS就能进行自动补全懒癌狂喜

非常强大的功能,活用可以省去很多麻烦

来,一个一个的看:

RollVariation,用于随机选取NPC的不同外观,在宠物里会用到,这里就不细说。常规的城镇NPC填0就行了。

GetNameForVariant,用于为NPC选取姓名,实际上这个方法更多是为原版使用的,我们几乎用不到。后文会说明怎么填写。

GetTextureNPCShouldUse,选取NPC使用的贴图,比如让该NPC在派对状态下切换到派对外观。后文会说明怎么填写。

GetHeadTextureIndex,选取NPC使用的小地图头像,一般而言一个NPC只需要一个头像。后文会说明怎么填写。

这里只是简单说一下它们大致的功能,下面然我们来看看该如何构建与使用吧。


如何构建TownNPCProfile?

在上面创建好了一个Profile之后,我们来挨个看一看如何填写它提供给我们的四个方法,让我们先把成品端上来:

//设置该NPC的本体与头像贴图以及姓名的信息,可通用
public class TestTownNPCProfile : ITownNPCProfile
{
    //基础材质路径
    string _rootPath;
    //派对材质路径
    string _altPath;
    //替换用小地图头像
    int _altHeadIndex;
    //在新声明一个此类时对其进行参数设置
    public TestTownNPCProfile(string rootPath, string altPath, int altHeadIndex = -1)
    {
        _rootPath = rootPath;
        _altPath = altPath;
        _altHeadIndex = altHeadIndex;
    }
    //随机选择NPC可用的外观,一般用不到
    public int RollVariation() => 0;
    //在不同的外观下会采用哪些名字池,一般用不到,直接如下填写
    public string GetNameForVariant(NPC npc) => npc.getNewNPCName();
    //设置绘制时使用的贴图,可以用来切换派对贴图与日常贴图
    public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
    {
        //当 切换到派对材质 且 并非图鉴展示 时使用派对皮肤
        if (npc.altTexture == 1 && !npc.IsABestiaryIconDummy)
        {
            return ModContent.Request<Texture2D>(_altPath);
        }
        return ModContent.Request<Texture2D>(_rootPath);
    }
    //设置头像贴图
    public int GetHeadTextureIndex(NPC npc)
    {
        //当 切换到派对材质 且 新头像ID不为-1 时 使用替换用头像
        if (npc.altTexture == 1 && _altHeadIndex != -1)
        {
            return _altHeadIndex;
        }
        return ModContent.GetModHeadSlot(_rootPath + "_Head");
    }
}

欸欸欸?那个 public TestTownNPCProfile 是个啥?前面怎么没说过啊?

这种写法叫构造方法,我们可以通过这种手段从外部实现对类内部的变量赋值,毕竟这个Profile以后还能拿去给别的NPC用嘛,咱们就写的通用性高一些,以后就不必给每个NPC都建一份Profile了。

首先,我们声明三个需要用到的变量,分别是 _rootPath基础材质路径_altPath替换用材质路径_altHeadIndex:替换用头像。同样的,在我们的构造方法内也提供了三种参数,分别对应这三个变量。

还是分别来看:

//随机选择NPC可用的外观,一般用不到
public int RollVariation() => 0;

这个在这里不作过多解释。

//在不同的外观下会采用哪些名字池,一般用不到,直接如下填写
public string GetNameForVariant(NPC npc) => npc.getNewNPCName();

npc.getNewNPCName() 就相当于调用了一次 SetNPCNameList()

当然你也可以给它加一些通用点缀比如npc.getNewNPCName()+"_Test",这样一来你的NPC在生成时其姓名后面就都会带一个“_Test”,比如“测试小伙_Test”。

//设置绘制时使用的贴图,可以用来切换派对贴图与日常贴图
public Asset<Texture2D> GetTextureNPCShouldUse(NPC npc)
{
    //当 切换到派对材质 且 并非图鉴展示 时使用派对皮肤
    if (npc.altTexture == 1 && !npc.IsABestiaryIconDummy)
    {
        return ModContent.Request<Texture2D>(_altPath);
    }
    return ModContent.Request<Texture2D>(_rootPath);
}

这个是本篇的重点之一,当派对事件发生时,npc.altTexture 就会变成1,平时这个属性的值为0。而 !npc.IsABestiaryIconDummy 是为了让NPC在图鉴展示时始终保持默认外形,不至于开派对时图鉴内也显示派对外观,当然如果你想这么做也不是不行。

//设置头像贴图
public int GetHeadTextureIndex(NPC npc)
{
    //当 切换到派对材质 且 新头像ID不为-1 时 使用替换用头像
    if (npc.altTexture == 1 && _altHeadIndex != -1)
    {
        return _altHeadIndex;
    }
    return ModContent.GetModHeadSlot(_rootPath + "_Head");
}

本篇的另一个重点,一般来说我们只需要最后一行那个返回值就可以了,但这次我们选择让NPC开派对时跟着换头像。

如果你直接返回了-1那么NPC的头像就不会被呈现在地图上

看到这儿你会发现这个 GetHeadTextureIndex 怎么是 int 类型啊?因为原版的头像就是 int 类型,而 GetModHeadSlot 的用途就是帮我们把对应路径下的头像转变成 int 类型的值。如果在这个路径下没有发现相应的贴图,就会返回-1。

这样把所有的方法都填好了,就完事儿了吗?当然没有,我们还没有在TestTownNPC应用这个Profile嘞!


如何使用TownNPCProfile?

建好了Profile之后,想要使用它就很简单了。首先回到我们的TestTownNPC中,插入这么一个重写函数:TownNPCProfile

这个重写函数本身的构成很简单,但是还记得前面我们提到的NPC头像的切换吗?GetModHeadSlot 只能获取已经被加入的头像,也就是 AutoloadHead 为你自动添加的那个默认头像。这里就来演示一下如何添加新的头像:

//通用路径,方便进行更改
static string rootPath = "TeaNPC/Content/NPCs/Towns/Test/TestTownNPC";
//替换用小地图头像
static int AltHeadSlot;
//加载数据,这里用于加载替换用小地图头像
public override void Load()
{
    //将该头像加入游戏内
    AltHeadSlot = Mod.AddNPCHeadTexture(Type, rootPath + "_Head_Party");
}
//设置NPC的贴图相关属性
public override ITownNPCProfile TownNPCProfile()
{
    return new TestTownNPCProfile(rootPath, rootPath + "_Party", AltHeadSlot);
}

首先声明一个 int 类型的变量即 AltHeadSlot

然后,插入一个重写函数:Load。这个函数会在你的Mod加载时执行,很适合进行一些初始化操作,这里我们用来添加新头像。

添加新头像用到了这么一个方法:Mod.AddNPCHeadTexture,第一个参数填写为之添加的NPC的ID即可,后面就是指定的路径。这样一来这个头像就被添加成功了,可以被 GetModHeadSlot 获取到了。

注意一下:这个方法仅适合城镇NPC,Boss有自己专属的AddBossHeadTexture,不要混着用啊。

最后,在TownNPCProfile中,新声明一个 TestTownNPCProfile,把我们准备好的参数填进去,就大功告成啦!

这样一来,以后我们创建了一个新的城镇NPC之后,只需要重复使用这次建立好的Profile就行了,方便的同时也减少了代码量。除非有特殊需求,我们将不会再需要建立新的Profile。


展示成果

处于派对状态下连带头像一起变成骚粉
图鉴中依旧显示为默认的白色外观

什么?你说你没有派对贴图?自己画一个去(无慈悲)


总结

有了这个新东西,我们就可以对城镇NPC进行更自由的编辑。还是那句话,只要你有足够的想法,在这上面实现更多有趣的功能完全不是问题。我是中学生,一个专门霍霍城镇NPC的屑仍在学习的模组作者,我们下次再见_(:з」∠)_

发表回复