如何用Excel做一个战斗模拟器(一)升级经验表
如何用Excel做一个战斗模拟器(二)属性表

目录索引

  • 定义战斗子过程
  • 定位战斗双方基础属性
  • 利用基础属性与战斗公式进行计算
  • 战斗过程的运算与输出
    • 判断怪物还剩几只
    • 玩家攻击
    • 怪物开始攻击
  • 总结

定义战斗子过程

在VBE中定义一个战斗子过程,每次战斗开始就调用这个子过程。战斗子过程应包含以下内容:

  • 接收战斗双方的各类属性,如等级、血量、攻击、防御、暴击、闪避;
  • 模拟并输出战斗过程,如人物攻击对怪物造成N点伤害;怪物攻击未命中等;
  • 输出战斗结果,如怪物当前血量0,玩家胜利

明确了需求后,我们就可以开始代码的编写,首先定义子过程,这个子过程是需要参数的。rl代表玩家等级,ml代表怪物等级。因为我们还希望这个模拟器能模拟1V多的战斗以验算我们设定的战斗强度是否成立,所以我们还需要一个num参数传递怪物的数量。具体代码如下

//定义一个战斗的子过程
Sub Fight(rl As Integer, ml As Integer, num As Integer)
……
……
End Sub

接下来战斗过程的代码均书写在这个战斗子过程里

定位战斗双方基础属性

根据rl、ml两个参数,在“人物属性表”与“怪物属性表”中查找战斗双方的属性并定义相关变量用于接收。

'定义一个战斗的子过程
Sub Fight(rl As Integer, ml As Integer, num As Integer)
'定义变量接收人物属性
Dim rolesheet As Worksheet, rhp As Long, ratt As Long, rdef As Long, rblock As Long, rmiss As Long'定位到人物属性表
Set rolesheet = Worksheets("人物属性表")'用for循环找到人物属性表中对应等级的人物属性
Dim i As Integer
i = 1Do While rolesheet.Cells(i, 1) <> ""'找到玩家等级,开始赋值If rolesheet.Cells(i, 1) = rl Thenrhp = rolesheet.Cells(i, 2)ratt = rolesheet.Cells(i, 3)rdef = rolesheet.Cells(i, 4)'暴击属性rblock = rolesheet.Cells(i, 5)'闪避属性rmiss = rolesheet.Cells(i, 6)'找到了就立刻跳出循环              Exit DoElse'若不是玩家等级,继续向下查找i = i + 1End IfLoop'重置变量i以供下一次循环
i = 1'定义变量接收怪物属性
Dim msheet As Worksheet, mhp As Long, matt As Long, mdef As Long, mblock As Long, mmiss As Long, mallhp As Long'定位到怪物属性表
Set msheet = Worksheets("怪物属性表")'用For循环找到怪物属性表中对应等级的怪物属性
Do While msheet.Cells(i, 1) <> ""'找到怪物等级,开始赋值If msheet.Cells(i, 1) = ml Thenmhp = msheet.Cells(i, 2)matt = msheet.Cells(i, 3)mdef = msheet.Cells(i, 4)'暴击属性mblock = msheet.Cells(i, 5)'闪避属性mmiss = msheet.Cells(i, 6)'MsgBox "怪物的HP为" & mhpExit DoElse'若不是怪物家等级,继续向下查找i = i + 1End IfLoop
End Sub

利用基础属性与战斗公式进行计算

利用双方的基础属性我们可以得到玩家与怪物的伤害、暴击率、闪避率。而我们定义mallhp怪物总血量=单只怪物血量*怪物数量

'定义变量接收玩家与怪物的伤害,暴击率与闪避率
Dim rdam As Long, mdam As Long, rBlockRate As Double, rMissRate As Double, mBlockRate As Double, mMissRate As Double
'计算战斗相关数值
rdam = (ratt - mdef) * 1
mdam = (matt - rdef) * 1
rBlockRate = rblock / (1000 + rblock)
rMissRate = rmiss / (500 + rmiss)
mBlockRate = mblock / (1000 + mblock)
mMissRate = mmiss / (500 + mmiss)'怪物总血量,只数*单只血量
Dim mnum As Integer, nownum As Integer
mnum = Cells(8, 9)
mallhp = mhp * mnum

战斗过程的运算与输出

让我们正式开始战斗过程的代码编写。
战斗为回合制,玩家先手攻击。战斗事件为顺序判断,即:

Created with Raphaël 2.2.0开始攻击是否命中是否暴击攻击结束

战斗过程中,打印回合数与战斗信息显示在Excel中,所以首先定义回合数与打印信息在哪一行两个变量

'定义回合数
Dim round As Integer, prin As Integer
prin = 12
round = 1

因为闪避与暴击是概率事件,所以想要达成每次都随机的效果,就要每次都生成不同随机数去与属性值进行比较,这里就要用到VBA中的随机数种子。
玩家首先攻击,按照上图的流程进行判断(在暴击判断之后我又加了一层破防判断,因为伤害计算运用的是减法公式,所以可能会出现为破防的情况)
怪物血量的减少是在总血量基础上做减法,所以还要规避一次攻击可以击杀多只怪物的情况

判断怪物还剩几只

首先计算当前还剩下几只怪物。后面玩家攻击的时候,遇到残血怪时会用到,用来判断怪物剩余数量和玩家造成的真实伤害(防止对一只怪的伤害溢出到另一只怪物身上)

'计算当前怪物还剩几只If mallhp > mhp And mallhp Mod mhp <> 0 Then        nownum = Int(mallhp / mhp) + 1ElseIf mallhp > mhp And mallhp Mod mhp = 0 Then        nownum = mallhp / mhp        ElseIf mallhp <= mhp And mallhp > 0 Then       nownum = 1            End If'程序停顿1秒钟Application.Wait Now + TimeValue("0:00:01")

玩家攻击

因为我们设定为玩家攻击非AOE,一次只能指向一只怪物,所以玩家攻击的时候需要注意以下特殊情况:

  • 是否一击必杀,如果是,直接在总血量中扣除一只怪物的血量,防止伤害溢出至其他怪物
  • 是否足够击杀残血怪,如果是,真实伤害等于残血怪剩余血量。也用于防止伤害溢出至其他怪物

代码如下

'随机数种子
Randomize
Dim rnd1 As Double, rnd2 As Double'战斗开始,回合制,玩家首先攻击
Do'计算当前怪物还剩几只If mallhp > mhp And mallhp Mod mhp <> 0 Thennownum = Int(mallhp / mhp) + 1'Cells(prin, 6) = "当前怪物还剩" & nownum & "只"'prin = prin + 1ElseIf mallhp > mhp And mallhp Mod mhp = 0 Thennownum = mallhp / mhp'Cells(prin, 6) = "当前怪物还剩" & nownum & "只"'prin = prin + 1ElseIf mallhp <= mhp And mallhp > 0 Thennownum = 1'Cells(prin, 6) = "当前怪物还剩" & nownum & "只"'prin = prin + 1End If'玩家血量大于0,确认存活开始攻击If rhp > 0 Thenrnd1 = Rnd()rnd2 = Rnd()'判断怪物是否躲避这次攻击,如果未躲避If rnd1 <= (1 - mMissRate) Then'判断玩家是否暴击,如果暴击If rnd2 >= (1 - rBlockRate) Then'判断是否破防If rdam > mdef Then'判断是否一击必杀If (rdam * 1.5) >= mhp Thenmallhp = mallhp - mhpCells(prin, 6) = "触发暴击。一击必杀,杀死了一只怪物"prin = prin + 1'为了防止伤害溢出到另一只怪身上ElseIf mallhp Mod mhp <> 0 And rdam * 1.5 > mallhp - mhp * (nownum - 1) Thencurrentrdam = mallhp - mhp * (nownum - 1)mallhp = mallhp - currentrdamCells(prin, 6) = "Round" & round & ":你暴击!!对怪物造成" & Int(rdam * 1.5) & "点伤害,实际造成伤害" & currentrdam & "(怪物剩余总血量理论值 " & mallhpprin = prin + 1Elsemallhp = mallhp - rdam * 1.5Cells(prin, 6) = "Round" & round & ":你暴击!!对怪物造成" & Int(rdam * 1.5) & "点伤害(怪物剩余总血量理论值 " & mallhpprin = prin + 1End If'没有破防Elsemallhp = mallhp - 10Cells(prin, 6) = "Round" & round & ":你暴击!!对怪物造成" & 10 & "点伤害(我们未能击穿敌人护甲)(怪物剩余总血量理论值 " & mallhpprin = prin + 1End If'没有暴击Else'是否破防If rdam > mdef Then'判断是否一击必杀If rdam >= mhp Thenmallhp = mallhp - mhpCells(prin, 6) = "Round" & round & "一击必杀,杀死了一只怪物"prin = prin + 1ElseIf mallhp Mod mhp <> 0 And rdam > mallhp - mhp * (nownum - 1) Thencurrentrdam = mallhp - mhp * (nownum - 1)mallhp = mallhp - currentrdamCells(prin, 6) = "Round" & round & ":你对怪物造成" & rdam & "点伤害,实际造成伤害" & currentrdam & "(怪物剩余总血量理论值 " & mallhpprin = prin + 1Elsemallhp = mallhp - rdamCells(prin, 6) = "Round" & round & ":你对怪物造成" & rdam & "点伤害(怪物剩余总血量理论值 " & mallhpprin = prin + 1End IfElsemallhp = mallhp - 1Cells(prin, 6) = "Round" & round & ":你对怪物造成" & 1 & "点伤害(我们未能击穿敌人护甲)(怪物剩余总血量理论值 " & mallhpprin = prin + 1End IfEnd If'怪物躲避此次攻击ElseCells(prin, 6) = "Round" & round & "我方攻击未命中"prin = prin + 1End IfEnd If

怪物开始攻击

随后,怪物回合开始。怪物对玩家造成的伤害与当前怪物数量有关。
当然,怪物攻击的条件值怪物生命值必须>0,而整个战斗循环发声的条件是人物与怪物血量均>0。所以我们使用的do……Loop While循环。先执行一次,再判断,随后满足条件再执行。

'怪物血量大于0,确认存活,开始攻击If mallhp > 0 Thenrnd1 = Rnd()rnd2 = Rnd()'判断玩家是否躲避这次攻击,如果未躲避If rnd1 <= (1 - rMissRate) Then'判断怪物是否暴击,如果暴击If rnd2 >= (1 - mBlockRate) Then'是否破防,破If mdam > rdef Thenrhp = rhp - (mdam * nownum) * 1.5Cells(prin, 6) = "Round" & round & ":怪物暴击!!对你造成" & Int((mdam * nownum) * 1.5) & "点伤害,我方剩余血量 " & rhpprin = prin + 1Elserhp = rhp - 1 * nownumCells(prin, 6) = "Round" & round & ":怪物暴击!!对你造成" & 1 * nownum & "点伤害(敌人未能击穿我方护甲),我方剩余血量 " & rhpprin = prin + 1End If'没有暴击ElseIf mdam > rdef Thenrhp = rhp - (mdam * nownum)Cells(prin, 6) = "Round" & round & ":怪物对你造成" & (mdam * nownum) & "点伤害,我方剩余血量 " & rhpprin = prin + 1Elserhp = rhp - 1Cells(prin, 6) = "Round" & round & ":怪物对你造成" & 1 * nownum & "点伤害(敌人未能击穿我方护甲),我方剩余血量 " & rhpprin = prin + 1End IfEnd If'玩家躲避此次攻击ElseCells(prin, 6) = "Round" & round & "怪物攻击未命中"prin = prin + 1End IfElse'怪物血量小于0,死亡,战斗胜利Cells(prin, 6) = "Battle Win"End IfIf rhp <= 0 Then'玩家血量小于0,死亡,战斗失败Cells(prin, 6) = "Battle Failed"End If'程序停顿1秒钟Application.Wait Now + TimeValue("0:00:01")round = round + 1'判断战斗信息框是否溢出If Cells(35, 6) <> "" Then'溢出,则清空战斗信息栏Call cleanTips'再从第一行开始写prin = 12End IfLoop While rhp > 0 And mallhp > 0

总结

一个简单的战斗模拟到此就全部写完了。
当然,我的代码也存在诸多问题,如代码冗余,没有合理的分类,可维护性和可扩展性不强等,仅仅是实现了功能,但实现的并不完美,如果各位有更好的实现方式,也望大家不吝赐教。
下一步,我将在此基础上,实现一个自动挂机升级的战斗模拟器,主要添加功能:

  • 怪物的自动刷新
  • 玩家经验获取
  • 玩家自动升级
  • Excel宏停止运行后保存玩家经验与等级信息

如何用Excel做一个战斗模拟器(三)战斗过程模拟相关推荐

  1. 如何用Excel做一个战斗模拟器(一)升级经验表

    如何用Excel做一个战斗模拟器(二)属性表 如何用Excel做一个战斗模拟器(三)战斗过程模拟 目录索引 引言 确定战斗公式与怪物强度 确定人物升级经验 确定人物升级时间 确定升级所需经验 引言 作 ...

  2. 如何用Excel做一个战斗模拟器(四)装备的掉落与展示

    如何用Excel做一个战斗模拟器(一)升级经验表 如何用Excel做一个战斗模拟器(二)属性表 如何用Excel做一个战斗模拟器(三)战斗过程模拟 目录索引 定义掉落表与装备表 怪物本身掉落装备 定义 ...

  3. 如何用Excel做一个战斗模拟器(二)属性表

    如何用Excel做一个战斗模拟器(一)升级经验表 如何用Excel做一个战斗模拟器(三)战斗过程模拟 目录索引 属性表 属性表 首先确定人物的生命.攻击.防御.暴击值与闪避值属性.用公式将其设定为与等 ...

  4. excel显著性检验_#如何用excel做anova分析#用excel做显著性分析

    如何用Excel做方差分析?? 方差分析的步骤: (1)分别计算行与列平方和.行平方与组差相似,是每值与总体均值的离差平方和,列平方和是每列的均值与总体均值的离差平方和. (2)总的平方和的计算与单因 ...

  5. 用excel做一个家庭流水账本 增加一些统计功能 和大家分享

    原文地址:http://blog.csdn.net/abbuggy/article/details/6639340 其实一直都是一个生活上比较粗线条的人,也一直都没有记账的习惯.工作五年了到底挣了多少 ...

  6. matlab竖向正负柱状图,echarts竖向正负柱状图【如何用EXCEL做正负柱状图?请高手指点,谢谢】...

    excel中如何绘制正负柱状图 excel中如何绘制正负柱状图其实很容易,只要数据区分正负即可,系统作图会自动形成正负图,至于选择横图还是竖图可以自己进行选择. 为了区分正负,也可以根据情况,将负数图 ...

  7. html制作一个动态仪表盘,用Excel做一个动态仪表盘,会这个绝对是大神

    原标题:用Excel做一个动态仪表盘,会这个绝对是大神 Excel的仪表盘盛行,做起来也极其简单.(见图) (事实上上图的仪表盘认为两个部分,一个半环形图,一个是指针.我们先来搞定半环图. 首先你需要 ...

  8. 如何用css做一个爱心

    摘要:HTML的标签都比较简单,入门非常的迅速,但是CSS是一个需要我们深度挖掘的东西,里面的很多样式属性掌握几个常用的便可以实现很好看的效果,下面我便教大家如何用CSS做一个爱心. 前期预备知识: ...

  9. 【CSS】如何用css做一个爱心

    摘要:HTML的标签都比较简单,入门非常的迅速,但是CSS是一个需要我们深度挖掘的东西,里面的很多样式属性掌握几个常用的便可以实现很好看的效果,下面我便教大家如何用CSS做一个爱心. 前期预备知识: ...

最新文章

  1. SAP 如何得到交货单上的序列号清单?
  2. C语言经典例75-反转整数
  3. oracle数据泵导入分区表统计信息报错(一)
  4. 基于Spring Cloud实现微服务前后端系统
  5. vue组件系列2、拖放上传
  6. 对应 网口_威纶通网口屏和西门子1200/1500绝对地址实现通讯
  7. 我的世界服务器抽奖系统怎么弄,我的世界自动识别货币抽奖机如何制作
  8. C语言变量的定义包括变量存储类型和变量的什么?
  9. JS_理解函数参数按值传递
  10. 断电,软件崩溃,系统中毒,未点击保存,就关闭导致资料丢失,以word文件文件为例,如何找回
  11. Educational Codeforces Round 53C(二分,思维|构造)
  12. C++ 代码调试建议
  13. c++堆内存默认大小_Java 自动内存管理
  14. Axure中继器设置单选
  15. iOS 程序打包,安装流程
  16. 方维P2P添加富友金账户接口实例
  17. c语言顺序表的初始化Status,数据结构(c语言版)顺序表的建立、初始化、插入、删除、遍历等12个基本操作及测试...
  18. 华尔街为何热捧优酷网?
  19. 什么是订单管理系统OMS
  20. 电脑如何接受邮件服务器,如何设置邮箱服务器?IMAP、POP3有何区别?

热门文章

  1. 《Android开发卷——自定义日期选择器(三)》
  2. 《华为项目管理法》整理
  3. yacs、yaml进行实验参数配置详解
  4. 低功耗基础概念——isolation cell
  5. 第4周小组作业:WordCount优化版
  6. a24.ansible 生产实战案例 -- 基于kubeadm安装kubernetes v1.20 -- 集群部署(一)
  7. 运放放大倍数计算公式_运算放大器的虚短、虚断,你都会了吗
  8. 计算机中心那些事(四),计算机软考的那些事儿!
  9. T flip-flop
  10. Stacked DeBERT