|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 烈林凤 于 2024-4-8 22:48 编辑
距离上次发帖已经过五个月了,原本说下一篇帖子应该在半个月后发,没想到鸽了这么久,私密马赛。
(究其原因是因为一直在忙自己游戏的其他内容,导致renpy一直没怎么动)
这次给各位带来的是回合制战斗系统
和之前一样,尽量不使用太难懂的python内容,只要懂renpy并且会一点python基础知识都可以看懂(咳咳,我就是这样的)。
关于教程里的很多名词的命名,比如“为什么叫削韧不叫削防”、“为什么叫破韧不叫破防”,我只能说,你想怎么命名都可以,我这么命名只是我听着顺耳。
这次将很多讲解的部分放在了代码注释里,请自行查看。
如果你觉得看文章看不懂想直接抄代码,可以直接复制“抄代码环节”里的代码。
感谢群友“豁然贯”提供的灵感,不然我也不会想到可以做回合制战斗系统的相关教程。(论坛是真的没有相关教程……)
注意!本篇教程使用的是8.2.1版本的renpy,如果你使用的是比这个更低的版本会出现报错!例如:
低版本报错
这是因为我在代码中使用了以前不规范的写法,例如:
[RenPy] 纯文本查看 复制代码 centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[round((npc_fang*0.2),1)]点的削韧!{nw=10}"
你需要将[round((npc_fang*0.2),1)]的部分进行转义,例如:
[RenPy] 纯文本查看 复制代码 $ lizi = round((npc_fang*0.2),1)
centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[lizi]点的削韧!{nw=10}"
请自行进行适配!不然就换成最新版本的renpy。(最好也是换成高版本的,因为有很多新教程都无法兼容旧版本)
接下来进入正题——
No.1
我们先对需要用到的变量进行定义——
[RenPy] 纯文本查看 复制代码 default xuanz = 0 # 控制界面按钮的使用
default zhandou_time = 0 # 战斗回合数
# 敌方和我方的各项数值均采用浮点数,使用round保留一位小数(直接去掉尾部)
default gamer_xue = 500.00 # 玩家血量
default gamer_gong = 100.00 # 玩家攻击力
default gamer_fang = 50.00 # 玩家防御力
default gamer_fang_max = 100.00 # 玩家防御力上限
default gamer_xue_max = 500.00 # 玩家血量上限
default npc_name = "" # 敌方名字
default npc_xue = 0.00 # 敌方血量
default npc_gong = 0.00 # 敌方攻击力
default npc_fang = 0.00 # 敌方防御力
# 因为本次只给敌方设置了一个战斗逻辑(只有攻击),所以偷个懒没写血量和防御上限
如果需要写更多的东西,比如buff、debuff、抗性什么的,需要定义更多变量,请自行填写
No.2
接下来是主要部分,轮到玩家回合时,玩家进行行为选择——
[RenPy] 纯文本查看 复制代码 screen zhandou():
# 轮到玩家的战斗回合时,玩家会来到这个界面选择行为
# 显示战斗回合数
text "{color=#BF3512}{size=50}{b}战斗回合数 [zhandou_time]":
xycenter(0.1,0.59)
frame:
xycenter(0.5,0.8)
xysize(1920,400)
hbox:
ycenter 0.12
xpos 0.05
# 显示玩家和敌方的各项数值
vbox:
text "[persistent.gamer_name]的角色信息{space=30}"
text "[npc_name]的角色信息{space=30}"
vbox:
text "血量[gamer_xue]{space=30}"
text "血量[npc_xue]{space=30}"
vbox:
text "攻击力[gamer_gong]{space=30}"
text "攻击力[npc_gong]{space=30}"
vbox:
text "防御力[gamer_fang]{space=30}"
text "防御力[npc_fang]{space=30}"
vbox:
xycenter(0.07,0.5)
# 点击按钮,显示各种行为的具体行为
textbutton "{size=40}攻击":
# 控制按钮的选择,如果不使用会导致玩家可以打开多个界面
if xuanz == 0 or xuanz == 1:
# 将其他按钮锁定,并临时打开一个界面
action [SetVariable("xuanz",1),ShowTransient("gongji")]
textbutton "{size=40}防御":
if xuanz == 0 or xuanz == 2:
action [SetVariable("xuanz",2),ShowTransient("fangyu")]
textbutton "{size=40}治疗":
if xuanz == 0 or xuanz == 3:
action [SetVariable("xuanz",3),ShowTransient("zhiliao")]
因为是教程,所以我只写了攻击、防御、治疗三种基础行为,可以自行添加更多功能,例如增益、削弱、逃离等等。
关于这里以及之后关于{}里的内容,请自行查阅文档“文本标签”部分,在此就不再过多赘述
文本 — Ren'Py 中文文档 (renpy.cn)
关于这里以及之后关于action里的内容,请自行查阅文档“界面行为”部分,在此就不再过多赘述
界面行为(action)、值(value)和函数 — Ren'Py 中文文档 (renpy.cn)
(还有,低版本是需要在文本末尾加{/}的,否则会报错,所以说请尽量升到最新版本)
NO.3
然后是选择行为后的各种具体行为——
[RenPy] 纯文本查看 复制代码 screen gongji():
# 攻击行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
textbutton "{size=50}削韧型攻击":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0), # 让所有按钮都可以选择
SetVariable("zhandou_time",zhandou_time+1), # 使战斗回合数+1
Jump("jisuan_削韧型攻击"), # 跳到该行为的计算过程
Hide("gongji")] # 关闭当前界面
# 让所有按钮都可以选择,并关闭当前界面
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("gongji")]
# 之后的内容就都是类似的了
screen fangyu():
# 防御行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
# 如果防御大于等于上限时就无法使用
if gamer_fang < gamer_fang_max:
textbutton "{size=50}常规型防御":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0),
SetVariable("zhandou_time",zhandou_time+1),
Jump("jisuan_常规型防御"),
Hide("fangyu")]
elif gamer_fang >= gamer_fang_max:
text "{size=50}{i}防御已达到最大值":
xycenter(0.5,0.5)
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("fangyu")]
screen zhiliao():
# 治疗行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
# 如果血量大于等于上限时就无法使用
if gamer_xue < gamer_xue_max:
textbutton "{size=50}防御型治疗":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0),
SetVariable("zhandou_time",zhandou_time+1),
Jump("jisuan_防御型治疗"),
Hide("zhiliao")]
elif gamer_xue >= gamer_xue_max:
text "{size=50}{i}血量已达到最大值":
xycenter(0.5,0.5)
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("zhiliao")]
关于为什么都只写一项,原因同上。
NO.4
随后是各项行为的计算过程——
[RenPy] 纯文本查看 复制代码 # 各类行为的计算过程我写的都有些复杂,如果是第一次尝试可以试着用更简单的计算方法
label jisuan_削韧型攻击:
# “削韧型攻击”的计算过程
if gamer_gong > npc_fang:
# 当玩家攻击力大于敌方防御力时
centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[round((gamer_gong-npc_fang),1)]点的伤害,并造成[round((npc_fang * 0.05),1)]点削韧!{nw=10}"
$ npc_xue = round(npc_xue + (npc_fang - gamer_gong),1)
$ npc_fang = round(npc_fang - (npc_fang * 0.05),1)
elif gamer_gong <= npc_fang:
# 当玩家攻击力小于等于敌方防御力时
centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[round((npc_fang*0.2),1)]点的削韧!{nw=10}"
$ npc_fang = round(npc_fang - (npc_fang * 0.2),1)
if gamer_gong > npc_fang:
# 当此次攻击使敌方防御力低于玩家攻击力时
centered "{size=80}{color=#BF3512}{b}成功将[npc_name]破韧!{nw=10}"
if npc_xue <= 0:
# 当此次攻击使敌方血量小于等于0时
centered "{size=80}{color=#BF3512}{b}[npc_name]已经被你击败!{nw=10}"
return
# 玩家行动回合结束,跳转到敌方的行动回合
jump npc_jisuan
label jisuan_常规型防御:
centered "{size=80}{color=#BF3512}{b}回复了[round((gamer_fang*0.2 + gamer_fang_max*0.1),1)]点防御值!{nw=10}"
$ gamer_fang = round(gamer_fang + (gamer_fang*0.2 + gamer_fang_max*0.1),1)
if gamer_fang > gamer_fang_max:
# 当此次回复后的防御力高于上限时,将防御力等于上限
$ gamer_fang = gamer_fang_max
jump npc_jisuan
label jisuan_防御型治疗:
centered "{size=80}{color=#BF3512}{b}回复了[round(gamer_xue_max * 0.05 + gamer_xue * 0.05)]点的血量和[round(gamer_xue * 0.01 + gamer_xue_max * 0.01)]点防御!{nw=10}"
$ gamer_xue = round(gamer_xue + gamer_xue_max * 0.05 + gamer_xue * 0.05)
$ gamer_fang = round(gamer_fang + gamer_xue * 0.01 + gamer_xue_max * 0.01)
if gamer_fang > gamer_fang_max:
# 当此次回复后的防御高于上限时,将防御等于上限
$ gamer_fang = gamer_fang_max
if gamer_xue > gamer_xue_max:
# 当此次回复后的血量高于上限时,将血量等于上限
$ gamer_xue = gamer_xue_max
jump npc_jisuan
简单说明一下我写的这些行为的计算公式:
削韧型攻击:当敌方防御力大于攻击力时,对敌方造成敌方当前防御力20%的削韧效果;当敌方防御力低于攻击力时,对敌方造成伤害,并造成敌方当前防御力5%的削韧效果
常规型防御:回复 防御力上限的20%+当前防御力的10% 的防御力
防御型治疗:回复 血量上限的5%+当前生命值的5% 的血量,并回复 血量上限的1%+当前生命值的1% 的防御力
如果防御和治疗的时机运用得当,可以产生电表倒转的效果(笑)
NO.5
最后就该轮到敌方的行动回合了——
[RenPy] 纯文本查看 复制代码 label npc_jisuan:
# 敌方行为的计算过程
"接下来是[npc_name]的行动回合!"
if npc_gong > gamer_fang:
# 敌方攻击力高于玩家防御力时
centered "{size=80}{color=#BF3512}{b}[npc_name]对你造成了[round((npc_gong - gamer_fang),1)]点的伤害,并造成[round((gamer_fang * 0.05),1)]点削韧!{nw=10}"
$ gamer_xue = round(gamer_xue + (gamer_fang - npc_gong),1)
$ gamer_fang = round(gamer_fang - (gamer_fang * 0.05),1)
elif npc_gong <= gamer_fang:
# 敌方攻击力小于等于玩家防御力时
centered "{size=80}{color=#BF3512}{b}[npc_name]对你造成了[round((npc_fang * 0.2),1)]点的削韧!{nw=10}"
$ gamer_fang = round(gamer_fang - (gamer_fang * 0.2),1)
if npc_gong > gamer_fang:
centered "{size=80}{color=#BF3512}{b}你被绿成功破韧!{nw=10}"
if gamer_xue <= 0:
# 玩家血量归零时
centered "{size=80}{color=#BF3512}{b}菜!{nw=10}"
return
else:
# 敌方行动回合结束,回到玩家的行动回合
call screen zhandou
敌方唯一招式的计算过程和玩家的“削韧型攻击”是一致的,你们可以写更多的敌方行为,并使用随机函数,调整权重,将敌方的行为整得更加智能(当然,这将会使代码更加复杂,因此就不再多写了(懒))
抄代码环节——
[RenPy] 纯文本查看 复制代码 default xuanz = 0 # 控制界面按钮的使用
default zhandou_time = 0 # 战斗回合数
# 敌方和我方的各项数值均采用浮点数,使用round保留一位小数(直接去掉尾部)
default gamer_xue = 500.00 # 玩家血量
default gamer_gong = 100.00 # 玩家攻击力
default gamer_fang = 50.00 # 玩家防御力
default gamer_fang_max = 100.00 # 玩家防御力上限
default gamer_xue_max = 500.00 # 玩家血量上限
default npc_name = "" # 敌方名字
default npc_xue = 0.00 # 敌方血量
default npc_gong = 0.00 # 敌方攻击力
default npc_fang = 0.00 # 敌方防御力
# 因为本次只给敌方设置了一个战斗逻辑(只有攻击),所以偷个懒没写血量和防御上限
screen zhandou():
# 轮到玩家的战斗回合时,玩家会来到这个界面选择行为
# 显示战斗回合数
text "{color=#BF3512}{size=50}{b}战斗回合数 [zhandou_time]":
xycenter(0.1,0.59)
frame:
xycenter(0.5,0.8)
xysize(1920,400)
hbox:
ycenter 0.12
xpos 0.05
# 显示玩家和敌方的各项数值
vbox:
text "[persistent.gamer_name]的角色信息{space=30}"
text "[npc_name]的角色信息{space=30}"
vbox:
text "血量[gamer_xue]{space=30}"
text "血量[npc_xue]{space=30}"
vbox:
text "攻击力[gamer_gong]{space=30}"
text "攻击力[npc_gong]{space=30}"
vbox:
text "防御力[gamer_fang]{space=30}"
text "防御力[npc_fang]{space=30}"
vbox:
xycenter(0.07,0.5)
# 点击按钮,显示各种行为的具体行为
textbutton "{size=40}攻击":
# 控制按钮的选择,如果不使用会导致玩家可以打开多个界面
if xuanz == 0 or xuanz == 1:
# 将其他按钮锁定,并临时打开一个界面
action [SetVariable("xuanz",1),ShowTransient("gongji")]
textbutton "{size=40}防御":
if xuanz == 0 or xuanz == 2:
action [SetVariable("xuanz",2),ShowTransient("fangyu")]
textbutton "{size=40}治疗":
if xuanz == 0 or xuanz == 3:
action [SetVariable("xuanz",3),ShowTransient("zhiliao")]
screen gongji():
# 攻击行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
textbutton "{size=50}削韧型攻击":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0), # 让所有按钮都可以选择
SetVariable("zhandou_time",zhandou_time+1), # 使战斗回合数+1
Jump("jisuan_削韧型攻击"), # 跳到该行为的计算过程
Hide("gongji")] # 关闭当前界面
# 让所有按钮都可以选择,并关闭当前界面
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("gongji")]
# 之后的内容就都是类似的了
screen fangyu():
# 防御行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
# 如果防御大于等于上限时就无法使用
if gamer_fang < gamer_fang_max:
textbutton "{size=50}常规型防御":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0),
SetVariable("zhandou_time",zhandou_time+1),
Jump("jisuan_常规型防御"),
Hide("fangyu")]
elif gamer_fang >= gamer_fang_max:
text "{size=50}{i}防御已达到最大值":
xycenter(0.5,0.5)
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("fangyu")]
screen zhiliao():
# 治疗行为的界面
frame:
xycenter(0.5,0.83)
xysize(1080,300)
# 如果血量大于等于上限时就无法使用
if gamer_xue < gamer_xue_max:
textbutton "{size=50}防御型治疗":
xycenter(0.15,0.2)
action [SetVariable("xuanz",0),
SetVariable("zhandou_time",zhandou_time+1),
Jump("jisuan_防御型治疗"),
Hide("zhiliao")]
elif gamer_xue >= gamer_xue_max:
text "{size=50}{i}血量已达到最大值":
xycenter(0.5,0.5)
textbutton "返回":
xycenter(0.95,0.9)
action [SetVariable("xuanz",0),Hide("zhiliao")]
# 各类行为的计算过程我写的都有些复杂,如果是第一次尝试可以试着用更简单的计算方法
label jisuan_削韧型攻击:
# “削韧型攻击”的计算过程
if gamer_gong > npc_fang:
# 当玩家攻击力大于敌方防御力时
centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[round((gamer_gong-npc_fang),1)]点的伤害,并造成[round((npc_fang * 0.05),1)]点削韧!{nw=10}"
$ npc_xue = round(npc_xue + (npc_fang - gamer_gong),1)
$ npc_fang = round(npc_fang - (npc_fang * 0.05),1)
elif gamer_gong <= npc_fang:
# 当玩家攻击力小于等于敌方防御力时
centered "{size=80}{color=#BF3512}{b}对[npc_name]造成了[round((npc_fang*0.2),1)]点的削韧!{nw=10}"
$ npc_fang = round(npc_fang - (npc_fang * 0.2),1)
if gamer_gong > npc_fang:
# 当此次攻击使敌方防御力低于玩家攻击力时
centered "{size=80}{color=#BF3512}{b}成功将[npc_name]破韧!{nw=10}"
if npc_xue <= 0:
# 当此次攻击使敌方血量小于等于0时
centered "{size=80}{color=#BF3512}{b}[npc_name]已经被你击败!{nw=10}"
return
# 玩家行动回合结束,跳转到敌方的行动回合
jump npc_jisuan
label jisuan_常规型防御:
centered "{size=80}{color=#BF3512}{b}回复了[round((gamer_fang*0.2 + gamer_fang_max*0.1),1)]点防御值!{nw=10}"
$ gamer_fang = round(gamer_fang + (gamer_fang*0.2 + gamer_fang_max*0.1),1)
if gamer_fang > gamer_fang_max:
# 当此次回复后的防御力高于上限时,将防御力等于上限
$ gamer_fang = gamer_fang_max
jump npc_jisuan
label jisuan_防御型治疗:
centered "{size=80}{color=#BF3512}{b}回复了[round(gamer_xue_max * 0.05 + gamer_xue * 0.05)]点的血量和[round(gamer_xue * 0.01 + gamer_xue_max * 0.01)]点防御!{nw=10}"
$ gamer_xue = round(gamer_xue + gamer_xue_max * 0.05 + gamer_xue * 0.05)
$ gamer_fang = round(gamer_fang + gamer_xue * 0.01 + gamer_xue_max * 0.01)
if gamer_fang > gamer_fang_max:
# 当此次回复后的血量高于上限时,将血量等于上限
$ gamer_fang = gamer_fang_max
jump npc_jisuan
label npc_jisuan:
# 敌方行为的计算过程
"接下来是[npc_name]的行动回合!"
if npc_gong > gamer_fang:
# 敌方攻击力高于玩家防御力时
centered "{size=80}{color=#BF3512}{b}[npc_name]对你造成了[round((npc_gong - gamer_fang),1)]点的伤害,并造成[round((gamer_fang * 0.05),1)]点削韧!{nw=10}"
$ gamer_xue = round(gamer_xue + (gamer_fang - npc_gong),1)
$ gamer_fang = round(gamer_fang - (gamer_fang * 0.05),1)
elif npc_gong <= gamer_fang:
# 敌方攻击力小于等于玩家防御力时
centered "{size=80}{color=#BF3512}{b}[npc_name]对你造成了[round((npc_fang * 0.2),1)]点的削韧!{nw=10}"
$ gamer_fang = round(gamer_fang - (gamer_fang * 0.2),1)
if npc_gong > gamer_fang:
centered "{size=80}{color=#BF3512}{b}你被绿成功破韧!{nw=10}"
if gamer_xue <= 0:
# 玩家血量归零时
centered "{size=80}{color=#BF3512}{b}菜!{nw=10}"
return
else:
# 敌方行动回合结束,回到玩家的行动回合
call screen zhandou
NEXT
这样,回合制战斗系统的基本功能就算是完成了,让我们运行试试——
[RenPy] 纯文本查看 复制代码 label start:
python:
quick_menu = False # 将快捷菜单栏隐藏
npc_name = "绿" # 将敌方名字重命名
npc_xue = 300.00 # 初始化敌方血量
npc_gong = 110.00 # 初始化敌方攻击力
npc_fang = 150.00 # 初始化敌方防御力
call screen zhandou # 跳转到回合制系统
回合制战斗系统
完美运行!(因为图片大小不能超过500KB所以会有点糊)
细心的小伙伴可能早就发现了,“楼主楼主,这个NO.2里写的[persistent.gamer_name]是什么啊?”
这个是我写的一个可以让玩家自己命名的代码,使用到了持久化数据:持久化数据 — Ren'Py 中文文档 (renpy.cn)
这里就当做“赠品”教给各位了:
[RenPy] 纯文本查看 复制代码 default persistent.gamer_name = ""
# 让玩家自定义角色名字
screen input_screen():
vbox:
xycenter(0.5,0.5)
text "请告诉我你的名字(最多15字符)":
xcenter 0.5
frame:
xcenter 0.5
ycenter 0.5
xsize 520
ysize 60
input:
value VariableInputValue("persistent.gamer_name")
xycenter(0.5,0.5)
default "请输入你的名字"
length 15
pixel_width 520
copypaste True
frame:
xcenter 0.5
ycenter 0.6
xsize 100
ysize 75
textbutton "确定":
if persistent.gamer_name != "":
action Return()
define gamer = Character(
"[persistent.gamer_name]",
what_prefix = "“",
what_suffix = "”"
)
[RenPy] 纯文本查看 复制代码 label start:
$ persistent._clear(progress=False) # 为了做测试,每次运行前都会将所有持久化数据清除,在正式作品中需要将其注释掉
if persistent.gamer_name == "":
call screen input_screen
else:
pass
当然,这个回合制战斗系统的逻辑并不一定只能在回合制战斗上进行,其他的RPG游戏系统中一样可以使用。
而且因为本篇教程是为了照顾萌新,所以很多内容写的都比较繁琐,能够优化的空间依旧是肉眼可见,但这就需要用到def和class等python相关内容了,因此就没有这么做,如果有能人异士愿意优化,那我将感激不尽!
还有,如果本篇教程中出现了错误,欢迎指出纠正!
还有,还有!教程中使用的素材图片均来源于网络,切勿随便使用!
至于下一篇教程会到什么时候出……咳咳,还是不立flag了,希望各位用的高兴!
|
评分
-
查看全部评分
|