在泰拉瑞亚,有武器是不够的,肯定还得有装备嘛。接下来的两章,我们会集中注意力在装备以及玩家属性上,顺便探索更多TR的机制。
创建源码文件
首先我们要准备一个贴图文件
比如这个奇怪的东西,如果没有贴图也可以去下载原版贴图改色:
接下来打开VS,把这个贴图拖进TemplateMod2\Items\Accessories
里面。
然后在Accessories这个文件夹上右键->添加->新建项,选择类,记得文件名要设置的跟贴图名字一样哦
然后你就会看到这个文件已经被添加到Accessories文件夹下了。
但是,因为这是一个新建的源码文件,所以它并不包含之前我们所说的那些代码和注释。而且由于命名空间的缺失,所以你可能会发现复制过来的代码会被VS画上很多横线QAQ。
不过没关系,VS的自动纠错功能是很强大的。
首先,我们不需要改命名空间,所以被命名空间包含的代码才是我们想要的,也就是class PurpleStone
首先,我们给PurpleStone
继承上ModItem
,告诉TML这是一个Mod物品
class PurpleStone : ModItem { }
如果你不是来拆我台的话,应该会看到ModItem
被VS画上了红线。
这个时候不要慌,看到那个小灯泡没有,点一下它,然后选择这个选项
这时候你会看到上面多出了一行
using Terraria.ModLoader;
注意:如果引用出现多个,请选择跟Terraria和XNA有关的那个,且不要带奇奇怪怪的前缀。比如
如果你不确定选择哪个才是对的,可以参考TemplateMod2的代码,仔细观察using语句。
然后你的红线也消失了,这个using语句的作用就是引用TML的ModLoader库。为什么要这么做呢,因为如果你只有ModItem
这个名字,编译器不知道从哪去找ModItem
,如果有多个ModItem
,它怎么知道你想要的是哪个呢。这时候如果你using了ModLoader这个命名空间,编译器就会去TML的ModLoader命名空间下寻找ModItem
。而这个ModItem
就是我们想要的那个。
接下来我们就可以写重写函数给这个物品加钩子了,我们需要的函数有SetStaticDefaults
,SetDefaults
和AddRecipes
。
具体添加方式可以是这样
添加完毕后代码应该是这样的
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Terraria.ModLoader; namespace TemplateMod2.Items.Accessories { public class PurpleStone : ModItem { // 物品名字设置 public override void SetStaticDefaults() { base.SetStaticDefaults(); } // 物品基本信息设置 public override void SetDefaults() { base.SetDefaults(); } // 物品合成方式设置 public override void AddRecipes() { base.AddRecipes(); } } }
饰品属性
饰品的属性其实很简单,不过多了这一句而已
// 告诉泰拉瑞亚,这个物品是个饰品 item.accessory = true;
有了它,这个物品就可以被装备在饰品栏了。假如你想做一个防御型的饰品,可以在SetDefaults里这么设置属性
// 跟以前没啥区别 item.width = 22; item.height = 22; // 重点在这里,这个属性设为true才能带在身上 item.accessory = true; // 物品的面板防御数值,装备了以后就会增加 item.defense = 16; item.rare = 8; item.value = Item.sellPrice(0, 5, 0, 0); // 这个属性代表这是专家模式专有物品,稀有度颜色会是彩虹的! item.expert = true;
进入游戏应该能看到这样的效果
但是,这个饰品的属性也太单调了吧,有没有办法加一些高级的属性呢?当然有,我们接下来就要介绍一个新的重写函数UpdateAccessory
public override void UpdateAccessory(Player player, bool hideVisual) { base.UpdateAccessory(player, hideVisual); }
这个重写函数(钩子),勾住了泰拉瑞亚原版更新戴在玩家身上的物品的过程,也是最适合添加饰品属性的函数。我们首先见到了一个新的东西Player player
,顾名思义,它代表着戴着这个饰品的玩家,那么bool hideVisual
是什么呢?
如果这个物品被设为不可见,那么hideVisual
就会是true
,否则就是false
。那么接下来我们看看如何让饰品发挥作用吧
UpdateAccessory
函数是每帧都会执行的,因此一秒会执行60次哦。
public override void UpdateAccessory(Player player, bool hideVisual) { // 让玩家的生命值上限增加100 player.statLifeMax2 += 100; // 让玩家魔法值上限增加100 player.statManaMax2 += 100; }
玩家有很多属性,教程里面没办法一一讲解,但是我们可以根据它的名字大概猜出用途(所以英语一定要好哦)。我本来想创建一个全属性以及作用表,但是有些属性极其难用(甚至需要配合很多其他内容),所以为了不误导大家,还是算了。
但是玩家的一些常用属性还是应该知道的,比如生命值属性,伤害属性,机动性,以及原版饰品一些奇怪的功能,所以我还是创建了一个简化表
名字 | 类型 | 描述 |
---|---|---|
statLifeMax | int | 玩家生命上限的基准,如果你不知道这是什么意思,请使用statLifeMax2。生命水晶会提升这个值而不是statLifeMax2 |
statLifeMax2 | int | 当前生命值上限,这个值是个临时值。计算方法为statLifeMax+各种乱七八糟的增幅,所以饰品增幅一定要写进这个属性 |
statDefense | int | 玩家当前防御值 |
statManaMax | int | 与statLifeMax差不多,只不过这个是法力值上限 |
statManaMax2 | int | statLifeMax2的法力值版本 |
meleeDamage,rangedDamage, magicDamage,minionDamage等 |
float | 玩家的各个属性伤害增幅,注意这些伤害增幅在原版是按照百分比增幅的,比如+0.05就是加5%伤害 |
meleeCrit,rangedCrit,magicCrit等 | int | 各个属性暴击几率增幅,注意这里就是整数增幅了+5就是加5%暴击率 |
noKnockback | bool | 如果为true玩家就不会被击退 |
noFallDmg | bool | 如果为true玩家就不会摔死 |
maxRunSpeed | float | 玩家最快能跑多快,改了以后会有鞋子的快跑效果哦 |
runAcceleration | float | 玩家加速到最快速度的加速度值 |
runSlowdown | float | 玩家停止移动时的减速度 |
moveSpeed | float | 玩家的移动速度,最多能设为1.6 |
meleeSpeed | float | 玩家的近战攻击速度,注意这里也是按照+0.05等于+5%攻击速度这这种方式计算的,而不是按照挥动一次的帧数 |
lifeRegen | int | 玩家在两秒内自然恢复的血量,+2就是多回复两点生命值 |
lifeRegenTime | int | 这个值也是增加生命恢复的,但是不是数值上,而是开始生命回复的速率,加的越多就越快开始生命回复 |
manaRegen | int | lifeRegen同理 |
manaCost | float | 玩家魔法消耗的百分比,-0.05代表减少5%总体魔法消耗 |
maxMinions | int | 玩家的最大召唤栏 |
按照这个表自定义一些饰品属性吧,具体的练习会在本章结束时给出。
翅膀制作
翅膀的图片文件我已经为你们准备好了,就在TemplateMod2\Items\Accessories
这个目录下。
你可能注意到了,ExampleWings
的贴图有两个,一个是普通的,一个是带_Wings
后缀的。那么第一个贴图就是物品贴图,而第二个贴图就是翅膀的帧图。(??不要惊讶,TR里面的动画就是要用到帧图的
我们先按照上面所说的创建好翅膀的源码文件。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Terraria; using Terraria.Localization; using Terraria.ModLoader; namespace TemplateMod2.Items.Accessories { [AutoloadEquip(EquipType.Wings)] public class ExampleWings : ModItem { public override void SetStaticDefaults() { base.SetStaticDefaults(); } public override void SetDefaults() { base.SetDefaults(); } public override void UpdateAccessory(Player player, bool hideVisual) { base.UpdateAccessory(player, hideVisual); } public override void AddRecipes() { base.AddRecipes(); } } }
诶,好像有个东西不太对,[AutoloadEquip(EquipType.Wings)]
这是啥啊。这个其实是一个C#里面叫做Attribute的东西,我们可以理解为给这个类打上一个标记,这样TML读到这个类的时候就会知道这是个翅膀装备。注意到我们之前的哪个帧图贴图了吗,为什么它要有一个后缀_Wings
,就是因为打了Wings标记的类需要一个Wings帧图,而且这个帧图名字必须匹配且必须有正好4帧。
SetDefaults
和之前的饰品没有区别
item.width = 22; item.height = 22; item.accessory = true; item.defense = 2; item.rare = 8; item.value = Item.sellPrice(0, 5, 0, 0); item.expert = true;
但是UpdateAccessory
这里我们要用到一个新的玩家属性
public override void UpdateAccessory(Player player, bool hideVisual) { // 翅膀的最长持续时间 player.wingTimeMax = 180; }
但是我感觉180并不是帧数,因为原版日耀翅膀的设置也是180,但是很明显爬升时间长于3秒,因为每个阶段的wingTime
消耗是不同的,所以以这个为基准来调整吧。
如果想让翅膀无限飞行,可以这么写
public override void UpdateAccessory(Player player, bool hideVisual) { player.wingTimeMax = 180; // 让翅膀的wingTime在每一帧都是一个固定的值 player.wingTime = player.wingTimeMax; }
这样player.wingTime
不会降到0那么就可以一直飞行了。
接下来我们看看翅膀的飞行参数控制
// 控制翅膀垂直飞行的参数 public override void VerticalWingSpeeds(Player player, ref float ascentWhenFalling, ref float ascentWhenRising, ref float maxCanAscendMultiplier, ref float maxAscentMultiplier, ref float constantAscend) { // 代码写在这 } // 控制翅膀水平飞行的参数 public override void HorizontalWingSpeeds(Player player, ref float speed, ref float acceleration) { // 代码写在这 }
这两个钩子的参数比较多,而且有些参数带有ref
,你只需要知道这些参数你可以直接设置就行了。先看VerticalWingSpeeds
这个函数,Player就不说了
ascentWhenFalling
这个属性是控制玩家在下落的时候开启翅膀的爬升率,如果设为0那么下落的时候就需要比较长的时间才能 上去。
ascentWhenRising
玩家切换到上升状态的时候开启翅膀的爬升率
maxAscentMultiplier
是玩家可以到达的最大爬升率
maxCanAscendMultiplier
暂时不知道有什么用
constantAscend
是正常飞行时翅膀的爬升率
然后就是HorizontalWingSpeeds
这个函数,speed
就是你一直按着方向键能到多快,acceleration
就是加速度啦。
至此,翅膀的基本属性就介绍完成了,如果你觉得翅膀这个飞行方式还是太low,那么我这里有个魔法。
把这段代码复制到UpdateAccessory
里面,然后告诉我进入游戏后会发生什么。
if (!player.controlJump && !player.controlDown) { player.gravDir = 0f; player.velocity.Y = 0; player.gravity = 0; player.noFallDmg = true; } if (player.controlDown) { player.gravity = Player.defaultGravity; player.gravDir = 1; player.noFallDmg = true; }
所以Player的属性真的是很多很奇妙呢。注意这个if
语句,我们以后会讲到它,具体来说就是
if (<条件>){ // 如果符合条件执行的代码 } else { // 不符合条件执行的代码 } // 其他代码
练习
基础
- 如何让某个饰品增加玩家的所有伤害和暴击20%答案
// 你以为我会这么写吗 /* player.meleeDamage += 0.2f; player.rangedDamage += 0.2f; player.magicDamage += 0.2f; player.minionDamage += 0.2f; player.thrownDamage += 0.2f; */ // 其实我是这么写的QAQ player.allDamage += 0.2f; player.magicCrit += 20; player.meleeCrit += 20; player.rangedCrit += 20; player.thrownCrit += 20;
- 做一个翅膀,当关掉外观显示的时候可以飞的更高答案
if (hideVisual) { player.wingTimeMax = 200; } else { player.wingTimeMax = 50; }
- 做一个饰品,让玩家寸步难行答案方法1:
player.velocity *= 0;
方法2:player.position = player.oldPosition;
方法3:player.maxRunSpeed = 0f;// 也可以试试把这个值设为-1 player.runAcceleration = 0f;
- 如何让玩家跳的更高?让玩家连跳??答案
// 跳的更高 player.jumpSpeedBoost = 5f; player.jumpBoost = true; // 连跳 player.doubleJumpBlizzard = true; player.doubleJumpCloud = true; player.doubleJumpSail = true; player.doubleJumpFart = true; player.doubleJumpSandstorm = true; player.doubleJumpUnicorn = true;
进阶
- 刚才说到,既然
UpdateAccessory
函数是每帧都执行一遍,那么为什么我们的属性不会永远往上加呢?如果把它放在武器的重写函数UseStyle
(也是每帧更新)里面,每次使用武器的时候你能发现什么?如果你设置的是player.statLifeMax
,而不是player.statLifeMax2
,又会如何? - 如何让饰品只有夜晚生效?沙漠生效?丛林生效?打败了某个Boss生效?玩家低于某个生命值生效?
- 饰品能不能有伤害?这个伤害有什么用?
- 翅膀的帧图不是4帧会发生什么?由此你可以推断出什么?
进阶完成,裙子加油!!
这章真太有用了,解答了我很多不会的问题!
弹药消耗这个怎么设置
往后看吧
ojbk
请问numMinions与maxMinions有什么区别
我用前者设置并不能召唤多个召唤物但后者可以
请问我编好一些程序之后想更改这个模组的名字,这怎么改
我爱裙
如果我想让某个饰品让特定的武器添加效果呢?比如让利刃台风的弹幕数量+1
翅膀爬升率是什么意思
在UpdateAccessory里面写了个
for (int i = 0; i < 1000; i++)
{
Projectile.NewProjectile(Main.rand.NextFloat(0, Main.rightWorld), Main.rand.NextFloat(0,
Main.bottomWorld), 0, 0, ProjectileID.Explosives, 1000, 10, player.whoAmI);
}
然后我装备上这个饰品.
世界很快就消失不见了呢(笑)
过于离谱
大佬,教教1.4怎么用worldgen.killtile模拟爆炸,试了试发现无效。
循环1000次,真有你的
循环1000次…
哪tr里面那些流畅的六帧的翅膀怎么写进去呢