其实这就是在之前的基础物品上多加亿些属性和亿些重写函数而已~
亿点新属性
之前,我们设置过了物品的宽高、价值和稀有度,但这个物品并不能使用。
要让物品可以使用,我们需要在 SetDefaults()
中写这些东西:
// 使用速度和使用动画持续时间! // 这个数值越低越快,因为TR游戏速度每秒是60帧,这里的20就是 // 20.0 / 60.0 = 0.333 秒挥动一次!也就是一秒三次 Item.useTime = 20; Item.useAnimation = 20; // 一般来说我们要把这两个值设成一样,但也有例外的时候 // 比如下边的工具,让useTime = 5,而useAnimation还是20,这这么做就会让这个物品点击一次使用20 / 5 = 4次!但是只有一次使用动画() // 使用类型,这个值决定了武器使用时到底是按什么样的动画播放 // 0 或 None 代表......字面意思,就是啥都没有!你写了之后甚至无法使用! // 1 或 Swing 代表挥动,也就是剑类武器! // 2 或 EatFood 代表像食物一样,拥有物品,手持,放在盘子上三帧的贴图,具体可见exmod里头的🥧(派)https://github.com/Cyrillya/Example-Mod-Zh-Project/blob/master/Content/Items/Consumables/ExampleFoodItem.cs // 3 或 Thrust 代表像1.3的同志短剑一样刺x 出去(也就是朝左或右刺出)(如果你想要写全方位刺出的剑,那你还是得看exmod) // 4 或 HoldUp 唔,这个一般不是用在武器上的,想象一下生命水晶使用的时候的动作 // 5 或 Shoot 手持,枪、弓、法杖类武器的动作,用途最广 // 6 或 DrinkLong 代表直接猛喝,感兴趣可以自己看看,挺好玩的( // 7 或 DrinkOld 代表1.3的喝药水动作 // 8 或 GolfPlay 代表高尔夫球杆的动作 // 9 或 DrinkLiquid 代表1.4的喝药水动作,相比1.3的来说,这个动作的手臂更加流畅,持握位置会在瓶口 // 10 或 HiddenAnimation 代表使用时无动画 // 11 或 MowTheLawn 代表割草机的动作,神奇,这玩意还有单独的动作 // 12 或 Guitar 代表常春藤、雨之歌等物品的动作,对这玩意也是单独的动作(爱抚剑ing // 13 或 Rapier 代表标尺、星光等武器的动作 // 14 或 RaiseLamp 代表夜光的动作,好吧这也单独写一个动作的吗?话说这玩意翻译过来叫吊灯......夜光大吊灯(bushi // Item.useStyle = 1; 请不要写魔法值 Item.useStyle = ItemUseStyleID.Swing; //需要注意一点,泰拉中的挥动型物品的贴图基本都是朝着右上角倾斜的,如果你的贴图不是如此,那可能会导致奇怪的视觉问题。 // 决定了这个武器鼠标按住不放能不能自动使用, true代表可以, false代表不行 // (鼠标别按废了,这条属性你要是不写那就是默认的false Item.autoReuse = true; // 决定了你在使用物品的时候可否转身,不写就是false Item.useTurn = true; // 这是使用时的音效,不写就是没有 // 这是一个挥动音效 Item.useSound = SoundID.Item1;
wiki上的SoundID我是加载不出来,,给你们另一个链接SoundID(部分)。
写了这三属性物品就能使用了!但是没有任何效果,诶就是玩儿~
武器
现在咱们要让这个物品可以打怪辣!
还是在 SetDefaults()
中:
// 使用时的体积倍率,不写就是默认1倍,即不变大也不变小 Item.scale = 1f; // 伤害!想都不要想,后面这个值随便改吧,但是不要超过2147483647 // 不然…… 你试试就知道了 Item.damage = 50; // 决定了这个武器的伤害类型 // Default 代表无属性(也就是不吃任何加成) // Generic 代表全属性(也就是全部加成都吃)所谓1.3的allDamage就是它了 // MagicSummonHybrid 代表什么我不知道,但是可以同时吃到魔法和召唤加成 // MeleeNoSpeed 代表近战,但是不吃攻速加成 // Melee 代表近战 // Ranged 代表远程 // Magic 代表马猴烧酒,不,魔法 // Summon 代表召唤 // SummonMeleeSpeed 代表额......看看鞭子吧,可以吃到近战和召唤加成 // Throwing 代表投掷(没错虽然1.4没了投掷武器,全给远程了,但是这个伤害类型还在!) Item.DamageType = DamageClass.Melee; // 这里用的是一把剑所以是Melee,近战伤害 // 击退力,写0~20f之间的数值,越大击退力越强 Item.knockBack = 6f; // 暴击率,角色自带4% Item.crit = 20; // 20%暴击率,游戏内显示会是20 + 4 = 24%暴击率 // 这是控制贴图是否造成伤害,默认是造成伤害 Item.noMelee = false; // 这是一把剑所以贴图是造成伤害的 // 但如果你是枪类的远程武器,你不希望拿着枪敲人的话就要把它设置为true // 这是控制使用时是否显示贴图,默认是有的 Item.noUseGraphic = false; // 吸血飞刀这个就是true,它使用时不显示贴图 // 假如这是一个法杖类型,不写默认false,这里就用到物品Type了 Item.staff[Type] = false; // enn,这是把剑 // 一般来说,法杖类武器会使用Shoot的那个使用方式,但它的贴图不像枪一样是水平朝向而是向右上倾斜 // 让它变成true就会导致使用时贴图再转45度,变成法杖尖端朝着射击方向 // 这是使用消耗的魔力值,不写就不消耗 Item.mana = 0;
你也可以使用 ModContent.GetInstance<你的伤害类>()
来使用你自定义的伤害类型,这里是一篇如何制作自定义伤害类的示例。
有了物品的使用时间,使用动画,使用方式,现在又加上了伤害类型和伤害,那么这个物品就可以创人了!现在,它是一个挥动起来的效果,并且,按住可以连续使用。
我们还可以给这个使用效果加一些特效。
给武器加特效(近战限定ver)
让我们找到这个叫 MeleeEffect
的重写函数:
这个函数会在武器使用时被触发。可以看到它给了两个参数,一个是player,这是正拿着这个物品的玩家实例,另一个是hitbox,这是这个物品使用的时候的碰撞箱。那么让我们给这把武器加一些使用时的粒子吧。
来看看效果:
看起来有点多而且乱七八糟,不过我们可以改改粒子的属性和生成间隔。
Main.GameUpdateCount
是游戏更新计数器,从你进入世界开始每帧+1,即使你用旅途模式暂停了游戏时间 Main.time
也不会受影响,是一个天然计时器。有关计时器的概念之后会提到,是运用很广泛的玩意儿~
现在它就变成了每三帧才生成一次(之前是每帧都生成),并且没有初速度(之前会有一个随机的初速度),还不受到重力影响。再来看看:
你们可以自己试试调整参数,来达到想要的效果。
不过以上只是近战,如果你希望它射出一些东西?
让武器发射弹幕
那就再加些属性!一样是在 SetDefaults()
中:
Item.shoot = ProjectileID.TerraBeam; // 物品使用时发射的弹幕类型,这里是泰拉刃的剑气 Item.shootSpeed = 6f; // 物品发射弹幕的速度,单位:像素/帧,一秒 = 60帧
现在,这个物品会在使用的时候朝着人物-鼠标的方向以每帧6个像素的速度射出泰拉刃的剑气。使用 ModContent.ProjectileType<你的弹幕类>()
来获取你的弹幕id,或是用ProjectileID.xxx来使用原版弹幕。
Item.shoot = ModContent.ProjectileType<你的弹幕类>(); // 此时一般会报错提示找不到这个类,使用Alt+Enter修复它!
这里要介绍一个新的重写函数——
Shoot
先来看看提供的参数。player,是正使用这个物品的玩家实例;source,这是生成源信息,下边会说;position,弹幕的发射位置,这里提供的position是玩家的中心 player.Center
;velocity,发射速度,此处是从玩家中心朝着使用时鼠标位置的大小为 Item.shootSpeed
的向量;type,发射的 弹幕/射弹 的id;damage,即是之前的物品伤害 Item.damage
;最后一个就是之前写过的击退力了。
这玩意的作用可大了。可以看到它的返回类型是 bool
。当你 return true
的时候,使用这个物品时,它就会使用你之前设定过的 Item.shoot
和 Item.shootSpeed
发射一个弹幕。但是当你 return false
时,这个自带的发射便会被阻止。
这样你就可以发射很多个弹幕:
public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, Vector2 position, Vector2 velocity, int type, int damage, float knockback) { // 保持发射原有的弹幕,并且朝着反方向额外发射一个霜冻箭矢! Projectile p = Projectile.NewProjectileDirect(source, position, -velocity, ProjectileID.FrostburnArrow, damage, knockback, player.whoAmI); return true; }
看起来很cool,你们可以利用这个函数来实现很多奇奇怪怪的效果。
顺便介绍一下这个发射弹幕的方法:
发射弹幕
第一个参数 spawnSource,就是之前提过的生成源了,它可以用来做很多花式操作,在之后的弹幕篇咱们再细嗦。
有关生成源的使用,请点击查看。接下来的 position,velocity 分别是射弹的生成位置和初速度,type 就是射弹的类型啦,damage 伤害,knockBack 击退。
然后这个owner很重要,它代表弹幕的主人,一定要进行一个正确的写。上文中,我们使用了 player.WhoAmI
来获取弹幕主人在 Main.player[]
(玩家数组)中的索引并填入。这个参数没有正确传入的话,这个弹幕可能没法打怪(即使打到了也不会执行伤害判定)或者刚发射出来就被系统干掉。不过由于144版本的默认参数它会自动获取当前端玩家,所以不是特别情况下可以不填。但我还是推荐你们手动填上。
再后边的 ai012
是弹幕的 ai数组
,也放在弹幕篇再讲。
消耗弹药的武器
假如你想让你的武器在使用时需要消耗弹药,那么:
// 让这个武器在使用时需要消耗被标记为箭矢的物品 // 同时这个物品在快捷栏中时会自动显示背包内有多少弹药 Item.useAmmo = AmmoID.Arrow;
注意,设置了这个属性,你写过的 Item.shoot
就会被弹药代表的弹幕给覆盖掉。
但是请不要只写 Item.useAmmo
不写 Item.shoot
,那会射不出来的。
要是你还想让这个武器跟巨兽鲨那样有一定概率不消耗弹药,那就用这个叫 CanConsumeAmmo
的重写函数:
public override bool CanConsumeAmmo(Item ammo, Player player) { return !Main.rand.NextBool(33, 100); }
当这个函数的返回值是 true
的时候,弹药就会消耗。
Main.rand
是TR自带的一个随机类。它有很多的随机数生成方法,返回类型也不同。这里使用的 Main.rand.NextBool(33, 100)
的效果是他有33/100的概率返回 true
,那么效果就是有33%的概率不消耗弹药了。(注意代码中有一个 !
,表示对 bool
取反)
这个方法提供了将被使用的弹药的实例,和正在使用这个武器的玩家的实例,我想你可以用这些来做点奇奇怪怪的判定。
你还可以用这个重写函数来让弹药被消耗掉的时候发生一些事情:
public override void OnConsumeAmmo(Item ammo, Player player) { // 键入你的想法 }
下面的函数可以让你的武器可以使用更多种的弹药:
public override bool? CanChooseAmmo(Item ammo, Player player) { if (ammo.type == ItemID.SandBlock) { return true; // 让沙子也可以被这把武器作为弹药 // 注意!此时射出的是这个ammo的shoot,如果这个ammo没有shoot就会射出此武器的shoot // 比如这里,沙子是没有shoot的,你射出的就是泰拉剑气而不是之前AmmoID.Arrow的箭矢了 } return null; // 默认返回null使用原本指定的弹药 // return false你就射不出来了 }
下面这个是上边的被动版本:
public override bool? CanBeChosenAsAmmo(Item weapon, Player player) { // 这次是给了武器实例 // 使用if (weapon.type == xxx) return true;来让这个物品能被特定武器作为弹药使用 return base.CanBeChosenAsAmmo(weapon, player); }
什么,你还想写什么效果?
武器案例参考
工具
再来说说工具,工具也就是在一把剑的基础上再加几个属性,让它们可以破坏物块,或是砍树锤墙。
还是那个熟悉的函数 SetDefaults
:
public override void SetDefaults() { //宽高啊,伤害啊,伤害类型什么的就自己写吧 // 加快使用 Item.useAnimation = 20; Item.useTime = 5; // 新属性 Item.pick = 100; // 100%的镐力! Item.axe = 20; // 这个比较特殊,20 * 5 = 100%的斧力! //Item.hammer = 100; // 100%的锤力! }
注意这个是用时间和使用动画时间,因为TR的机制是使用动画结束才算一次完整的使用,也就是说 Item.useAnimation
决定了你是不是在使用这个物品,而 Item.useTime
决定了多久触发一次效果,比如这里就是20/5=4次,你使用一次就能对着物块造成四次伤害
唔,这里还有一个属性: Item.reuseDelay
,不写的话就是默认为0,它决定了你完成一次触发后还要多久才能再次触发。
有关更多工具,比如鱼竿,捕虫网之类的请点此查看。
警告:镐力和锤力冲突,请不要同时写(除非你把他们拆开放在左右键)(或者你想一边破坏物块一边把它们敲成半砖顺便还拆了个背景墙)。同时工具不可以拥有弹幕,即Item.shoot需要保持默认值0。
更多有关使用的重写函数介绍
修改发射
噢,看看这个玩意儿:
它把木箭变成烈焰蝙蝠了,这是怎么做的呢?
// 这个重写函数在你使用了武器,这个武器要射出弹幕了!诶但是还没射出来,现在你可以修改它的发射参数 public override void ModifyShootStats(Player player, ref Vector2 position, ref Vector2 velocity, ref int type, ref int damage, ref float knockback) { // 可以看到这里面的参数有些带上了“ref”,这表明你在这里修改过的值会被传回去,影响到之后发射弹幕的效果。 // 当当前射弹类型是木箭的时候,把它改成别的 if(type == ProjectileID.WoodenArrowFriendly) { type = ProjectileID.Hellwing; // 这就是地狱之翼弓的弹幕 } // 当然你也可以直接让射出的弹幕转成另一种弹幕,而不是只有木箭 //type = ProjectileID.Hellwing; // 都会转化成地狱之翼弓弹幕 //type = Main.rand.Next(Main.maxProjectileTypes); // 也可以让它射出随机的弹幕!小心别把自己创死 }
命中效果
注意,这里的效果只作用于物品本身,并不会作用到由该物品射出的射弹上。
player是造成本次攻击的玩家实例,target是被命中的NPC实例。
// 这个效果发生在你已经命中了目标,并且已经结算了伤害的那一刻 public override void OnHitNPC(Player player, NPC target, NPC.HitInfo hit, int damageDone) { // 给怪物加上灵液buff,持续10秒,后面的参数别管 target.AddBuff(BuffID.Ichor, 600); // 至于如何制作自己的Buff,之后会讲 // 可以在命中的时候发射一个弹幕,或者给自己回血等等 // 如果造成的伤害大于10或者本次伤害是暴击 if (damageDone > 10 || hit.Crit) { // player.statLife += 10; // 回复10点生命,但是这个不会跳字 // player.HealEffect(10); // 玩家头上跳出绿色的10,就像使用生命水晶或是生命果那样 player.Heal(10); // 这种写法会同时回血+跳字,如无特殊需求建议使用这个 } }
握持偏移
有些武器使用时是这样的,看起来没啥问题,其实手握的地方是枪托。而这显然不符合我们注重细节的要求,那么如何修改武器的持握位置呢?
public override Vector2? HoldoutOffset() { return base.HoldoutOffset(); }
这个函数允许你设置useStyle
为 ItemUseStyleID.Shoot
且不是法杖的物品的使用贴图偏移量,如果函数返回null
就是使用原版的偏移量,上图的武器我用了这个偏移量:
public override Vector2? HoldoutOffset() { // 横坐标往左移动10像素,纵坐标向上移动5像素 return new Vector2(-10, -5); }
于是效果是不是好多了?
除此之外,这两个函数也能修改物品的握持位置:
public override Vector2? HoldoutOrigin() { return base.HoldoutOrigin(); } public override void HoldStyle(Player player) { base.HoldStyle(player); }
值得一提的是 HoldoutOrigin
只对 useStyle
为 ItemUseStyleID.Shoot
且是法杖的物品有用,能修改物品贴图旋转中心的偏移量。HoldStyle
是物品在使用中(握在手上)会发生的事情,可以用来修改物品贴图的位置和旋转。
这个函数也十分有意思,能修改玩家在用这个武器(被选中)的时候玩家的动作。返回true如果你修改了玩家的动画。
public override bool HoldItemFrame(Player player) { return base.HoldItemFrame(player); }
我们可以这么写:
public override bool HoldItemFrame(Player player) { // 选中武器的时候设置为第3帧 player.bodyFrame.Y = player.bodyFrame.Height * 2; return true; }
这样只要切到这个武器玩家就会举起手来(笑)
调整魔力消耗
这个重写函数就比较神秘,呃啊。
public override void ModifyManaCost(Player player, ref float reduce, ref float mult) { // 嗯,这也是ref,但我不明白它为什么要给两个调整参数,总之最后的效果是mana * reduce * mult = 本次实际花费的mana // 想要让魔力消耗减少20%,就 reduce -= 0.2f; // 增加30%,就 mult *= 1.3f; // 加算和乘算的区别在哪呢? }
可否使用
public override bool CanUseItem(Player player) { // return true; 可以使用 // return false; 不能使用 // 假如是夜晚就不能用 if(!Main.dayTime) { return false; } // 玩家在海洋就不能用 if (player.ZoneBeach) { return false; } return true; }
这个函数的运用很广泛。
练习
基础
- 如何实现玩家每次使用武器时,武器大小会随机变化?答案
Item.scale = Main.rand.NextFloat(1.00f, 114.00f);// 哈哈这个随机大小的范围可能有一点大 // 具体放哪自己看着办吧~
- 如何实现使用武器后,会朝以发射角度为基准,发射五个平均分的弹幕?答案
// 让我们使用for和三角函数来达成这个效果吧!(tr使用的是弧度制,且一圈是-1~1Pi) for (float r = -MathHelper.Pi; r < MathHelper.Pi; r += MathHelper.TwoPi / 5f)// 循环五次,让r分别等于相当于角度的0、72、144、216、288五个度数 { float r2 = r + velocity.ToRotation(); // 加上发射向量所代表的角度 Vector2 v = new Vector2((float)Math.Cos(r2), (float)Math.Sin(r2)) * 10f;// 使用三角函数将其转换成向量 Projectile.NewProjectile(source, position, v, type, damage, knockback, player.whoAmI);// 发射! } // 写在shoot重写函数里即可
进阶
- 如何实现玩家在使用物品时,物品会每帧变换各种属性?(如大小、镐力/斧力/锤力、伤害等)
劝退
1.如何实现一个可以当作武器(可同时造成近战/远程/魔法/召唤伤害,并附带50%敌怪最大生命值无视护甲的伤害)/工具(斧头/镐子/锤子/钓鱼竿)/弹药/摸彩袋/药水/饰品/装甲/时装/物块。该物品的稀有度是一个名为“无意识”的稀有度(稀有度颜色会从浅绿到深绿不断变化)。将光标放到该物品上时,该物品描述会不断变化,随机复制游戏内任意一个有多行描述的物品当作本物品的描述。伤害根据游戏内总物品数量决定,并乘以(白色稀有度物品数量-蓝色稀有度物品数量)+红色稀有度物品数量 * 黄色稀有度物品数量。使用时间则是游戏内总npc数量。发射的弹幕会随机挑选玩家身上三个能发射弹幕物品的弹幕,发射方式则是随机挑选原版一个会发射弹幕敌怪的发射方式(包括boss),放置的物块只会是游戏内正常游玩无法放置的物块,右键打开后会开出来游戏内全部摸彩袋,喝下后会随机给予2~7个正面buff和4~12个负面buff,持续时间无限且通过此种方式给予的buff永远无法削除(除非删除玩家存档),当作弹药时会每分钟变换为一种随机的游戏内弹药,饰品效果是原版全部饰品效果之和,盔甲效果是让玩家当场变成幽灵并让天上下这个物品的雨,时装会随机挑选一个原版时装当作自己的时装(重载mod时会切换一个新的时装)