跳至正文

粘滞型弹幕

还记得原版的破晓之光吗?

有请受害者

今天咱们就来试着制作一个这种可以粘在敌人身上的弹幕。

老规矩,创建一个类继承 ModProjectile,写入基础属性。记得准备贴图哦~

送你们一个狙击步枪的贴图hhhhhh

public override void SetDefaults()
{
    Projectile.width = 16;
    Projectile.height = 16;
    Projectile.friendly = true;
    Projectile.tileCollide = true;
    Projectile.penetrate = 2;//穿透多个,不然刚打到就寄了,这样就粘不到嘞
    Projectile.ignoreWater = true;
    Projectile.timeLeft = 600:
    Projectile.DamageType = DamageClass.Ranged;
    //属性可以自己改
}

接下来进入弹幕AI部分,为了清晰的表示逻辑,这里用弹幕的 ai[0] 来识别弹幕是否处于粘在NPC身上的状态,用ai[1]来记录被命中的 NPC.whoAmI

public bool Sticking
{
    get { return Projectile.ai[0] != 0; }// 因为默认状态下ai[0]是 = 0,所以这里用 != 0进行判定
    set { Projectile.ai[0] = value ? 1 : 0; }// 三元运算符:当表达式值为true,返回前者,反之为后者
}
public int TargetWho
{
    get { return (int)Projectile.ai[1]; }
    set { Projectile.ai[1] = value; }
}
public override void AI()
{
    if (Sticking)// 当弹幕粘在NPC时执行
    {
        // 获取粘滞的NPC
        NPC target = Main.npc[TargetWho];

        // 如果目标NPC死了弹幕也一起死亡
        if (!target.active)
        {
            Projectile.Kill();
            return;// 结束函数
        }

        // 把目标的速度给弹幕,让弹幕跟着粘滞目标
        // 这就是粘住了(迫真
        Projectile.velocity = target.velocity;

        //然后你就可以在此对NPC造成伤害,也可以做一些其他效果比如生成粒子,给NPC上buff

        Projectile.ai[2]++;// 作为攻击计时器
        // 此处即为每10帧对NPC造成一次伤害,数值为5点
        if (Projectile.ai[2] >= 10)
        {
            target.SimpleStrikeNPC(5, 0);
            Projectile.ai[2] = 0;
        }
    }
    else// 弹幕正常行动时执行
    {
        // 这里可以不写任何东西,反正弹幕被射出来就会按着给的速度自己跑

        // 不过假如你想模拟重力,你可以这么写
        // 弹幕Y轴速度每帧增加,它就是个抛物线的感觉了
        Projectile.velocity.Y += 0.1f;
        // 让弹幕的角度等于速度的朝向,用于视觉(绘制)
        Projectile.rotation = Projectile.velocity.ToRotation();
    }
}

接下来,我们要让弹幕执行“粘上NPC”这个行为。使用之前介绍过的命中后效果那个函数:

public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
{
    // 打到某个目标之后
    // 把粘滞设为true,这样AI就会从正常行动切换到粘滞状态
    Sticking = true;
    // 把被命中目标的身份记录下来
    TargetWho = target.whoAmI;
    // 并重置弹幕的存活时间,60为一秒,要多久看你们
    Projectile.timeLeft = 360;
}

但此时还有一个问题,我们要保证弹幕粘上NPC之后不能再伤害NPC,否则会导致弹幕的 penetrate(穿透数)减少,导致弹幕死亡(这玩意 = 0 就会寄)。所以现在要用这个:

public override bool? CanDamage()
{
    // 不在粘滞状态才能造成伤害
    // 这和AI里那个SimpleStrikeNPC并不会冲突
    return !Sticking;
}

最后是弹幕的绘制,这个在这里不做介绍,想了解详细请查阅绘制教程。

public override bool PreDraw(ref Color lightColor)
{
    Texture2D tex = TextureAssets.Projectile[Type].Value;
    Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, lightColor * Projectile.Opacity,
        Projectile.rotation, tex.Size() / 2f, Projectile.scale,
        (Math.Abs(Projectile.rotation) < Math.PI / 2f) ? 0 : SpriteEffects.FlipVertically, 0f);
    return false;
}
再次有请受害者

可以看到狙击步枪扎在石头人身上了(笑死)

至于只打了一滴血自然是因为伤害太低被防御抵了。不过它的图层似乎在石巨人之上,倒回文章开头看看破晓之光,你应该能发现它的图层在石巨人下边。

这个问题也是很好解决的,首先在命中NPC那里添加 Projectile.hide = true; ,隐藏原本的绘制,接着把绘制添加到NPC图层的后面:

public override void DrawBehind(int index, List<int> behindNPCsAndTiles, List<int> behindNPCs, List<int> behindProjectiles, List<int> overPlayers, List<int> overWiresUI)
{
    behindNPCs.Add(index);
}
受害者三顾茅庐

哈,这下对了。粘滞弹幕的基本点都在这啦,(其实这篇是个阉割版,细节并不全)

其它的花里胡哨玩意儿就要你们自己去探索咯。这里附上Exmod的粘滞弹幕

怎么发射这个弹幕不需要再教了吧?

啥?要?自己看武器篇去(恼

发表回复