作者:天火游侠 酱油
声明:由于家用笔记本用的是WPS,与Office的可能会有些出入,但并不阻碍制作,请在阅读的时候一并打开Excel,跟着我左手右手一个慢动作,右手左手慢动作回放。
为了帮助未入行和已入行不久的新人学习Excel函数,我思考良久后决定用Excel的函数来做一个战斗模拟器,闲话不多说,直接先上简图:
之所以叫简单的较复杂的战斗模拟器,是因为简单是简单在用函数,较复杂是复杂在属性多。在做完简图后我们再来拉一个角色的标准属性模版(表名定为LevelSheet):
知识点来了:上图中前三行分别是干什么用的呢?
头一行,是这项属性的名称(废话)
二一行,是这项属性在前端所用的字段(变量)名称
三一行,是这项属性在后端存储所采用的数据类型,Int为整数型,String为文本型,Float为带小数点的浮点型
拉完了标准属性模版后,我们再拉一个角色的属性偏移表(表名定为HeroDB):
知识点来了:什么是属性偏移表?
角色各个属性根据自身(职业)特性,针对标准属性做出的修正
例:1级的买买提体力为1000,攻击为100,防御为260
大家看到最后两列是技能吧,没错,接下来我们来做一个技能的表(表名定为SkillDB):
知识点来了:这里的效果类型和效果参数是什么鬼?
因为技能一般除了伤害外,有时还会附带一些状态类效果(增益、减益),于是、我将这些状态类效果合并为一个字段,而不是每一项状态类效果都给设置一个字段。此处我所采用的定义是:0 = 无状态类效果;1 = 自身伤害上升10%;2 = 敌方伤害下降10%;3 = 敌方每回合损失自身体力上限的5%的持续伤害(无法闪避,强制扣血)
对应状态类效果,一般会给一个持续的时间(回合),于是效果参数就是来设置这个持续的时间(回合),此处的单位为回合(一般下不会像我这样只设成持续1回合,即仅下一回合生效,我这么做是因为讲解方便)
注:此处所用触发几率即触发技能的几率,例如——买买提有10%的概率触发1技能,10%的概率触发2技能,80%的概率进行普通攻击
最后,我们来拉一张装备的属性表(表名定为EquipDB):
由于本次仅仅是做战斗模拟器,所以只写了一些用得上的属性,实际上在制定表头的时候并不会只用我所列的这些属性,例如,角色或物品会有一条“描述”的字段。
准备好了这几个数据表,我们来开始做战斗模拟器
先来做一个角色列表的下拉选择菜单:选中B2单元格,点击数据——数据有效性
为了方便数据查找,特使用ID来辨识,同理,将第2行的其他单元格也这么做:
之后,我们来对第三行的属性来进行计算,这里讲3个查找用的函数,Lookup、Vlookup、Hlookup:
根据查找值参数,在查找值所在查找向量找到所在位置,返回返回向量中对应的值
根据查找值参数,在数据表的第一列搜索查找值,找到该值后,则返回值为:以第一列为准,往后推数列序数的这一列所对应的值
与Vlookup作用差不多,只是由列改为行
此处因表结构缘故,只使用Lookup与Vlookup进行演示(实际上一般都用Vlookup来做),在B3写上:
=VLOOKUP($B$2,HeroDB!$A$4:$E$7,3)*LOOKUP($D$2,LevelSheet!$A$4:$A$23,LevelSheet!$B$4:$B$23)+VLOOKUP($H$2,EquipDB!$A$4:$H$18,4)
其中:
VLOOKUP($B$2,HeroDB!$A$4:$E$7,3)查找该角色体力属性的偏移
LOOKUP($D$2,LevelSheet!$A$4:$A$23,LevelSheet!$B$4:$B$23)查找该等级下的标准体力值
VLOOKUP($H$2,EquipDB!$A$4:$H$18,4)查找装备2所提供的额外体力加成值
知识点来了:为什么我会在单元格的位置上加上两个美刀的符号?当然,并不是因为我有钱,其实我也是个穷人
不加$符号(例:A1)为相对引用,若我在B1输入=A1,再将B1向下拖动到B2,那么B2处就会显示=A2
加2个$符号(例:$A$1)为绝对引用,我在B1输入=$A$1,再将B1向下拖动到B2,那么B2处就会显示=$A$1
加单个$符号(例:$A1、A$1),$符号在哪个(列、行)前面,就是对哪个(列、行)进行绝对引用,对另一个进行相对引用
用同样的方法,我们把第三行的数据都填上(由于暴击与闪避两项属性并无便宜,所以用2条查找就可以了,体力、攻击、防御三项属性的单元格格式设置为数值-0位小数,暴击与闪避两项属性的单元格格式设置为数值-2位小数):
做完了基础属性计算(记得验算一下看看对不对),我们开始着手技能的设置:
在K列前插入一列(K2命名为技能随机数):
K3处输入=RANDBETWEEN(1,100)
用于生成一个介于最小整数与最大整数之间的随机整数(包括最小、最大整数)
接着,再在L列前插入一列(L2命名为伤害系数):
先是在L3用一串VLOOKUP(B2,HeroDB!A4:G7,6)来读取角色的技能1ID,再由LOOKUP(VLOOKUP($B$2,HeroDB!$A$4:$G$7,6),SkillDB!$A$4:$A$11,SkillDB!$C$4:$C$11)来读取该ID在SkillDB表中对应的伤害系数,接着就是用IF函数来对技能随机数进行一个是否触发技能1的判断:
判断测试条件是否为真,为真则返回真值,为假则返回假值
那么问题来了,如何进行判断呢?
我们已经用一长串函数来读取了技能1所对应的伤害系数了对吧,那么我们再用LOOKUP(VLOOKUP($B$2,HeroDB!$A$4:$G$7,6),SkillDB!$A$4:$A$11,SkillDB!$F$4:$F$11)读取一次技能1所对应的技能触发几率,之后用IF来进行判断:
之所以有一个“*100”,是因为前面我们所采用的是RoundBetween(1,100),所以触发概率0.1也要相应扩大100倍变为10,若随机数小于等于10,则触发技能1,否则进行技能2触发判断,以此类推,完成公式如下:
吓到了没有?这段函数翻译成人话就是“如果随机数小于技能1的触发几率,则返回技能1的伤害系数;否则判断随机数减去技能1的触发概率后是否小于技能2的触发概率,是则返回技能2的伤害系数;否则返回1(普通攻击伤害系数)”,这个地方建议大家自行添加辅助列,例如“触发技能”,此处为了完全是为了【装逼】而用了一大坨的函数。
然后你发现依旧是一坨函数23333,不过伤害系数处的函数就简单了很多,一个IF函数嵌套一个查找函数IF($L$3>0,VLOOKUP($L$3,SkillDB!$A$4:$F$11,3),1)
知识点来了:为什么要先做一个是否大于0的判断呢?
因为在上面的那坨代码中,我将普通攻击所代表的技能定为0,而0在技能表中并不存在,所以要先进行一次是否大于0的判断
我想了想,这一串函数还是太长了,我们来再简化一下:
再插入两列辅助列,用来先查找到2个技能的触发几率:
L3=(LOOKUP(VLOOKUP($B$2,HeroDB!$A$4:$G$7,6),SkillDB!$A$4:$A$11,SkillDB!$F$4:$F$11))
M3=(LOOKUP(VLOOKUP($B$2,HeroDB!$A$4:$G$7,7),SkillDB!$A$4:$A$11,SkillDB!$F$4:$F$11))
这两条应该不难写吧?接着根据K3、L3、M3三个参数用IF进行嵌套判断来返回触发的技能:
N3=IF($K$3<><>
这么一来是不是变得简短又清晰了呢?好,言归正传,再来插两列,用来读取技能对应的触发效果及持续回合
跟到这里P3、Q3两个单元格应该写什么函数应该有个数了吧?
P3==IF($N$3>0,VLOOKUP($N$3,SkillDB!$A$4:$F$11,4),0)
Q3==IF($N$3>0,VLOOKUP($N$3,SkillDB!$A$4:$F$11,5),0)
好了,到此为止角色A完工了,我们用同样的方法来完善B角色的
至此,我们需要的数据都读完了,接下来进入正题【战斗模拟】,不过在模拟之前,请大家用F9来对随机数进行刷新来调试自己的函数有没有写错
先在A4写上Round1,作为回合计数器,B2处写上:
注意绝对应用与相对引用的项,别写错了
知识点来了:&和””是干什么用的?
&是一种连接符,将前后两个内容连接起来,例:在A1写有“史晓林”,A2写有“发红包”,在A3处写=A1&A2,就会得到“史晓林发红包”
“”代表其中的内容为字符串(文本)
我来解释一下这一串的意思:
先用VLOOKUP($B$2,HeroDB!$A$4:$B$7,2)来查找角色A的诨号
再用VLOOKUP($T$2,HeroDB!$A$4:$B$7,2)来查找角色B的诨号
接着IF($N$3>0,VLOOKUP($N$3,SkillDB!$A$4:$B$11,2),'普通攻击')来确定角色A使用的是技能还是普通攻击
最后用&将这些与“对”、“使用”、“造成了”连接
由于我给技能按上了状态类效果,还有持续回合,所以我要用2个单元格来作一个记录触发的技能效果与持续回合的处理,不能直接使用已经列出来的触发效果(P列)和持续回合(Q列),先将K3、N3~Q3下拉填充到K4、N4~Q4,再将N4中的K3项解除绝对引用改为K4,将O4~Q4中的N3项解除绝对引用改为N4:
这么一来,L4和M4就可以拿来存储:
由于是起始回合,只需要写L4=$P$4,M4=$Q$4就可以了,公式上的变化是从第二回合才开始,我们先来做重头戏【伤害计算】(请耐心细心,因为很容易错):
我选择在G2进行伤害的计算,在这提一下我所采用的伤害公式是:伤害=攻击-(防御/233)*100%,即每233点防御提供1%的免伤,大家也可以自行设计伤害公式:
=ROUNDDOWN((IF(RAND<=$ab$3,0,($d$3*(1-$x$3><>
我从内向外讲解:
$D$3*(1-$X$3/23300)伤害计算公式,伤害=攻击*(1-防御/233*100%)
O4伤害系数
IF(RAND<>
随机生成一个介于0和1之间的数
— RAND<>
再以此法将角色B的第四行写出来:
接着我们来做剩余体力的计算,这个就简单了,直接最大体力减去本回合对方伤害即可:
J3=$B$3-AA4(接下来我会采用这种简单做法)
我们可以用条件格式——数据条来使得剩余HP高端起来(由于艹Egg的WPS翻不到数据条的条件格式,所以用Office的可以这么干,点条件格式—数据条—自定义,最小值选数字=0,最大值选公式=$B$3,然后在下面选择样式就可以得到一个动态的数据条了)
接着教大家一个更高端的HP血条制作方法(以此法做建议加一个剩余HP数值的辅助列,不然接下来不好做):
返回重复次数个字符串
J4=REPT('|',($B$3-AA4)/$B$3*15)&ROUNDUP(($B$3-AA4)/$B$3*100,1)&'%'
$B$3-AA4)/$B$3 当前血量的百分比
15满血时候的重复次数(这个大家可以随意调试)
'|'充当协调的字符串
与RoundDown相似,只不过是向上取舍字体设置为Britannic Bold,字体颜色设置为红色
当当当~~~~到了最后一步了,大家可以做个深呼吸,上个厕所,约个炮(放炮仗)什么的
第二回合开始有些地方的公式需要做出改变(以A为例子),先由第四行下拉填充第五行:
1.伤害计算,在伤害系数O5后加一条*(1+SUM(IF(L4=1,0.1,0),IF(AD4=2,-0.1,0))),这一条是伤害的状态修正系数,判断上回合自己与对方是否有使用带有自身伤害提升、自身伤害下降状态效果的技能,将两个修正值相加(即增益减益可以相抵)
2.伤害计算,在整个伤害判定的末尾加一条+IF(L4=3,0.05*$T$3,0),这一条是由持续伤害状态带来的伤害
G5=ROUNDDOWN((IF(RAND<=$ab$3,0,($d$3*(1-$x$3 3300)*o5*(1+sum(if(l4=""><>
3.剩余HP,J5处的$B$3改为J4
同样地对B的区块进行修改,最后来做一个美化操作:
选中这几个辅助列,右键—隐藏,对B也这么做
然后就从第二回合开始下拉吧!(因为B方最后一片被隐藏了,所以下拉时要多选择一个后面的单元格进行下拉)
完成版展示
后记:也许有细心的人发现,效果持续回合数并没有怎么用到
其实这是为了持续多回合的状态而做的准备,当然也得相应多加几个辅助列来处理重复使用状态类技能而刷新了持续回合数的情况
联系客服