《魔塔》》是一种策略类的固定数值RPG游戏。 本篇主要讨论红塔游戏,侧重于路线的寻找。
一般RPG类游戏可以使用脚本语言来编写任务剧情,这样可以使得剧情更复杂和灵活多变,这同样适用于魔塔游戏。但是为了自动生成关卡的目的,还是使用数据驱动的方法来实现游戏逻辑,这样方便编写搜索算法。
游戏关卡的设计一般可以使用编辑器来编辑,编辑器很好实现,但要设计一个耐玩的关卡似乎不太简单,后面会做一些自动生成的尝试。
参考“魔塔吧”,网站WDMOTA
在讨论自动生成关卡之前,先来复刻一版现成的魔塔游戏。这里选择胖老鼠的21层魔塔,
这一版魔塔相对简单:楼层数少、迷宫不复杂、没有坑人的机关、商店不会涨价,因此更容易编写自动生成的算法。
游戏剧情
前来拯救公主的勇者在魔塔醒来后遇到了仙子,仙子告诉他他被魔塔的小怪打晕了,是自己将他救了出来。仙子让勇者去找一个十字架,这样仙子可以把自己的力量借给勇者。仙子给了勇者三把钥匙后,勇者就出发了。
勇者在4层找到了一个小偷,小偷答应帮助勇者,于是勇者请求小偷为自己开2层的门,小偷答应了,并告诉勇者如果找到了镶有红宝石的铁榔头,他可以为勇者打开18层的路。
勇者在16层遇见了魔王和神秘老人(若在规定时间内未到达16层,则老人不会出现),神秘老人将神秘宝物交给勇者,让他交给仙子。仙子告诉勇者这个宝物叫“灵智障灵之杖”,勇者现在拿着的是“冰之灵杖”。灵杖总共有三把,另外两把是“心之灵杖”和“炎之灵杖”,三灵杖是封印地下层的血影的钥匙。
勇者回到16层打败魔王,然后将12层的榔头交给4层的小偷,18层救公主的通道打开了。公主说勇者必须杀死恶魔自己才愿意走,与公主对话后通往19层的楼梯开启。
勇者在19层击败冥灵魔王,冥灵魔王逃到21层。勇者来到20层后,发现没有上楼的楼梯了,之后将7层的十字架交给仙子,仙子将勇者所有能力值提高1/3。
勇者来到21层击败了冥灵魔王,来到22层找到仙子,仙子让勇者找齐另外两个灵杖。勇者收集三个魔杖后与仙子对话,然后从23层的花门进入地下层杀死血影。(若未带着三个权杖与仙子对话,则地下层出现的怪物是魔龙,正常情况下无法击败)打败血影后,勇者救出公主离开魔塔。
自动生成关卡的思路:
方案一
1,先生成迷宫。
2,摆放楼梯、门、怪物、NPC、商店等。一般每层两个楼梯(可连通),若干层一个商店,若干层一对商人,每层一到两个NPC就可以了,怪物的分布等级低的出现在较低楼层。
3,最后摆放道具。通过摆放奖励道具来控制引导行进路线的复杂性,因为直接往后走是无法通关的,玩家必须按一定顺序获取道具,才能保证最后通关。
4,通过算法给生成的关卡评分,如果不够好则重新生成,或许也可以试试用遗传算法对关卡做一些改动。
如何判别一个关卡的好坏:
1,对关卡进行搜索模拟角色行进路线,路线不能太简单,如果有很多的道具都没有走到直接就通关了,无疑是一个很糟的关卡。
2,路线必须要可以走到底,不能是一个不可完成的关卡。
3,游戏需要一定难度,即玩家如果选择的路线不对会出现卡关,玩家行走的路线要有一定的曲折。
搜索算法:
将生成的地图变成稀疏图的结构以便于搜索。 商店节点要挂上所出售的商品节点,NPC节点要挂上奖励的物品节点。图的变动搜索,根据角色属性不同,图节点之间的路径是否可通也是不断变化的。
//搜索深度太大,和地图上所有非空节点数差不多,有的节点还要访问多次。深度可能达到数千。
//随着步数的深入,可选的下一步节点集迅速增大, 这已经是一个np难题了。 大约是不可能完成的任务,必须做优化处理。
//在访问并清除一个节点时将其邻节点加入前锋边,在搜索失败回退时要同时回退n个邻节点。
//剪枝方法,当节点集中出现奖励物品时,可以优先访问。当商店节点打通后,会优先频繁访问商店。采用分阶段的方法减少搜索深度,避免出现太大的节点集。
方案二,直接算法生成,避免耗时的搜索算法。先生成路径,先考虑最简单的情况,一张大图,没有楼梯口(楼梯口可以最后将大图切割成小的楼层时再添加),也先不考虑npc和商店。
定好主角在每个阶段的属性值,根据属性值是可以倒推出怪物和奖励道具的。
//先生成迷宫大地图,分割路径为一段段的小胡同,计算胡同邻接关系,使用随机算法遍历胡同,根据遍历顺序生成到达胡同末端时的战力值,
//因为战力值的限制,玩家游戏时只能按照遍历顺序清关,否则会卡关失败
//然后根据起点和终点战力值在每条胡同上布置怪物和奖励
另外对于魔塔游戏一般会有一些漏洞。尽快到达商店是玩家主选策略,因为打通商店后玩家就可以及时更新自身属性了,这样优势累积越来越大。到了后期主角属性可以相差很大,平衡已经不太好控制了。所以可以考虑分阶段规整角色属性,使得累积优势变小,重新开始新阶段的关卡。
数据配置:
怪物
id112001,"史莱姆", "monster_01.png",life50, force20, defend1, money1, exp1,
id112002,"中史莱姆", "monster_02.png",life70, force15, defend2, money2, exp1,
id112003,"大史莱姆", "monster_03.png",life200, force35, defend10, money5, exp3,
id112004,"史莱姆王", "monster_04.png",life700, force250, defend125, money32, exp30,
id112005,"小蝙蝠", "monster_05.png",life100, force20, defend5, money3, exp2,
id112006,"大蝙蝠", "monster_06.png",life150, force65, defend30, money10, exp8,
id112007,"吸血蝙蝠", "monster_07.png",life550, force160, defend90, money25, exp20,
id112008,"冥灵魔王", "monster_08.png",life33333, force2000, defend1600, money375,exp300,
id112009,"骷髅兵", "monster_09.png",life110, force25, defend5, money5, exp8,
id112010,"小魔法师", "monster_10.png",life250, force120, defend70, money20, exp17,
id112011,"大魔法师", "monster_11.png",life500, force400, defend260, money47, exp45,
id112012,"大护法", "monster_12.png",life450, force150, defend90, money22, exp19,
id112013,"骷髅队长", "monster_13.png",life140, force40, defend20, money8, exp5,
id112014,"骷髅王", "monster_14.png",life400, force90, defend50, money15, exp12,
id112015,"骷髅王后", "monster_15.png",life3333, force1200, defend1133, money126,exp112,
id112016,"半兽人", "monster_16.png",life300, force75, defend45, money13, exp10,
id112017,"兽人王", "monster_17.png",life900, force450, defend330, money50, exp50,
id112018,"石怪", "monster_18.png",life500, force115, defend65, money15, exp15,
id112019,"Pilgrim", "monster_19.png",life3100, force1150, defend1050, money92, exp80,
id112020,"蓝袍法师", "monster_20.png",life125, force50, defend25, money10, exp7,
id112021,"红袍法师", "monster_21.png",life100, force200, defend110, money30, exp25,
id112022,"小护法", "monster_22.png",life1250, force500, defend400, money55, exp55,
id112023,"牛头护法", "monster_23.png",life1500, force560, defend460, money60, exp60,
id112024,"双刀鬼士", "monster_24.png",life120, force620, defend520, money65, exp75,
id112025,"铠甲魔", "monster_25.png",life2000, force680, defend590, money70, exp65,
id112026,"骑士", "monster_26.png",life850, force350, defend200, money45, exp40,
id112027,"骑士队长", "monster_27.png",life900, force750, defend650, money77, exp70,
id112028,"幽灵骑士", "monster_28.png",life1600, force1306, defend1200, money132,exp112,
id112029,"红衣魔王", "monster_29.png",life15000, force1500, defend1400, money100,exp100,
id112030,"邪魔", "monster_30.png",life1300, force300, defend150, money40, exp35,
id112031,"幽灵法师", "monster_31.png",life2000, force1106, defend973, money120,exp105,
道具
"",
46,
id113001,"红色钥匙", "", "data/minigame/magictower/key_01.png", "", persent0, life0, force0, defend0, money0, exp0, lev0, redKey1, yellowKey0, blueKey0,
id113002,"黄色钥匙", "", "data/minigame/magictower/key_02.png", "", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey1, blueKey0,
id113003,"蓝色钥匙", "", "data/minigame/magictower/key_03.png", "", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey1,
id113004,"红色门", "", "data/minigame/magictower/door_01.png", "data/minigame/magictower/door_01", persent0, life0, force0, defend0, money0, exp0, lev0, redKey-1, yellowKey0, blueKey0,
id113005,"黄色门", "", "data/minigame/magictower/door_02.png", "data/minigame/magictower/door_02", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey-1, blueKey0,
id113006,"蓝色门", "", "data/minigame/magictower/door_03.png", "data/minigame/magictower/door_03", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey-1,
id113007,"红色门", "", "data/minigame/magictower/door_04.png", "data/minigame/magictower/door_04", persent0, life0, force0, defend0, money0, exp0, lev0, redKey-1, yellowKey0, blueKey0,
id113008,"黄色门", "", "data/minigame/magictower/door_05.png", "data/minigame/magictower/door_05", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey-1, blueKey0,
id113009,"蓝色门", "", "data/minigame/magictower/door_06.png", "data/minigame/magictower/door_06", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey-1,
id113010,"铁门", "", "data/minigame/magictower/door_07.png", "data/minigame/magictower/door_07", persent0, life0, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113011,"血瓶", "", "data/minigame/magictower/item_05.png", "", persent0, life200, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113012,"蓝瓶", "", "data/minigame/magictower/item_06.png", "", persent0, life500, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113013,"红宝石", "", "data/minigame/magictower/item_01.png", "", persent0, life0, force3, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113014,"蓝宝石", "", "data/minigame/magictower/item_02.png", "", persent0, life0, force0, defend3, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113015,"碧灵神剑", "得到碧灵神剑,攻击+150", "data/minigame/magictower/item_61.png", "", persent0, life0, force150, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113016,"玄武铁盾", "得到玄武铁盾,防御+190", "data/minigame/magictower/item_85.png", "", persent0, life0, force0, defend190, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113017,"铁剑", "获得铁剑,攻击+10", "data/minigame/magictower/item_49.png", "", persent0, life0, force10, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113018,"铁盾", "获得铁盾,防御+10", "data/minigame/magictower/item_73.png", "", persent0, life0, force0, defend10, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113019,"金币", "得到金钱$200", "data/minigame/magictower/item_63.png", "", persent0, life0, force0, defend0, money200, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113020,"青锋剑", "得到青锋剑,攻击力+70", "data/minigame/magictower/item_51.png", "", persent0, life0, force70, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113021,"黄金盾", "得到黄金盾,防御力+55", "data/minigame/magictower/item_75.png", "", persent0, life0, force0, defend55, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113022,"升级羽毛", "得到升级羽毛,等级提高1级", "data/minigame/magictower/item_21.png", "", persent0, life0, force0, defend0, money0, exp0, lev1, redKey0, yellowKey0, blueKey0,
id113023,"寒鸦羽", "得到寒鸦羽,等级提高三级", "data/minigame/magictower/item_22.png", "", persent0, life0, force0, defend0, money0, exp0, lev3, redKey0, yellowKey0, blueKey0,
id113024,"千年玉露", "得到千年玉露,生命提高一倍", "data/minigame/magictower/item_40.png", "", persent1, life1, force0, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113500,"奖励", "得到三种钥匙各一把!", ".png", "", persent0, life0, force0, defend3, money0, exp0, lev0, redKey1, yellowKey1, blueKey1,
id113501,"奖励", "能力上升,生命+4000,攻击+200,防御+200!", ".png", "", persent0, life4000, force200, defend200, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113502,"奖励", "得到铠甲衣,防御+55!", ".png", "", persent0, life0, force0, defend55, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113503,"奖励", "得到钢剑,攻击+55!", ".png", "", persent0, life0, force55, defend0, money0, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113800,"商品", "800点生命/$25", ".png", "", persent0, life800, force0, defend0, money-25, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113801,"商品", "4点攻击/$25", ".png", "", persent0, life0, force4, defend0, money-25, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113802,"商品", "4点防御/$25", ".png", "", persent0, life0, force0, defend4, money-25, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113803,"商品", "提升一级/100点", ".png", "", persent0, life0, force0, defend0, money0, exp-100, lev1, redKey0, yellowKey0, blueKey0,
id113804,"商品", "4点攻击/30点", ".png", "", persent0, life0, force4, defend0, money0, exp-30, lev0, redKey0, yellowKey0, blueKey0,
id113805,"商品", "4点防御/30点", ".png", "", persent0, life0, force0, defend4, money0, exp-30, lev0, redKey0, yellowKey0, blueKey0,
id113806,"商品", "1把黄钥匙/$10", ".png", "", persent0, life0, force0, defend0, money-10, exp0, lev0, redKey0, yellowKey1, blueKey0,
id113807,"商品", "1把蓝钥匙/$50", ".png", "", persent0, life0, force0, defend0, money-50, exp0, lev0, redKey0, yellowKey0, blueKey1,
id113808,"商品", "1把红钥匙/$100", ".png", "", persent0, life0, force0, defend0, money-100, exp0, lev0, redKey1, yellowKey0, blueKey0,
id113809,"商品", "4000点生命/$100", ".png", "", persent0, life4000, force0, defend0, money-100, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113810,"商品", "20点攻击/$100", ".png", "", persent0, life0, force20, defend0, money-100, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113811,"商品", "20点防御/$100", ".png", "", persent0, life0, force0, defend20, money-100, exp0, lev0, redKey0, yellowKey0, blueKey0,
id113812,"商品", "卖一把黄钥匙/$7", ".png", "", persent0, life0, force0, defend0, money7, exp0, lev0, redKey0, yellowKey-1, blueKey0,
id113813,"商品", "卖一把蓝钥匙/$35", ".png", "", persent0, life0, force0, defend0, money35, exp0, lev0, redKey0, yellowKey0, blueKey-1,
id113814,"商品", "卖一把红钥匙/$70", ".png", "", persent0, life0, force0, defend0, money70, exp0, lev0, redKey-1, yellowKey0, blueKey0,
id113815,"商品", "提升三级/270点", ".png", "", persent0, life0, force0, defend0, money0, exp-270, lev3, redKey0, yellowKey0, blueKey0,
id113816,"商品", "增加攻击17/95点", ".png", "", persent0, life0, force17, defend0, money0, exp-95, lev0, redKey0, yellowKey0, blueKey0,
id113817,"商品", "增加防御17/95点", ".png", "", persent0, life0, force0, defend17, money0, exp-95, lev0, redKey0, yellowKey0, blueKey0,
"success",
NPC
通过改变NPC的talkindex来控制剧情走向,NPC在说完一句话后会执行用 [ ] 括起来的一段命令,命令可以认为是基于行为模板的。比如[break 20]表示npc说道第20句对白后将结束对话,并且下次对话从第20句开始。 比如[npctalkindex 115001,21]会改变115001号npc的对话索引到21,那么该NPC的下次对话将从第21句开始。
"",
17,
id115001,"仙子", "data/minigame/magictower/npc_04.png", bitem0,
talknum24,talkindex0
0 , time-1, [null], "\c4仙子:\n\c0 勇士——,勇士——,快醒醒!",
1 , time-1, [null], "\c4勇士:\n\c0 唔......头好痛 ......",
2 , time-1, [null], "\c4仙子:\n\c0 勇士你终于醒啦!O(∩_∩)O~",
3 , time-1, [null], "\c4勇士:\n\c0 ......,你是谁,我在哪里?",
4 , time-1, [null], "\c4仙子:\n\c0 我是这里的守护者——蝴蝶仙子,你是来救公主的吧!",
5 , time-1, [null], "\c4勇士:\n\c0 是的,你知道公主现在在哪里吗?",
6 , time-1, [null], "\c4仙子:\n\c0 公主被怪物抓到塔里去了.....",
7 , time-1, [null], "\c4勇士:\n\c0 啊,那公主不是有危险吗,我要进去救公主...唔...!",
8 , time-1, [null], "\c4仙子:\n\c0 勇士不要,你这样进去是打不过那些怪物的!",
9 , time-1, [null], "\c4勇士:\n\c0 可是我答应国王要救公主回去的,我不能半途而废!",
10, time-1, [null], "\c4仙子:\n\c0 这样吧我把我的力量给你,不过你要先找到一个镶着宝石的十字架!",
11, time-1, [null], "\c4勇士:\n\c0 十字架?它有什么用?",
12, time-1, [null], "\c4仙子:\n\c0 我本来是这座塔的守护者,半年前,从北方来了一群怪物,他们打伤我...!",
13, time-1, [null], "\c4仙子:\n\c0 他们霸占了塔,到处做坏事并将我的力量封到了那个十字架上...!",
14, time-1, [null], "\c4仙子:\n\c0 有了它,我就能慢慢才能发挥自己的力量,十字架应该在7楼!",
15, time-1, [null], "\c4勇士:\n\c0 仙子,我会拿到的,我一定要救出公主,打败那群可恶的怪物!",
16, time-1, [reward 113500],"\c4仙子:\n\c0 我这里有三把钥匙,塔里面有很多不同颜色的门,需要钥匙才能打开。",
17, time-1, [null], "\c4勇士:\n\c0 那三把钥匙怎么够用啊?.....",
18, time-1, [null], "\c4仙子:\n\c0 里面还有很多这样的钥匙,但是勇士你要合理利用好才行!",
19, time-1, [npcmove -1,-1,0],"\c4勇士:\n\c0 我知道了,那我要进塔了!",
20, time-1, [break 20],"\c4仙子:\n\c0 勇士一定要小心,拿到十字架后就可以交给我了。",
21, time-1, [null], "\c4勇士:\n\c0 仙子我拿到十字架了,你看是不是这个?",
22, time-1, [reward 113501],"\c4仙子:\n\c0 就是这个十字架,勇士谢谢你,现在我就把我的力量给你。",
23, time-1, [null], "\c4仙子:\n\c0 希望你能尽快打败大魔王,记得21层没有准备好不要进去!",
id115002,"关于", "data/minigame/magictower/monster_32.png", bitem0,
talknum4,talkindex0
0 , time-1, [null], "\c4关于:\n\c0 嗨,你好勇士!我是程序的作者,我叫...!",
1 , time-1, [null], "\c4关于:\n\c0 自我介绍完了,同时很高兴认识你,那我们来说一下游戏吧!",
2 , time-1, [null], "\c4关于:\n\c0 勇敢的勇士,是初次玩魔塔吗?如果是,那就请快进入游戏吧!",
3 , time-1, [break 0],"\c4关于:\n\c0 加油,勇士,去拯救你的公主吧!"
id115003,"十字架", "data/minigame/magictower/item_24.png", bitem1,
talknum1,talkindex0
0 , time-1, [npctalkindex 115001,21],"\c4十字架:\n\c0 得到十字架,可以去交给仙子!",
id115004,"小偷", "data/minigame/magictower/npc_03.png", bitem0,
talknum12,talkindex0
0 , time-1, [null], "\c4勇士:\n\c0 你已经得救了,快离开这里吧!",
1 , time-1, [null], "\c4小偷:\n\c0 哇,我又可以在这里寻宝啦,多谢勇士相救。",
2 , time-1, [null], "\c4小偷:\n\c0 我叫无魂,是这里有名的神盗,哎, 一不小心被抓了,那现在你救了我",
3 , time-1, [null], "\c4无魂:\n\c0 那我也帮你做一件事吧,有什么需要我帮忙的吗?",
4 , time-1, [null], "\c4勇士:\n\c0 你还是快走吧,这里怪物太多了,很危险!",
5 , time-1, [null], "\c4无魂:\n\c0 不行的,知恩要图报,我帮了你就会离开。",
6 , time-1, [null], "\c4勇士:\n\c0 那你可以打开第二层的铁门吗?",
7 , time-1, [npcmove 115005,-99,0],"\c4无魂:\n\c0 这个简单,我就帮你打开,噢还有一件事,18层的路被魔王堵住了。",
8 , time-1, [break 8],"\c4无魂:\n\c0 如果你能找到一个水晶榔头,我就能打通18层,找到了记得找我哦。",
9 , time-1, [null], "\c4勇士:\n\c0 无魂,我找到了,是这一把吗?",
10, time-1, [null], "\c4无魂:\n\c0 O(∩_∩)O~,就是这一把,现在我就去打通18层,后会有期哦。"
10, time-1, [setblock 111017,0,10,6001],"\c4无魂:\n\c0 18层已经打通了。"
id115005,"铁门", "data/minigame/magictower/door_07.png", bitem0,
talknum0,talkindex0
id115006,"水晶榔头", "data/minigame/magictower/item_10.png", bitem1,
talknum1,talkindex0
0 , time-1, [npctalkindex 115004,9],"\c4水晶榔头:\n\c0 得到水晶榔头,交给4层的小偷,可打通18层!",
id115007,"上锁的楼梯", "data/minigame/magictower/item_37.png", bitem0,
talknum1,talkindex0
0 , time-1, [npctalkindex 115004,9],"\c4上锁的楼梯:\n\c0 第18层的路尚未打通!",
id115008,"红衣魔王", "data/minigame/magictower/monster_29.png", bitem0,
talknum3,talkindex0
0 , time-1, [null], "\c4红衣魔王:\n\c0 愚蠢的人类,快停止吧,不要再执迷不悟了!",
1 , time-1, [setblock -1,-1,-1,2029],"\c4勇士:\n\c0 该醒悟的是你,快叫你们大王出来受死!",
2 , time-1, [null], "\c4红衣魔王:\n\c0 想见我们魔王,先过我这一关!"
id115009,"公主", "data/minigame/magictower/npc_06.png", bitem0,
talknum7,talkindex0
0 , time-1, [null], "\c4勇士:\n\c0 公主,我终于找到你了,快跟我走吧,这里危险!",
1 , time-1, [null], "\c4公主:\n\c0 你是父王派来救我的吧,可是我不想走,我要你把魔王赶出去。",
2 , time-1, [null], "\c4公主:\n\c0 到那时我再跟你走!",
3 , time-1, [null], "\c4勇士:\n\c0 可是真的很危险啊,公主我怕你受到伤害,还是现在就带你出去吧!",
4 , time-1, [null], "\c4公主:\n\c0 有你保护我,我不会害怕!",
5 , time-1, [null], "\c4勇士:\n\c0 那好吧,公主,记得要躲在我的身后,我会一直保护你的。",
6 , time-1, [setblock -1,-1,-1,6001], "\c4公主:\n\c0 谢谢你,人家知道了。"
id115010,"冥灵魔王分身", "data/minigame/magictower/monster_08.png", bitem0,
talknum4,talkindex0
0 , time-1, [null], "\c4冥灵魔王:\n\c0 有意思,年轻人,你竟然能走到这里,看来是我低估你了!",
1 , time-1, [null], "\c4勇士:\n\c0 你就是魔王吧,为了公主,我要杀了你,把你们赶出去!" ,
2 , time-1, [null], "\c4冥灵魔王:\n\c0 哈哈哈哈!来吧,让我见识一下你的能力!",
3 , time-1, [setblock -1,-1,-1,2008], "\c4冥灵魔王:\n\c0 看来你的能力真的提高了不少,去21层吧,那里才是真正的我!"
id115011,"老爷爷", "data/minigame/magictower/npc_01.png", bitem1,
talknum4,talkindex0
0 , time-1, [null], "\c4勇士:\n\c0 老爷爷你可以走了,妖魔已经被我打死了!",
1 , time-1, [null], "\c4老爷爷:\n\c0 哦,我的孩子,太谢谢你了,你真勇敢,我就把这个给你吧!",
2 , time-1, [null], "\c4老爷爷:\n\c0 这是我年轻时用过了,穿在身上很坚固,孩子,快穿上吧!",
3 , time-1, [reward 113502], "\c4勇士:\n\c0 谢谢老爷爷,你快离开这里吧,这里很危险!",
id115012,"商真人", "data/minigame/magictower/npc_02.png", bitem1,
talknum4,talkindex0
0 , time-1, [null], "\c4勇士:\n\c0 老先生快离开这里吧,已经没妖怪了!",
1 , time-1, [null], "\c4老先生:\n\c0 谢谢你,壮士,我叫商真人,一直经商,为了回报你,这把剑给你!",
2 , time-1, [null], "\c4商真人:\n\c0 壮士,你一定要小心,这里的怪物很残暴!"
3 , time-1, [reward 113503], "\c4勇士:\n\c0 谢谢商先生,你路上也要小心!"
id115013,"风信子", "data/minigame/magictower/item_11.png", bitem1,
talknum1,talkindex0
0 , time-1, [reward -1], "\n\c0 得到风信子,按[W]可以任意穿梭楼层!",
id115014,"怪物属性表", "data/minigame/magictower/item_35.png", bitem1,
talknum1,talkindex0
0 , time-1, [reward -2], "\n\c0 获得怪物属性表,点击[Q]查看或关闭!",
id115015,"经验老人", "data/minigame/magictower/npc_01.png", bitem1,
talknum4,talkindex0
0 , time-1, [null], "\c4经验老人:\n\c0 勇敢的年轻人,你终于来了,我在这里等了好久了,为了能尽快打败魔王,我找到一把上古神剑,如果你愿意用500点经验和我交换,可以使你的攻击增加120,那么你愿意交换吗?",
1 , time-1, [null], "\c4经验老人:\n\c0 经验不足,等等再来吧!",
2 , time-1, [null], "\c4经验老人:\n\c0 获得月光神剑,攻击+120!",
3 , time-1, [reward 113502], "\c4经验老人:\n\c0 获得月光神剑,攻击+120!",
id115016,"大商人", "data/minigame/magictower/npc_02.png", bitem1,
talknum4,talkindex0
0 , time-1, [null], "\c4大商人:\n\c0 勇士我这里有一件很好的盾可以增加防御120,为了帮助你尽快打败打败魔王,只要你有500金币,我就把它送给你,你愿意花500金币来和我交换吗?",
1 , time-1, [null], "\c4大商人:\n\c0 金币不足,等等再来吧!",
2 , time-1, [null], "\c4大商人:\n\c0 获得月光神盾,防御+120!"
3 , time-1, [reward 113503], "\c4大商人:\n\c0 获得月光神盾,防御+120!"
id115999,"终了", "data/minigame/magictower/npc_06.png", bitem1,
talknum1,talkindex0
0 , time-1, [null], "\n\c0 历尽千辛万苦\n方救得公主\n因为心中朦胧的感觉\n不畏险阻\n \n听过千叮万嘱\n才收获有无\n只因自己平凡的思想\n哪懂踌躇\n| | 终",
"success",
reward: -1楼层穿梭器 -2怪物属性表
商店略
地图
"",
23,
id111000,"序章", "data/minigame/magictower/road_1.png", size{11,11,}, entryUP{160,288,}, entryDown{160,32,},
4007, 4014, 4014, 4014, 4014, 6001, 4014, 4014, 4014, 4014, 4007,
4007, 4014, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4014, 4007,
4007, 4014, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4014, 4007,
4007, 4014, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4014, 4007,
4007, 4014, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4014, 4007,
4007, 4014, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4014, 4007,
4007, 4007, 4014, 4014, 4014, -1, 4014, 4014, 4014, 4007, 4007,
4007, 4007, 4007, 4007, 4007, 3005, 4007, 4007, 4007, 4007, 4007,
-1, 4007, -1, 4007, -1, 5001, -1, 4007, -1, 4007, 5002,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4007, 4007, 4007, 4007, 4007, -1, 4007, 4007, 4007, 4007, 4007,
id111001,"第1层", "data/minigame/magictower/road_1.png", size{11,11,}, entryUP{160,288,}, entryDown{32,0,},
6001, -1, 3002, 2001, 2002, 2001, -1, -1, -1, -1, -1,
4007, 4007, 4007, 4007, 4007, 4007, 4007, 4007, 4007, 4007, -1,
3011, -1, 2009, 3005, -1, 4007, 3011, 3002, 3011, 4007, -1,
3002, 2009, 3013, 4007, -1, 4007, 3011, 3002, 3011, 4007, -1,
4007, 3005, 4007, 4007, -1, 4007, 4007, 4007, 2003, 4007, -1,
3002, 2013, -1, 4007, -1, 3005, 2020, 2001, 2005, 4007, -1,
3014, -1, 3003, 4007, -1, 4007, 4007, 4007, 4007, 4007, -1,
4007, 3005, 4007, 4007, -1, -1, -1, -1, -1, -1, -1,
-1, 2013, -1, 4007, 4007, 3004, 4007, 4007, 4007, 3005, 4007,
3011, 3012, 3002, 4007, 3001, -1, -1, 4007, 3002, 2016, 3003,
3011, 5014, 3002, 4007, -1, 6002, -1, 4007, 3002, 3002, 3002,
id111002,"第2层", "data/minigame/magictower/road_1.png", size{11,11,}, entryUP{0,32,}, entryDown{0,288,},
6002, 4007, -1, 2027, -1, 4007, 3013, 3014, 3002, 3001, 4007,
-1, 4007, 3014, 4007, 3012, 4007, 3013, 3014, 3002, 3003, 4007,
-1, 4007, 3002, 4007, 3002, 4007, 3013, 3014, 3002, 2026, 4007,
-1, 4007, 3002, 4007, 3002, 4007, 4007, 4007, 4007, 3005, 4007,
-1, 4007, -1, 4007, -1, -1, -1, 3005, -1, -1, 4007,
-1, 4007, 3005, 4007, 4007, 3005, 4007, 4007, 3005, 4007, 4007,
-1, 5005, -1, -1, -1, -1, 4007, -1, 2026, -1, 4007,
-1, 4007, 3005, 4007, 4007, 3006, 4007, 3010, 4007, 3010, 4007,
-1, 4007, 3002, 4007, 3012, 3011, 4007, -1, 4007, -1, 4007,
-1, 4007, 3002, 4007, 3012, 3011, 4007, -1, 4007, -1, 4007,
6001, 4007, 3013, 4007, 3012, 3011, 4007, 5011, 4007, 5012, 4007,
id111003,"第3层", "data/minigame/magictower/road_1.png", size{11,11,}, entryUP{32,320,}, entryDown{320,288,},
3017, 2002, 3002, 4007, 7001, 7002, 7003, 4007, 4007, 4007, 4007,
2002, 3002, -1, 4007, -1, -1, -1, 4007, -1, 2005, -1,
3002, 2009, -1, 4007, 4007, 3005, 4007, 4007, -1, 4007, -1,
4007, 3005, 4007, 4007, -1, 2009, -1, 4007, 3002, 4007, 2002,
-1, -1, -1, 4007, 4007, 4007, -1, 4007, 3002, 4007, 2005,
2001, 4007, -1, 2005, 2002, 2005, -1, 4007, 3002, 4007, 2002,
2001, 4007, 4007, 4007, 4007, 4007, -1, -1, -1, 4007, -1,
-1, -1, -1, -1, -1, 4007, 4007, 3005, 4007, 4007, -1,
4007, 4007, 4007, 4007, 2005, 4007, 2002, -1, 2002, 4007, -1,
4007, -1, -1, -1, -1, 4007, 3014, 2005, 3002, 4007, -1,
6002, -1, 4007, 4007, 4007, 4007, 3013, 3012, 3002, 4007, 6001,
游戏源码:
配置数据结构
#ifndef __TowerMap__H__
#define __TowerMap__H__
#include "Math/MathLib.h"
#include "AI/Entity/GameStyle.h"
#include "General/String.h"
#include "Render/Texture.h"
enum TowerBlock
{
TB_UpStairs = 116001,//楼梯
TB_DownStairs = 116002,
TB_WallMin = 114000, //墙
//TB_WallMax = 114999, //
//TB_ItemMin = 113000, //道具
//TB_ItemMax = 113999, //
TB_GhostMin = 112000,//怪物
TB_GhostMax = 112999,
};
class MTStyle:public Style
{
public:
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
//默认的路图片
String m_textureName;
TexturePtr m_texture;
};
class MTWallStyle:public MTStyle
{
public:
DeclareStyleEnum(MTWallStyle ,114001);
MTWallStyle();
~MTWallStyle();
bool Load( File& file );
bool Save( File& file );
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
public:
int m_walkAble;
};
class MTItemStyle:public MTStyle
{
public:
DeclareStyleEnum(MTItemStyle ,113001);
MTItemStyle();
~MTItemStyle();
bool Load( File& file );
bool Save( File& file );
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
String m_anim;//拾取或开门动画
bool m_bPersent;
int m_life ;
int m_force ;
int m_defense;
int m_exp ;
int m_money ;
int m_level ;
int m_yellowKeyNum;
int m_blueKeyNum ;
int m_redKeyNum ;
TexturePtr m_textureAnim[3];
};
class MTGhostStyle:public MTStyle
{
public:
DeclareStyleEnum(MTGhostStyle ,112001);
MTGhostStyle();
~MTGhostStyle();
bool Load( File& file );
bool Save( File& file );
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
int m_life ;
int m_force ;
int m_defense;
int m_exp ;
int m_money ;
int m_level ;
};
class MTNpcStyle:public MTStyle
{
public:
DeclareStyleEnum(MTNpcStyle ,115001);
MTNpcStyle();
~MTNpcStyle();
bool Load( File& file );
bool Save( File& file );
enum TalkAction
{
TA_Null = 0,
TA_Reward = 1, //parm itemid
TA_NpcTalkIndex = 2, //parm npcid,talkindex
TA_Break = 3, //parm: thistalkindex
TA_NpcMove = 4, //parm: npcid offx offy
TA_SetBlock = 5, //parm: floor x y block
TA_StairUp = 6, //parm:
TA_StairDown = 7, //parm:
TA_Transport = 8, //parm: floor
};
static const char* TalkActionToString(int enumeration);
static bool StringToTalkAction(const char* str,int& type);
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
class Talk
{
public:
String words;
TalkAction action;
int parm1,parm2,parm3,parm4;
float time;//到时间自动切换下一句
};
bool bitem; //一次性npc,或者叫作任务物品
Talk* talks;
int talkNum;
int talkIndex;
};
//TB_UpStairs = 6001,//楼梯
class MTShopStyle:public MTStyle
{
public:
DeclareStyleEnum(MTShopStyle ,117001);
MTShopStyle();
~MTShopStyle();
bool Load( File& file );
bool Save( File& file );
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
int itemNum;
int* items;
};
class MTMapStyle:public MTStyle
{
public:
DeclareStyleEnum(MTMapStyle ,111001);
class Block
{
public:
MTStyle* style;
int block;
};
MTMapStyle();
~MTMapStyle();
bool Load( File& file );
bool Save( File& file );
#ifdef CLIENT_APP
virtual void UpdateAllItems(ListItemUpdater& updater);
#endif
int Clear();
void Render();
void RendToTexture(TextureData& image);
Block* GetBlock(const vec2I& pos);
void SetBlock(const vec2I& pos,int block);
bool IsOut(const vec2I& pos);
vec2I m_size;
vec2I m_entryUP;
vec2I m_entryDown;
Block* m_blocks;
//默认的路图片
String m_roadTexName;
TexturePtr m_texRoad;
};
#endif
游戏类:
#ifndef __MiniGameMine__H__
#define __MiniGameMine__H__
#include "Rpg/MiniGame.h"
#include "Render/Texture.h"
#include "MagicTower/MagicTowerMap.h"
class GuiGroupCtrl;
class MiniGameMagicTower:public MiniGame
{
public:
MiniGameMagicTower();
virtual ~MiniGameMagicTower();
public:
virtual bool Start();
virtual bool Stop();
virtual bool Render();
virtual void RenderUI();
virtual bool Update();
virtual bool Free();
virtual bool KeepResource(bool once,int& circle,String& nextTip);
//三种类型结构
virtual MiniPlayer* CreatePlayer();
virtual MiniPlayer* CreateRobot ();
virtual MiniPlayer* CreateRole ();
void Update_Running();
void Update_Talking();
void Update_Fighting();
void Update_Shopping();
void Update_Messaging();
void Transport(int floor);
bool CanBuy(MTItemStyle* item);
void OnSave();
void OnLoad();
//[0~max]
MTMapStyle* GetMap(int floor);
void OpenDoor(MTItemStyle* door);
void MoveNpc(int npcId,const vec2I& mov);
void ShowMsg(int x, int y, const char* msg);
void ShowNotice(const char* msg);
void TextAtPos_(const vec2& pos, const char* txt);
void DoUp();
void DoDown();
//对话界面
void PopTalking(const vec2I& npcpos, MTNpcStyle* who);
//商城界面
void PopShopping(const vec2I& shoppos,MTShopStyle* who);
//战斗界面
void PopFighting();
//怪物图鉴界面
void PopViewBook();
//传送界面
void PopTransporting();
enum GameState
{
GS_Starting,
GS_Running,
GS_Talking,
GS_Fighting,
GS_Shopping,
GS_Transporting,
GS_Viewing,
GS_Message,
GS_OpeningDoor,
};
GameState m_GameState;
String m_message;
String m_notice;
float m_noticeTime;
//protected:
MTMapStyle* m_curMap;
int m_curFloor; //楼层,从0开始
int m_enterMaxFloor; //记录最大的进入层数,方便风信子的程序
MTNpcStyle* m_talkingNpc;
float m_talkingTime;
vec2I m_talkingNpcPos;
MTGhostStyle* m_fightingGhost;
float m_fightingTime;
int m_fightingGhostLife;
MTShopStyle* m_shoppingNpc;
vec2I m_shopPos;
RectF m_talkWindowRect;
RectF m_windowRect;
MTItemStyle* m_openingDoor;
float m_openingDoorTime;
vec2I m_openingDoorPos;
//楼层穿梭器
bool m_transportLock;
//怪物图鉴
bool m_handBookLock;
TexturePtr m_texViewingBack;
TexturePtr m_texRole;
};
extern MiniGameMagicTower* G_MagicTowerGame;
#endif
#include "General/Pch.h"
#include "General/StringUtil.h"
#include "General/Window.h"
#include "General/Timer.h"
#include "General/File.h"
#include "MagicTower/MagicTowerPlayer.h"
#include "MagicTower/MiniGameMagicTower.h"
#include "MagicTower/MiMagicTower_PlayGui.h"
#include "Render/RendDriver.h"
#include "Render/Font.h"
#include "Input/InputMgr.h"
#include "Render/Camera.h"
#include "Gui/GuiMgr.h"
#include "Gui/GuiFrame.h"
#include "Gui/GuiControlMisc.h"
#include "General/Pce.h"
MiniGameMagicTower* G_MagicTowerGame = NULL;
MiniGameMagicTower::MiniGameMagicTower()
{
G_MagicTowerGame = this;
}
MiniGameMagicTower::~MiniGameMagicTower()
{
G_MagicTowerGame = NULL;
}
bool MiniGameMagicTower::Start()
{
if(!MiniGame::Start())
return false;
m_talkingNpc = NULL;
m_fightingGhost = NULL;
m_fightingGhostLife = 0;
m_shoppingNpc = NULL;
LoadMTStyls();
m_curFloor = 0;
m_enterMaxFloor = 0; //记录最大的进入层数,方便风信子的程序
m_curMap = G_MagicTowerGame->GetMap(m_curFloor);
m_towerRole.pos = m_curMap->m_entryUP;
G_TextureMgr->AddTexture(m_texViewingBack , "data/minigame/magictower/ViewingBack.png");
G_TextureMgr->AddTexture(m_texRole , "data/minigame/magictower/role1.png");
m_GameState = GS_Running;
m_handBookLock = true;
m_transportLock = true;
//PlaySoundEx(SOUND_BEGIN);
m_windowRect = RectF(0,0,m_curMap->m_size.x*32+150,m_curMap->m_size.y*32);
//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。
if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);
//设置摄像机
CameraCtrlerTarget* ctrler = new CameraCtrlerTarget;
ctrler->SetDistToTar(60);
ctrler->SetTarPos(m_startPos);
G_Camera->PushCtrler(ctrler);
G_Camera->SetEuler(0, -60, 0);
//片头摄像机
PushIntroCamera();
RandMTMap1();
return true;
}
void MiniGameMagicTower::OnSave()
{
}
void MiniGameMagicTower::OnLoad()
{
}
bool MiniGameMagicTower::Stop()
{
MiniGame::Stop();
return true;
}
bool MiniGameMagicTower::Free()
{
MiniGame::Free();
return true;
}
bool MiniGameMagicTower::Render()
{
G_RendDriver->ClearClipRect();
G_RendDriver->EndUI();
G_RendDriver->SetViewPortf(0,0,1,1);
return true;
}
bool MiniGameMagicTower::Update()
{
MiniGame::Update();
switch(m_GameState)
{
case GS_Running:
Update_Running();
break;
case GS_Talking:
{
Update_Talking();
}
break;
case GS_Shopping:
Update_Shopping();
break;
case GS_Viewing:
case GS_Starting:
case GS_Transporting:
if(G_Keyboard->IsKeyUping(DIK_C))
{
m_GameState = GS_Running;
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
//playGui->m_dlgFighting ->SetVisible(false);
//playGui->m_dlgTalking ->SetVisible(false);
playGui->m_dlgShopping ->SetVisible(false);
playGui->m_dlgTransporting->SetVisible(false);
playGui->m_dlgViewingBook ->SetVisible(false);
}
break;
case GS_Message:
Update_Messaging();
break;
case GS_Fighting:
{
static char str2[40];
//if(G_Keyboard->IsKeyPressed(DIK_P)==false)
{
m_fightingTime += G_Timer->GetStepTime();
}
//直接胜利
if(G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
m_fightingGhostLife = 0;
m_GameState = GS_Running;
}
else
{
//if(m_fightTime > 0.3f || G_Keyboard->IsKeyPressed(DIK_F))//DIK_F fast
if(m_fightingTime > 0.1f || G_Keyboard->IsKeyPressed(DIK_F))
{
m_fightingTime = 0;
//角色先攻击
m_fightingGhostLife -= (m_towerRole.m_force - m_fightingGhost->m_defense);
if(m_fightingGhostLife <= 0)
{
m_GameState = GS_Running;
sprintf(str2, "获得 金钱:%d 经验:%d", m_fightingGhost->m_money,m_fightingGhost->m_exp);
ShowNotice(M2U(str2).c_str());
m_towerRole.m_money += m_fightingGhost->m_money;
m_towerRole.m_exp += m_fightingGhost->m_exp;
}
if(m_fightingGhost->m_force - m_towerRole.m_defense > 0) //设置吸血蝙蝠等特殊怪物的减血方式
{
// if(m_fightingGhost==29)
// if(m_towerRole.m_life/(4*m_fightingGhost->m_life/(m_towerRole.m_force-m_fightingGhost->m_defense)))>m_fightingGhost->m_force-m_defense)
m_towerRole.m_life -= m_fightingGhost->m_force - m_towerRole.m_defense;
}
else
{
m_towerRole.m_life -= 1;
}
}
{
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
playGui->m_textOtherLife->SetText(StrFormat("%d", m_fightingGhost->m_life));
playGui->m_textMyLife ->SetText(StrFormat("%d", m_towerRole.m_life));
}
}
}
break;
}
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
playGui->m_textRoleInfos[0]->SetText(StrFormat("%d", m_towerRole.m_level));
playGui->m_textRoleInfos[1]->SetText(StrFormat("%d", m_towerRole.m_life));
playGui->m_textRoleInfos[2]->SetText(StrFormat("%d", m_towerRole.m_force));
playGui->m_textRoleInfos[3]->SetText(StrFormat("%d", m_towerRole.m_defense));
playGui->m_textRoleInfos[4]->SetText(StrFormat("%d", m_towerRole.m_money));
playGui->m_textRoleInfos[5]->SetText(StrFormat("%d", m_towerRole.m_exp));
playGui->m_textRoleInfos[6]->SetText(StrFormat("%d", m_towerRole.m_yellowKeyNum));
playGui->m_textRoleInfos[7]->SetText(StrFormat("%d", m_towerRole.m_blueKeyNum));
playGui->m_textRoleInfos[8]->SetText(StrFormat("%d", m_towerRole.m_redKeyNum));
playGui->m_textMapName->SetText(m_curMap->name.c_str());
return true;
}
bool MiniGameMagicTower::KeepResource(bool once, int& circle, String& nextTip)
{
return true;
}
void MiniGameMagicTower::RenderUI()
{
G_RendDriver->PushMatrix();
G_RendDriver->Translatef((G_Window->m_iWidth-500)/2,-(G_Window->m_iHeight-360)/2,0);
//vec2 offset;//= vec2((m_windowRect.width-430)/2,(m_windowRect.height-120)/2);
//窗口大小不变 如果格子数变大 则格子尺寸变小
G_FontMgr->SetSize(12);
m_curMap->Render();
m_texRole->Bind();
G_RendDriver->DrawTextureRect(RectF(m_towerRole.pos.x,m_towerRole.pos.y,32,32));
if(m_GameState == GS_Starting)
{
//DRAW Poem
//{
m_GameState = GS_Running;
//}
}
if(m_GameState == GS_Message)
{
G_RendDriver->Color4f(1,1,1,1);
m_texViewingBack->Bind();
G_RendDriver->DrawTextureRect(RectF(0,0,m_windowRect.width,m_windowRect.height));
RectF r = m_talkWindowRect;
G_RendDriver->DrawRect(m_talkWindowRect);
TextAtPos_(vec2(4, 22), m_message.c_str());
G_FontMgr->SetColor(Color(1, 0, 1, 1));
TextAtPos_(vec2(34, 182), " 按下[Y]\\[N]或[鼠标]操作");
}
if(m_GameState == GS_OpeningDoor)
{
int i = m_openingDoorTime * 4;
m_openingDoorTime += G_Timer->GetStepTime();
if(i >= 3 || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
m_GameState = GS_Running;
}
else
{
G_RendDriver->Color4f(1, 1, 1, 1);
if(m_openingDoor->m_textureAnim[i])
m_openingDoor->m_textureAnim[i]->Bind();
G_RendDriver->DrawTextureRect(RectF(m_openingDoorPos.x,m_openingDoorPos.y, 32, 32));
}
}
if(m_noticeTime < 2)
{
m_noticeTime += G_Timer->GetStepTime();
G_FontMgr->TextAtPos(vec2(10, 30), m_notice.c_str());
}
G_FontMgr->SetSize(16);
G_RendDriver->PopMatrix();
}
void MiniGameMagicTower::TextAtPos_(const vec2& pos, const char* txt)
{
G_FontMgr->TextAtPos(pos, M2U(txt).c_str());
}
void MiniGameMagicTower::Update_Running()
{
vec2I move;
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
if(G_Keyboard->IsKeyUping(DIK_Q))
{
PopViewBook();
}
else if(G_Keyboard->IsKeyUping(DIK_W))
{
PopTransporting();
}
else if(G_Keyboard->IsKeyPressed(DIK_UP))
{
move.y = -32;
}
else if(G_Keyboard->IsKeyPressed(DIK_DOWN))
{
move.y = 32;
}
else if(G_Keyboard->IsKeyPressed(DIK_LEFT))
{
move.x = -32;
}
else if(G_Keyboard->IsKeyPressed(DIK_RIGHT))
{
move.x = 32;
}
if(G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
m_towerRole.m_moveTime = 99;
}
m_towerRole.m_moveTime += G_Timer->GetStepTime();
if(m_towerRole.m_moveTime>0.1f
&& (move.x || move.y)
)
{
m_towerRole.m_moveTime = 0;
bool canMove = true;
m_towerRole.pos += move;
MTMapStyle::Block* pBlock = m_curMap->GetBlock(m_towerRole.pos/ 32);
int block = pBlock->block;
if(m_curMap->IsOut(m_towerRole.pos/32))//超出边界
{
m_towerRole.pos -= move;
}
else if(block==TB_UpStairs) //楼梯
{
DoUp();
}
else if(block==TB_DownStairs) //楼梯
{
DoDown();
}
else if(dynamic_cast(pBlock->style)) //遇敌
{
MTGhostStyle* ghost = dynamic_cast(pBlock->style);
if(m_towerRole.IsWin(ghost) == false
&& G_Keyboard->IsKeyPressed(DIK_LCONTROL)==false)
{
//无法战胜
m_towerRole.pos -= move;
}
else
{
//可以战胜
m_fightingGhost = ghost;
PopFighting();
m_curMap->SetBlock(m_towerRole.pos / 32, -1);
}
}
//wall
else if(dynamic_cast(pBlock->style))
{
MTWallStyle* wall = dynamic_cast(pBlock->style);
//不能通过区域
if(wall->m_walkAble==false
&& G_Keyboard->IsKeyPressed(DIK_LCONTROL)==false//穿墙
)
m_towerRole.pos -= move;
}
//item
else if(dynamic_cast(pBlock->style))
{
MTItemStyle* item = dynamic_cast(pBlock->style);
bool canUse = true;
bool canMove = true;
if (item->m_redKeyNum<0)
{
if (m_towerRole.m_redKeyNum>= -item->m_redKeyNum || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
OpenDoor(item);//开门
}
else
{
canUse = false;
}
canMove = false;
}
if (item->m_yellowKeyNum<0)
{
if (m_towerRole.m_yellowKeyNum>= -item->m_yellowKeyNum || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
OpenDoor(item);
}
else
{
canUse = false;
}
canMove = false;
}
if (item->m_blueKeyNum<0)
{
if (m_towerRole.m_blueKeyNum>= -item->m_blueKeyNum || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
OpenDoor(item);
}
else
{
canUse = false;
}
canMove = false;
}
if (item->ID==113010)//铁门 不需要钥匙
{
canUse = true;
canMove = false;
OpenDoor(item);
}
if (canUse)
{
//获得资源或能力
m_towerRole.UseItem(item);
if (item->description!="")
{
ShowMsg(340,40,item->description.c_str());
}
m_curMap->SetBlock(m_towerRole.pos/ 32, -1);//清除道具
}
if (canMove==false)
{
m_towerRole.pos -= move;
}
}
//npc
else if(dynamic_cast(pBlock->style))
{
MTNpcStyle* npc = dynamic_cast(pBlock->style);
PopTalking(m_towerRole.pos, npc);
m_towerRole.pos -= move;
}
//shop
else if(dynamic_cast(pBlock->style))
{
MTShopStyle* shop = dynamic_cast(pBlock->style);
PopShopping(m_towerRole.pos, shop);
m_towerRole.pos -= move;
}
}
}
void MiniGameMagicTower::Update_Talking()
{
if (m_talkingNpc==NULL)
return;
//if(G_Keyboard->IsKeyPressed(DIK_P)==false)
{
m_talkingTime += G_Timer->GetStepTime();
}
MTNpcStyle::Talk* talk = &m_talkingNpc->talks[m_talkingNpc->talkIndex];
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
if(G_Keyboard->IsKeyUping(DIK_SPACE)
|| (G_Keyboard->IsKeyPressed(DIK_LCONTROL) && G_Keyboard->IsKeyPressed(DIK_SPACE))
|| (talk->time!=-1 && m_talkingTime> talk->time)
)
{
if (talk->action==MTNpcStyle::TA_Break)
{
m_talkingNpc->talkIndex = talk->parm1;
m_GameState = GS_Running;
playGui->m_dlgTalking->SetVisible(false);
}
else
{
if (talk->action==MTNpcStyle::TA_Reward)
{
if (talk->parm1==-1)
{
m_transportLock = false;
}
else if (talk->parm1==-2)
{
m_handBookLock = false;
}
else
{
MTItemStyle* item = G_StyleMgr->GetStyle(talk->parm1);
if (item)
{
m_towerRole.UseItem(item);
//ShowMsg(300, 40, "得到三种钥匙各一把!" item.name );//todo 飞入动画
}
}
}
else if (talk->action==MTNpcStyle::TA_NpcTalkIndex)
{
MTNpcStyle* npc = G_StyleMgr->GetStyle(talk->parm1);
if (npc)
{
npc->talkIndex = talk->parm2;
if (npc->talkIndex>=npc->talkNum)
{
npc->talkIndex = npc->talkNum-1;
//Assert(0,"npc->talkIndex>=npc->talkNum");
}
}
}
else if (talk->action==MTNpcStyle::TA_NpcMove)//npc移动
{
int npcID = talk->parm1;
if (npcID==-1)
{
npcID = m_talkingNpc->ID;
}
MoveNpc(npcID,vec2I(talk->parm2,talk->parm3));
}
else if (talk->action==MTNpcStyle::TA_SetBlock)//设置block
{
int floor = talk->parm1;
if (floor==-1)
floor = m_curMap->ID;
vec2I pos(talk->parm2,talk->parm3);
if (pos.x==-1)
pos = m_talkingNpcPos/32;
MTMapStyle* curMap = G_StyleMgr->GetStyle(floor);
curMap->SetBlock(pos,talk->parm4);
}
m_talkingNpc->talkIndex ++;
if (m_talkingNpc->talkIndex>=m_talkingNpc->talkNum)
{
m_talkingNpc->talkIndex = m_talkingNpc->talkNum-1;
m_GameState = GS_Running;
playGui->m_dlgTalking->SetVisible(false);
//一次性npc
if(m_talkingNpc->bitem)
{
MoveNpc(m_talkingNpc->ID,vec2I(-999,0));
}
}
else
{
PopTalking(m_talkingNpcPos, m_talkingNpc);
}
}
}
}
void MiniGameMagicTower::Update_Shopping()
{
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
if(G_Keyboard->IsKeyUping(DIK_C))
{
m_GameState = GS_Running;
playGui->m_dlgShopping->SetVisible(false);
return;
}
int select = -1;
for(int i=0;i<9;i++)
{
if(G_Keyboard->IsKeyUping(DIK_1+i))
{
select = i;
}
}
if (select>=0 && selectitemNum)
{
int index = 0;
MTItemStyle* selectItem = NULL;
for(int i=0;iitemNum;++i)
{
MTItemStyle* item = G_StyleMgr->GetStyle(m_shoppingNpc->items[i]);
if(item)
{
if (index==select)
{
selectItem = item;
break;
}
index++;
}
}
GuiListCtrl* listCtrl;
playGui->m_dlgShopping->MAPCTRL(listCtrl,"scroll.contentGroup.list");
if (selectItem && listCtrl)
{
GuiGroupCtrl* groupItem;
GuiButtonCtrl* itemText1;
groupItem = dynamic_cast(listCtrl->GetItem(index));
groupItem->MAPCTRL(itemText1,"text1");
if (itemText1->IsEnable())
{
m_towerRole.UseItem(selectItem);
if (G_Keyboard->IsKeyPressed(DIK_LCONTROL)==false)
{
itemText1->SetEnable(CanBuy(selectItem));
}
}
}
}
}
void MiniGameMagicTower::Transport(int floor)
{
m_GameState = GS_Running;
m_curFloor = floor;
m_curMap = G_MagicTowerGame->GetMap(m_curFloor);
m_towerRole.pos = m_curMap->m_entryUP;
ShowNotice(StrFormat("进入 '%s'",m_curMap->name.c_str()));
}
bool MiniGameMagicTower::CanBuy( MTItemStyle* item )
{
bool enable = true;
if (item->m_money<0 && -item->m_money>m_towerRole.m_money)
enable = false;
if (item->m_exp<0 && -item->m_exp>m_towerRole.m_exp)
enable = false;
if (item->m_redKeyNum<0 && -item->m_redKeyNum>m_towerRole.m_redKeyNum)
enable = false;
if (item->m_yellowKeyNum<0 && -item->m_yellowKeyNum>m_towerRole.m_yellowKeyNum)
enable = false;
if (item->m_blueKeyNum<0 && -item->m_blueKeyNum>m_towerRole.m_blueKeyNum)
enable = false;
return enable;
}
void MiniGameMagicTower::Update_Messaging()
{
if(G_Keyboard->IsKeyUping(DIK_C))
{
m_GameState = GS_Running;
}
}
void MiniGameMagicTower::OpenDoor(MTItemStyle* door)
{
m_openingDoorTime = 0;
m_GameState = GS_OpeningDoor;
m_openingDoor = door;
m_openingDoorPos = m_towerRole.pos;
}
MTMapStyle* MiniGameMagicTower::GetMap(int floor)
{
return G_StyleMgr->GetStyle(111000 + floor);
}
void MiniGameMagicTower::ShowNotice(const char* msg)
{
m_notice = msg;
m_noticeTime = 0;
}
void MiniGameMagicTower::ShowMsg(int x, int y, const char* msg)
{
m_message = msg;
m_GameState = GS_Message;
}
void MiniGameMagicTower::DoUp()
{
char buf[256];
m_curFloor++;
if(m_enterMaxFloor < m_curFloor)
m_enterMaxFloor = m_curFloor;
m_curMap = G_MagicTowerGame->GetMap(m_curFloor);
m_towerRole.pos = G_MagicTowerGame->m_curMap->m_entryUP;
sprintf(buf, M2U("进入 %s").c_str(), m_curMap->name.c_str());
G_MagicTowerGame->ShowNotice(buf);
m_fightingGhost = 0;
}
void MiniGameMagicTower::DoDown()
{
char buf[256];
m_curFloor--;
m_curMap = G_MagicTowerGame->GetMap(m_curFloor);
m_towerRole.pos = G_MagicTowerGame->m_curMap->m_entryDown;
sprintf(buf, M2U("进入 %s").c_str(), m_curMap->name.c_str());
G_MagicTowerGame->ShowNotice(buf);
m_fightingGhost = 0;
}
void MiniGameMagicTower::PopTalking( const vec2I& npcpos, MTNpcStyle* who )
{
if (who==NULL
||who->talkIndex>=who->talkNum)
{
return;
}
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
m_talkingTime = 0;
m_talkingNpcPos = npcpos;
m_talkingNpc = who;
m_GameState = GS_Talking;
GuiGroupCtrl* dlg = playGui->m_dlgTalking;
dlg->SetVisible(true);
vec2 pos(npcpos.x,npcpos.y);
if (npcpos.x>300)
{
//pos.x = 140;
pos.x = 110;
}
else
{
pos.x = 10;
}
if (npcpos.y>250)
{
pos.y = npcpos.y - 120;
}
else
{
pos.y = npcpos.y + 10;
}
RectF rect = dlg->GetRectReal();
rect.SetPos(pos);
dlg->SetRectReal(rect);
dlg->RePlay();
GuiRichTextCtrl* text;
dlg->MAPCTRL(text,"richtext");
text->Clear();
text->AddHtmlWords(m_talkingNpc->talks[m_talkingNpc->talkIndex].words.c_str(),16);
}
//战斗界面
void MiniGameMagicTower::PopFighting()
{
m_fightingTime = 0;
m_GameState = GS_Fighting;
m_fightingGhostLife = m_fightingGhost->m_life;
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
GuiGroupCtrl* dlg = playGui->m_dlgFighting;
dlg->SetVisible(true);
dlg->RePlay();
GuiDragIconCtrl* icon;
dlg->MAPCTRL(icon,"icon");
icon->SetIconTexture(m_fightingGhost->m_texture);
playGui->m_textOtherName->SetText(m_fightingGhost->name.c_str());
playGui->m_textOtherLife->SetText(StrFormat("%d", m_fightingGhost->m_life));
playGui->m_textOtherForce->SetText(StrFormat("%d", m_fightingGhost->m_force));
playGui->m_textOtherDefend->SetText(StrFormat("%d", m_fightingGhost->m_defense));
playGui->m_textMyLife ->SetText(StrFormat("%d", m_towerRole.m_life));
playGui->m_textMyForce ->SetText(StrFormat("%d", m_towerRole.m_force));
playGui->m_textMyDefend->SetText(StrFormat("%d", m_towerRole.m_defense));
}
//商城界面
void MiniGameMagicTower::PopShopping(const vec2I& shoppos,MTShopStyle* who )
{
m_GameState = GS_Shopping;
m_shoppingNpc = who;
m_shopPos = shoppos;
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
GuiGroupCtrl* dlg = playGui->m_dlgShopping;
dlg->SetVisible(true);
vec2 pos(shoppos.x,shoppos.y);
if (shoppos.x>300)
{
//pos.x = 140;
pos.x = 110;
}
else
{
pos.x = 10;
}
if (shoppos.y>250)
{
pos.y = shoppos.y - 210;
}
else
{
pos.y = shoppos.y + 10;
}
RectF rect = dlg->GetRectReal();
rect.SetPos(pos);
dlg->SetRectReal(rect);
dlg->RePlay();
GuiDragIconCtrl* icon;
dlg->MAPCTRL(icon,"icon");
icon->SetIconTexture(m_shoppingNpc->m_texture);
GuiRichTextCtrl* text;
dlg->MAPCTRL(text,"richtext");
text->Clear();
text->AddHtmlWords(m_shoppingNpc->description.c_str(),16);
GuiListCtrl* listCtrl;
playGui->m_dlgShopping->MAPCTRL(listCtrl,"scroll.contentGroup.list");
if (listCtrl)
{
listCtrl->ClearItem();
GuiGroupCtrl* groupItem;
GuiButtonCtrl* itemText1;
GuiButtonCtrl* itemText2;
GuiDragIconCtrl* itemIcon;
for(int i=0;iitemNum;++i)
{
MTItemStyle* item = G_StyleMgr->GetStyle(m_shoppingNpc->items[i]);
if(item)
{
groupItem = dynamic_cast(listCtrl->InsertItem());
groupItem->MAPCTRL(itemIcon,"icon");
groupItem->MAPCTRL(itemText1,"text1");
groupItem->MAPCTRL(itemText2,"text2");
itemIcon->SetIconTexture(item->m_texture);
itemText1->SetText(item->description.c_str());
bool enable = true;
if (G_Keyboard->IsKeyPressed(DIK_LCONTROL)==false)
{
enable = CanBuy(item);
}
itemText1->SetEnable(enable);
}
}
}
}
//怪物图鉴界面
void MiniGameMagicTower::PopViewBook()
{
if(m_handBookLock == false || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
m_GameState = GS_Viewing;
GuiGroupCtrl* dlg = playGui->m_dlgViewingBook;
dlg->SetVisible(true);
dlg->RePlay();
//计数
int monsterNum[1000];
memset(monsterNum, 0, 256 * 4);
int blockNum = m_curMap->m_size.x * m_curMap->m_size.y;
for(int i = 0; i < blockNum; i++)
{
MTMapStyle::Block* pBlock = &m_curMap->m_blocks[i];
if(dynamic_cast(pBlock->style))
{
MTGhostStyle* ghost = dynamic_cast(pBlock->style);
monsterNum[ghost->ID-TB_GhostMin] ++;
}
}
GuiListCtrl* listCtrl;
playGui->m_dlgViewingBook->MAPCTRL(listCtrl,"scroll.contentGroup.list");
if (listCtrl)
{
listCtrl->ClearItem();
GuiGroupCtrl* groupItem;
GuiButtonCtrl* itemText1;
GuiButtonCtrl* itemText2;
GuiDragIconCtrl* itemIcon;
char buf[256];
char lost[32];
{
StyleGroupRef styles(Enum_Style(MTGhostStyle));
Style* it = styles.GetFirst();
while (it)
{
MTGhostStyle* style = (MTGhostStyle*)it;
if(monsterNum[style->ID - TB_GhostMin] > 0)
{
groupItem = dynamic_cast(listCtrl->InsertItem());
groupItem->MAPCTRL(itemIcon,"icon");
groupItem->MAPCTRL(itemText1,"text1");
groupItem->MAPCTRL(itemText2,"text2");
itemIcon->SetIconTexture(style->m_texture);
itemText1->SetText(style->name.c_str());
if(m_towerRole.IsWin(style)==0)
{
strcpy(lost, "无法战胜");
}
else
{
sprintf(lost, "%d", m_towerRole.GetLost(style));
}
sprintf(buf, "生命:%-2d 攻击:%-2d 防御:%-2d 金钱:%-2d 经验:%-2d 损失:%s",
style->m_life, style->m_force, style->m_defense, style->m_money, style->m_exp, lost);
itemText2->SetText(M2U(buf).c_str());
}
it = styles.GetNext();
}
}
}
}
}
//传送界面
void MiniGameMagicTower::PopTransporting()
{
if(m_transportLock==false || G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
MiMagicTower_PlayGui* playGui = G_GuiMgr->GetGui();
m_GameState = GS_Transporting;
GuiGroupCtrl* dlg = playGui->m_dlgTransporting;
dlg->SetVisible(true);
dlg->RePlay();
int MaxFloor = m_enterMaxFloor;
if(G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
MaxFloor = G_StyleMgr->GetStyleNum()-1;
}
GuiListCtrl* listCtrl;
playGui->m_dlgTransporting->MAPCTRL(listCtrl,"scroll.contentGroup.list");
if (listCtrl)
{
listCtrl->ClearItem();
GuiGroupCtrl* groupItem;
GuiButtonCtrl* itemName;
for(int i = 0; i <= MaxFloor; i++)
{
groupItem = dynamic_cast(listCtrl->InsertItem());
groupItem->MAPCTRL(itemName,"text");
MTMapStyle* map = GetMap(i);
if(map)
itemName->SetText(map->name.c_str());
//itemName->CallBack()->Add("MouseUp",(*it).address,this,&LoginGui::OnComListButton_LocalNetServer);
}
}
}
}
void MiniGameMagicTower::MoveNpc( int npcID,const vec2I& mov )
{
for(int y = 0; y < m_curMap->m_size.y; y++)
{
for(int x = 0; x < m_curMap->m_size.x; x++)
{
MTMapStyle::Block* pBlock = m_curMap->GetBlock(vec2I(x, y));
if(pBlock->style
&&pBlock->style->ID==npcID)
{
//todo判断可移动?
m_curMap->SetBlock(vec2I(x+mov.x,y+mov.y),pBlock->block);
m_curMap->SetBlock(vec2I(x,y),-1);
return;
}
}
}
StyleGroupRef styles(Enum_Style(MTMapStyle));
Style* it = styles.GetFirst();
while (it)
{
MTMapStyle* style = (MTMapStyle*)it;
MTMapStyle* curMap = style;
for(int y = 0; y < curMap->m_size.y; y++)
{
for(int x = 0; x < curMap->m_size.x; x++)
{
MTMapStyle::Block* pBlock = curMap->GetBlock(vec2I(x, y));
if(pBlock->style
&&pBlock->style->ID==npcID)
{
//todo判断可移动?
curMap->SetBlock(vec2I(x+mov.x,y+mov.y),pBlock->block);
curMap->SetBlock(vec2I(x,y),-1);
}
}
}
it = styles.GetNext();
}
}
自动生成算法思路(未完成):
class MTGraphNode
{
public:
MTGraphNode();
~MTGraphNode();
int index;
int floor; //节点所在楼层
vec2I blockPos; //节点所在格子
int block; //节点内容
MTStyle* blockStyle;
int neighborNum; //邻节点
MTGraphNode** neighbors;
bool* neighborOpens; //邻节点是否因为此节点的打通而加入了前锋边,用于回退去除。
vec2 drawPos;//绘制图时节点位置RendToTexture
};
class TextureData;
class MTGraph
{
public:
MTGraph();
~MTGraph();
void Add(MTMapStyle* map);
int Score();
void Arrange();
void RendToTexture(TextureData& image);
int MaxNodeNum;
int nodeNum;
MTGraphNode* nodes;
};
MTGraphNode::MTGraphNode()
:floor(1)
,block(-1)
,blockStyle(NULL)
,neighborNum(0)
,neighbors(NULL)
{
}
MTGraphNode::~MTGraphNode()
{
SafeDeleteArray(neighbors);
}
MTGraph::MTGraph()
:MaxNodeNum(20*20*100)
,nodeNum(0)
,nodes(NULL)
{
nodes = new MTGraphNode[MaxNodeNum];
}
MTGraph::~MTGraph()
{
SafeDeleteArray(nodes);
}
void MTGraph::Add( MTMapStyle* curMap )
{
MTGraphNode* table[32][32];
//加入图节点
for(int y = 0; y < curMap->m_size.y; y++)
{
for(int x = 0; x < curMap->m_size.x; x++)
{
MTMapStyle::Block* pBlock = curMap->GetBlock(vec2I(x, y));
int block = pBlock->block;
if (block!=-1 && dynamic_cast(pBlock->style)==NULL)
{
MTGraphNode* node = &nodes[nodeNum];
node->index = nodeNum;
node->block = block;
nodeNum++;
if(pBlock->style)
{
node->blockStyle = pBlock->style;
}
node->floor = curMap->ID;
node->blockPos = vec2I(x,y);
node->drawPos = vec2(x*32+16,352-(y*32+16));
table[y][x] = node;
}
}
}
//构造邻居
std::vector neighbours;
std::vector search;
neighbours.reserve(32);
search.reserve(32);
bool flags[32][32];
vec2I dir[] = {vec2I(-1,0),vec2I(1,0),vec2I(0,-1),vec2I(0,1)};
for(int n=0;nblockPos);
flags[node->blockPos.y][node->blockPos.x] = true;
while(search.empty()==false)
{
vec2I it = search.back();
search.pop_back();
//遍历四个邻居
for (int k=0;k<4;++k)
{
itn = it + dir[k];
if (itn.x>=0 && itn.xm_size.x
&&itn.y>=0 && itn.ym_size.y
&& flags[itn.y][itn.x]==false)
{
MTMapStyle::Block* pBlock = &curMap->m_blocks[itn.y*curMap->m_size.x+itn.x];
if (pBlock->block==-1)
{
search.push_back(itn);
}
else if(dynamic_cast(pBlock->style)==NULL)
{
neighbours.push_back(table[itn.y][itn.x]);
}
flags[itn.y][itn.x] = true;
}
}
}
//
node->neighborNum = neighbours.size();
if(node->neighborNum>0)
{
node->neighbors = new MTGraphNode*[node->neighborNum];
for(int n=0;nneighborNum;++n)
{
node->neighbors[n] = neighbours[n];
}
}
}
}
void MTGraph::RendToTexture( TextureData& finalImage )
{
Color color(0.6f,0.8f,1,1);
finalImage.AllocTexture(32*11,32*11,RS_RGBA,&color);
Color colorLine(0,0,0,0.5f);
for(int n=0;nblockStyle)
{
finalImage.SubCopy(node->blockStyle->m_texture,node->drawPos.x-16,node->drawPos.y-16,32,32,0,0);
}
finalImage.Circle(node->drawPos.x-3,node->drawPos.y-3, 6,6,1,colorLine);
for(int k=0;kneighborNum;++k)
{
MTGraphNode* nodeN = node->neighbors[k];
finalImage.Line(node->drawPos.x,node->drawPos.y, nodeN->drawPos.x,nodeN->drawPos.y
, 1,colorLine);
}
}
}
void MTGraph::Arrange()
{
//无需排版
}
typedef std::list NodeList;
class MTState
{
public:
bool nodeFlags[256]; //各node是否被访问过
NodeList nodeList; //前锋边 接下来可以转换的状态
int parentIndex; //父状态中的索引,用于输出最终路径
TowerRole towerRole; //主角状态
bool PushSubState(std::list& stateList)
{
int index = 0;
for (NodeList::iterator it=nodeList.begin();it!=nodeList.end();++it,++index)
{
MTGraphNode* node = *it;
MTGhostStyle* monster = dynamic_cast(node->blockStyle);
MTItemStyle* item = dynamic_cast(node->blockStyle);
if (nodeFlags[node->index]==false)
{
continue;//节点已经被访问 怪被清 奖励被捡取
}
if (monster && towerRole.IsWin(monster)==false)
{
continue;//无法战胜 不能访问
}
if (node->blockStyle->ID==TB_UpStairs)//已合并多个楼层为一张大图
{
return true;
}
//新状态
MTState* newState = new MTState(*this);
newState->parentIndex = index;
newState->nodeFlags[node->index] = false;//清怪
//newState->nodeList.erase(); flags will skip it.
for(int k=0;kneighborNum;++k)
{
MTGraphNode* neighbor = node->neighbors[k];
if (nodeFlags[neighbor->index])
{
newState->nodeList.push_back(neighbor);
}
}
if (monster)
{
newState->towerRole.m_life -= newState->towerRole.GetLost(monster);
}
else if (item)
{
newState->towerRole.UseItem(item);
}
//
stateList.push_back(newState);
}
return false;
}
};
int MTGraph::Score()
{
//动规算法?
//搜索深度太大,和地图上所有非空节点数差不多,有的节点还要访问多次。深度可能达到数千。
//随着步数的深入,可选的下一步节点集迅速增大,最大节点集不会超过数十?,o(10的1000次方) 这已经是一个np难题了。 大约是不可能完成的任务。
//在搜索失败回退时要同时回退n个邻节点。 bool* neighborOpens;
//剪枝方法,当节点集中出现奖励物品时,可以优先访问。当商店节点打通后,会优先频繁访问商店。
MTState* state = new MTState;
std::list stateList;
//state->tryIndex = 0;
state->nodeList.push_back(nodes);
state->nodeFlags;
stateList.push_back(state);
while(!stateList.empty())
{
//避免内存超大,使用深度优先搜索
MTState* state = stateList.back();
stateList.pop_back();
//加入所有子状态
bool res = state->PushSubState(stateList);
delete state;
if (res)
{
break;//到达终点 结束
}
}
MTState* endState = stateList.back();
//统计endState中未访问的节点数,越小越好
int num = 0;
for(int k=0;knodeFlags[k]==true)
{
num++;
}
}
//清除
while(!stateList.empty())
{
MTState* state = stateList.back();
stateList.pop_back();
delete state;
}
return 0;
}
void RandMTMap1()
{
return;
int floorNum = 21;
//生成
{
int num = 0;
StyleGroupRef styles(Enum_Style(MTMapStyle));
Style* it = styles.GetFirst();
while (it)
{
MTMapStyle* curMap = (MTMapStyle*)it;
Maze maze;
if (num<4 || (Rand()%3))
{
maze.GeneratePrimNatureMaze(curMap->m_size.x,curMap->m_size.y);
}
else
{
maze.GeneratePrimTrunkMaze(curMap->m_size.x,curMap->m_size.y);
}
//楼梯口
vec2I upStair(RandRange(0,curMap->m_size.x-1),RandRange(0,curMap->m_size.y-1));
vec2I downStair;
while(1)
{
downStair = vec2I(RandRange(0,curMap->m_size.x-1),RandRange(0,curMap->m_size.y-1));
if ((upStair-downStair).Length()>1)
{
break;
}
}
maze.MakePath(upStair,downStair);
curMap->m_entryUP = upStair;
curMap->m_entryDown = downStair;
curMap->SetBlock(upStair,TB_UpStairs);
curMap->SetBlock(downStair,TB_DownStairs);
int roadNum = 0;
//墙
for(int y = 0; y < curMap->m_size.y; y++)
{
for(int x = 0; x < curMap->m_size.x; x++)
{
MTMapStyle::Block* pBlock = curMap->GetBlock(vec2I(x, y));
if(maze.mazeBlockType(x,y)==Maze::Wall)
{
pBlock->block = 114014;//TB_WallMin + rand;
}
else
{
pBlock->block = -1;
roadNum++;
}
}
}
vec2I posI;
//门
{
int tryCount = 0;
int num = roadNum * RandRange(0.1f,0.13f);
for (int i=0;i1000)
{
break;
}
posI.x = RandRange(1,curMap->m_size.x-2);
posI.y = RandRange(1,curMap->m_size.y-2);
if (curMap->GetBlock(posI)->block==-1
&&(
( curMap->GetBlock(posI+vec2I(0,1))->block==-1&&curMap->GetBlock(posI+vec2I(0,-1))->block==-1)
||( curMap->GetBlock(posI+vec2I(1,0))->block==-1&&curMap->GetBlock(posI+vec2I(-1,0))->block==-1)
)
)
{
int ID = 3004 + RandRange(0,3);
curMap->SetBlock(posI,ID);
break;
}
}
}
}
//怪 boss
{
int tryCount = 0;
int monsterNum = G_StyleMgr->GetStyleNum();
int num = roadNum * RandRange(0.1f,0.13f);
for (int i=0;i1000)
{
break;
}
posI.x = RandRange(0,curMap->m_size.x-1);
posI.y = RandRange(0,curMap->m_size.y-1);
if (curMap->GetBlock(posI)->block==-1)
{
int IDMin = 2001 + (curMap->ID-111000)*2;
int IDMax = IDMin + RandRange(-3,3);
Clamp(IDMin,0,monsterNum);
Clamp(IDMax,0,monsterNum);
curMap->SetBlock(posI,RandRange(IDMin,IDMax));
break;
}
}
}
}
//shop
{
int tryCount = 0;
int shopNum = G_StyleMgr->GetStyleNum();
StyleGroupRef styles(Enum_Style(MTShopStyle));
Style* it = styles.GetFirst();
while (it)
{
MTShopStyle* style = (MTShopStyle*)it;
int floor = (style->ID-117001)*3 +RandRange(0,3);
Clamp(floor,0,floorNum);
MTMapStyle* curMap = G_StyleMgr->GetStyle(111001+floor);
while(1)
{
if (tryCount>1000)
{
break;
}
posI.x = RandRange(0,curMap->m_size.x-1);
posI.y = RandRange(0,curMap->m_size.y-1);
if (curMap->GetBlock(posI)->block==-1)
{
curMap->SetBlock(posI,style->ID);
break;
}
}
it = styles.GetNext();
}
}
//npc
{
int tryCount = 0;
int shopNum = G_StyleMgr->GetStyleNum();
StyleGroupRef styles(Enum_Style(MTNpcStyle));
Style* it = styles.GetFirst();
while (it)
{
MTNpcStyle* style = (MTNpcStyle*)it;
int floor = (style->ID-115001)*3 +RandRange(0,3);
Clamp(floor,0,floorNum);
MTMapStyle* curMap = G_StyleMgr->GetStyle(111001+floor);
while(1)
{
if (tryCount>1000)
{
break;
}
posI.x = RandRange(0,curMap->m_size.x-1);
posI.y = RandRange(0,curMap->m_size.y-1);
if (curMap->GetBlock(posI)->block==-1)
{
curMap->SetBlock(posI,style->ID);
break;
}
}
it = styles.GetNext();
}
}
//道具
{
//普通道具多个
//关键道具只有一个
int tryCount = 0;
int shopNum = G_StyleMgr->GetStyleNum();
StyleGroupRef styles(Enum_Style(MTItemStyle));
Style* it = styles.GetFirst();
while (it)
{
MTItemStyle* style = (MTItemStyle*)it;
int floor = (style->ID-113001)*3 +RandRange(0,3);
Clamp(floor,0,floorNum);
MTMapStyle* curMap = G_StyleMgr->GetStyle(111001+floor);
while(1)
{
if (tryCount>1000)
{
break;
}
posI.x = RandRange(0,curMap->m_size.x-1);
posI.y = RandRange(0,curMap->m_size.y-1);
if (curMap->GetBlock(posI)->block==-1)
{
curMap->SetBlock(posI,style->ID);
break;
}
}
it = styles.GetNext();
}
}
it = styles.GetNext();
if (num++>2)
{
break;
}
}
}
//判别
{
MTGraph graph;
int num = 0;
StyleGroupRef styles(Enum_Style(MTMapStyle));
Style* it = styles.GetFirst();
while (it)
{
MTMapStyle* curMap = (MTMapStyle*)it;
graph.Add(curMap);
}
graph.Score();
}
//打印
if(0)
{
int num = 0;
TextureData finalImage;
StyleGroupRef styles(Enum_Style(MTMapStyle));
Style* it = styles.GetFirst();
while (it)
{
MTMapStyle* curMap = (MTMapStyle*)it;
curMap->RendToTexture(finalImage);
finalImage.SaveToFile(StrFormat("data/test/magictower/map_%d.png",curMap->ID));
MTGraph graph;
graph.Add(curMap);
graph.Arrange();
graph.RendToTexture(finalImage);
finalImage.SaveToFile(StrFormat("data/test/magictower/graph_%d.png",curMap->ID));
it = styles.GetNext();
if (num++>2)
{
break;
}
}
}
}
void RandMTMap2()
{
//方案二,先生成路径,先考虑最简单的情况,一张大图,没有楼梯口(楼梯口可以最后将大图切割成小的楼层时再添加),也先不考虑npc和商店。
// 定好主角在每个阶段的属性值,根据属性值是可以倒推出怪物和奖励道具的。
//先生成迷宫大地图,分割路径为一段段的小胡同,计算胡同邻接关系,使用随机算法遍历胡同,根据遍历顺序生成到达胡同末端时的战力值,
//因为战力值的限制,玩家游戏时只能按照遍历顺序清关,否则会卡关失败
//然后根据起点和终点战力值在每条胡同上布置怪物和奖励
return;
MTMapStyle __curMap;
MTMapStyle* curMap = &__curMap;
//生成
{
//先生成迷宫大地图
curMap->m_size = vec2I(11,220);
int blockNum = curMap->m_size.x * curMap->m_size.y;
curMap->m_blocks = new MTMapStyle::Block[blockNum];
Maze maze;
maze.GeneratePrimNatureMaze(curMap->m_size.x,curMap->m_size.y);
//分割路径为一段段的小胡同
//。。。
int roadNum = 0;
//墙
for(int y = 0; y < curMap->m_size.y; y++)
{
for(int x = 0; x < curMap->m_size.x; x++)
{
MTMapStyle::Block* pBlock = curMap->GetBlock(vec2I(x, y));
if(maze.mazeBlockType(x,y)==Maze::Wall)
{
pBlock->block = 114014;//TB_WallMin + rand;
}
else
{
pBlock->block = -1;
roadNum++;
}
}
}
}
//判别
{
MTGraph graph;
graph.Add(curMap);
graph.Score();
}
//打印
if(0)
{
TextureData finalImage;
curMap->RendToTexture(finalImage);
finalImage.SaveToFile(StrFormat("data/test/magictower/map_%d.png",curMap->ID));
MTGraph graph;
graph.Add(curMap);
graph.Arrange();
graph.RendToTexture(finalImage);
finalImage.SaveToFile(StrFormat("data/test/magictower/graph_%d.png",curMap->ID));
}
}