跳至正文

Boss的创建与基础重写函数

前置知识: Steve_666:从零开始的NPC教程

好,从这里开始,我们的零基础Boss制作之旅

Boss的创建

好,既然是Boss教程,那我们就先来创建一个Boss,Boss是什么呢,其实就是一个NPC,要用 public class XXX : ModNPC 来创建一个基础的npc,但是boss需要一个特殊的属性,[AutoloadBossHead],这个属性干嘛的呢?就是加载npc地图上的大头贴,这个需要你自备图片

注意两点: [AutoloadBossHead] 要写在public class外,还有大头贴的命名格式:Boss名字_Head_Boss

大头贴文件
public override void SetDefaults()
{
    NPC.width = 114;
    NPC.height = 514;//这两个代表这个NPC的碰撞箱宽高,以及tr会从你的贴图里扣多大的图
    NPC.damage = 191;
    NPC.lifeMax = 9810;//npc的血量上限
    NPC.defense = 38;
    NPC.scale = 2.33f;//npc的贴图和碰撞箱的放缩倍率
    NPC.knockBackResist = 0f;
    NPC.HitSound = SoundID.NPCHit5;//挨打时发出的声音
    NPC.DeathSound = SoundID.NPCDeath7;//趋势时发出的声音
    NPC.value = Item.buyPrice(0, 4, 50, 0);//NPC的爆出来的MONEY的数量,四个空从左到右是铂金,金,银,铜
    NPC.lavaImmune = true;//对岩浆免疫
    NPC.noGravity = true;//不受重力影响。一般BOSS都是无重力的
    NPC.noTileCollide = true;//可穿墙
    NPC.npcSlots = 20; //NPC所占用的NPC数量,在TR世界里,NPC上限是200个,通常,这个用来限制Boss战时敌怪数量,填个10,20什么的
    NPC.boss = true; //将npc设为boss 会掉弱治药水和心,会显示xxx已被击败,会有血条
    NPC.dontTakeDamage = true;//为true则为无敌,这里的无敌意思是弹幕不会打到npc,并且npc的血条也不会显示了
    Music = MusicLoader.GetMusicSlot("xxx/Assets/Music/xxx");
}

还有几个基础属性

life是npc的当前血量

realLife是多体共血,比如蠕虫,之后我会细说

aiStyle为-1代表不使用原版AI,如果不写这一条,则会默认为0,aistyle为0时代表的是束缚状态的NPC,X轴速度会趋于0

music = :BOSS战的背景音乐,AI里面可以修改这个来切换BOSS音乐,所以换阶段可以换音乐了,这个要写自己的路径,然后音乐名无后缀,什么?如果要用原版音乐怎么办?

Music = MusicID.Boss1;

接下来是SetStaticDefaults

public override void SetStaticDefaults()
{
    DisplayName.SetDefault("114514");
    DisplayName.AddTranslation(7, "你是一个一个~");
    Main.npcFrameCount[NPC.type] = 3; 
    NPCDebuffImmunityData debuffData = new NPCDebuffImmunityData {
        SpecificallyImmuneTo = new int[] {
            BuffID.Poisoned,
        }
    };
}

DisplayName.SetDefault是npc在游戏内显示的名字

DisplayName.AddTranslation是给npc的名字加一个翻译,这里的7shi

Silence,wench!I do not want to see magic figures anymore,I just want to be code-concise.

我们使用 DisplayName.AddTranslation((int)GameCulture.CultureName.Chinese, "谢谢cheems");

有人问SetDefaultsSetStaticDefaults有什么区别,答案是SetDefaults是实例的,SetStaticDefaults是静态的

什么意思呢?举个例子,场上有两个boss,你如果在SetDefaults里设置一个变量,那么两个boss用的是不同的变量,在SetStaticDefaults里设置,那么两个boss用的是同一个变量

buffimmune[ID]:免疫BUFF。例如BUFFID.Poisoned,你可以这么写

NPCDebuffImmunityData debuffData = new NPCDebuffImmunityData {
    SpecificallyImmuneTo = new int[] {
        BuffID.Poisoned,
    }
};

npcFrameCount[NPC.type],这个就填你的boss有几帧,什么?不填可不可以?

此图片的alt属性为空;文件名为5C2A_P8ITR1ZCBD352AAR.jpg
裙裙语录第二弹

各种重写函数

首先我们来了解一下经典,专家和大师的npc增强

经典专家大师
伤害1倍2倍3倍
防御1倍1倍1倍
生命值1倍2倍3倍
弹幕伤害2倍4倍6倍
npc数据增强表

如果我们想自己调专家大师的数据,那我们可以使用这个重写函数

public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
{
    NPC.life = (int)(NPC.life * 0.5f);
}

但是这个只能改变专家模式下的数据,而大师模式则需要用另一种方法

public static int Life()
{
    if (Main.masterMode) return 114514 / 3;
    else if (Main.expertMode) return 114514 / 2;
    else return 114514;
}
public override void SetDefaults()
{
    NPC.lifeMax = Life();
}

这种方法可以更改所有模式的所有数据,我喜欢这一种,再来提一嘴,当大师模式时,Main.expertModeMain.masterMode都是true

另外,两个方法不能同时使用,如果有人因为这个出问题我当场噶了他

下一个,AI函数,这是游戏非暂停模式下每帧执行的函数,下面会细讲

public override void AI()
{
    //你想写什么都可以
}

好,来了一个重点,FindFrame

public override void FindFrame(int frameHeight)
{
    NPC.frame.Y = x * frameHeight;
}

只要用这段代码就可以切换到npc的第x帧辣!注意,这个x是从零开始算的,所以x=0就是第一帧,以此类推

NPC.frame.Y他是按像素算的,不要被坑了啊

HitEffect在BOSS被挨打时执行

public override void HitEffect(int hitDirection, double damage)
{
            
}

ModifyNPCLoot,在NPCLoot之前执行的函数,可以更改掉落

public override void ModifyNPCLoot(NPCLoot npcLoot)
{
            
}

OnHitPlayer:boss本身击中玩家时执行,仅限npc碰撞时产生

public override void OnHitPlayer(Player target, int damage, bool crit)
{
            
}

ModifyHitbyItem:boss被玩家的物品(真近战)击中前执行

public override void ModifyHitByItem(Player player, Item item, ref int damage, ref float knockback, ref bool crit)
{
            
}

OnHitbyItem:boss被玩家的物品(真近战)击中时执行

public override void OnHitByItem(Player player, Item item, int damage, float knockback, bool crit)
{
            
}

ModifyHitByProjectile:被玩家的弹幕命中前执行

public override void ModifyHitByProjectile(Projectile projectile, ref int damage, ref float knockback, ref bool crit, ref int hitDirection)
{
            
}

OnHitByProjectile:被玩家的弹幕命中时执行

public override void OnHitByProjectile(Projectile projectile, int damage, float knockback, bool crit)
{
    
}

OnKill:boss被干掉时执行,这个我用来写尸块,我们来解析一下

public override void OnKill()
{
    int Gore1 = Mod.Find<ModGore>("Gore1").Type;
    int Gore2 = Mod.Find<ModGore>("Gore2").Type;
    var entitySource = NPC.GetSource_Death();
    for (int i = 0; i < 4; i++)
    {
        Gore.NewGore(entitySource, NPC.position, new Vector2(Main.rand.Next(-6, 7), Main.rand.Next(-6, 7)), Gore1);
    }
    Gore.NewGore(entitySource, NPC.position, new Vector2(Main.rand.Next(-6, 7), Main.rand.Next(-6, 7)), Gore2);
    SoundEngine.PlaySound(SoundID.Roar, NPC.Center);
}

第一第二行,是定义两个尸块,尸块需要单独的图片

尸块图片

下一行是定义npc的死亡源,这个不用管

接下来就是生成4个gore1,一个gore2,播放一个吼叫音效

来看看效果

肥肠滴好啊!

啊哈哈哈,重点来喽!StrikeNPC函数

public override bool StrikeNPC(ref double damage, int defense, ref float knockback, int hitDirection, ref bool crit)
{
    damage = 114514;
    return true;
}

讲解一下,这个函数在npc挨打前执行,damage是造成的伤害,defense就是受击时的防御,knockback就是受到的击退,hitDirection是攻击的方向,1是右,-1是左,crit是是否暴击,如果return false的话则是不受伤,哦对了,damage为0仍然会让npc受1点伤,暴击2点

还有一个函数,PreDraw函数,这个函数在npc绘制前执行,特效拖尾都要写在里面,后面细讲,返回false可以干掉原版绘制

public override bool PreDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
{
    return true;
}

PostDraw函数,在npc绘制后执行

public override void PostDraw(SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
{
        
}

BossLoot,这个是boss的药水掉落函数,说是药水掉落,其实你填什么都可以

public override void BossLoot(ref string name, ref int potionType)
{
    potionType = ItemID.LovePotion;
    name = "下北泽";
}

这个name,就是boss被干掉时的名字

下面一个是CheckDead,在npc趋势时触发,返回false会导致npc死亡啥也不掉,连尸块都没有,经常用来制作尾杀

public override bool CheckDead()
{
    return false;
}

DrawHealthBar这个函数,控制Boss的血条绘制 ,scale是血条的大小,position是血条的位置,return false可以阻止原版血条的绘制

注意,这个血条是所有npc都有的那个绿色的,在npc下方的,不是屏幕下面那个boss血条啊喂!

public override bool? DrawHealthBar(byte hbPosition, ref float scale, ref Vector2 position)
{
        scale = 3f;
        position += new Vector2(0, -32);
        return true;
}

重点来辣!NPCLoot函数

public override void ModifyNPCLoot(NPCLoot npcLoot)
{
    LeadingConditionRule notExpertRule = new LeadingConditionRule(new Conditions.NotExpert());
    notExpertRule.OnSuccess(ItemDropRule.Common(ItemID.StoneBlock, 3, 5, 15));
    npcLoot.Add(notExpertRule);
    npcLoot.Add(ItemDropRule.BossBag(ItemID.StoneBlock));
    npcLoot.Add(ItemDropRule.MasterModeCommonDrop(ItemID.StoneBlock));
    npcLoot.Add(ItemDropRule.MasterModeDropOnAllPlayers(ItemID.StoneBlock));
}

好,我来细细地讲解一下,第一行是创建一个掉落规则,在非专家大师模式时掉落,第二行是向这个掉落规则里放一个掉落,1/3概率掉落,一次掉落5~15个石头,第三行是把这个掉落规则放入总掉落里,第四行是向总掉落里放一个石头,这个石头以宝藏袋的标准掉落出来(只在专家大师掉落),第五行,在大师模式下掉落一个石头,第六行,在大师模式下,给所有玩家,都掉落一个石头,人人有份,每个人在自己的客户端都有一个

如果想要写出拥有更多花样的掉落,以及宝藏袋本身,请参考这篇教程

小作业

写出你的第一个Boss,要求:

Boss血条缩小,显示在boss头上,在大师模式有1/10的概率掉落0-11个石头,可以反弹所有攻击

很简单吧,我走了,我不打扰()

标签:

《Boss的创建与基础重写函数》有1个想法

发表回复