魔兽地图编辑器ydwe为什么兵模型是一样的在地图上显示不一样

【And】我终于搞明白了为什么星际2地图编辑器如此受到各方重视~_即时战略吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:15,323贴子:
【And】我终于搞明白了为什么星际2地图编辑器如此受到各方重视~
从魔兽争霸开始,一直以来我都很奇怪,为什么一款即时战略游戏,他的地图编辑器却能受到很大的关注。按道理说作为RTS玩家,如何搞定对手才是头等大事。然而待到魔兽DotA盛行,RPG满天飞的时候,心理已有些答案:地图编辑器可以让游戏自由度扩大许多。看看现在的魔兽争霸3,在所有玩家里面玩正规对战的(还不是只玩对战,你玩就算)和玩其他地图的比率,就可以发现,魔兽现在根本不是靠RTS元素在吸引大众玩家,完全是通过地图的形式将其他类型的游戏代入,从而让魔兽从一款纯粹的RPGRTS发展成为包含众多游戏类型的大集合,而这一切,都要归功于灵活而强大的地图编辑器。TD、RPG、DotA(暂且将其单独分类,因为DotA不同于普通RPG),甚至赛车~~~~。一个高自由度的地图编辑器,造就了如此夸张的游戏受众。现在要是国内哪家网吧的电脑里面没有冰封王座,并且附上几百张各式各样的地图,那一定是很罕见的奇观...正因为魔兽的地图编辑器获得了如此大的成功,暴雪自然愿意将这个宝贝移植到其他作品上。从冰封王座发售以后的作品来看,魔兽世界显然不可能。大菠萝3还没看到影子,即将发售的星际争霸2变成了放这个宝贝的唯一选择。众所周知,星际初代在RTS界享有的盛誉,其他游戏很难比肩(不是说没有,而是说少,就这么一两款),SC1可是一款不折不扣的纯RTS,不像WAR3那样偏RPG,也不像CC4那样偏RTT。但是,星际2在原本很纯正的基础上,却高调宣布其地图编辑器将会对RPG地图的制作提供强大支援,这在核心RTS玩家眼里无异于把自家老婆给别人上一晚上,什么滋味自己心里清楚。RTS曾经有过许多辉煌,据说当年有很多人在网吧靠各种方便食品通宵鏖战CC1和SC1。但是,即使是最辉煌的魔兽争霸时代,RTS的光辉也远不及FPS,RPG这几类游戏类型。终究还是RTS这个类型的局限性。转回正题,很可能暴雪只是想单纯的复制其地图编辑器在魔兽争霸上的成功,但是无意间得到的一条消息,却让我恍然大悟:原来暴雪想干这个~入手4月上的MC,在看那堆编辑介绍SC2的时候,看到了两张图,是第一人称视角的图,和常见的FPS截图几乎没有差别。当我看到说SC2的任务关卡将会有这种画面出现的时候,我突然在想:暴雪应该会在地图编辑器中开放对这个视角的支持吧~?于是乎,我们不难理解暴雪为何对地图编辑器这个叫好不叫座的东西如此感兴趣了(虽然地图编辑器创造了很多让冰封王座风光无限的地图,但暴雪方面几乎没有营收,只是赚了点名声)。再加上之前透露出SC2部分自制地图可能是付费下载的消息,一切,都摆在了我们的面前:暴雪似乎早已认识到RTS自身的局限性,于是期待通过强大的地图编辑器,以地图为媒介,引入其他游戏类型,使得星际2变成一个无所不能的万用游戏程序。到时候星际2将不仅是一款RTS,更是一款包罗万象的杂合体。而通过收取这些地图的使用费用,暴雪便可以轻松的用一款作品涉猎几乎游戏的所有领域,不仅是单机游戏类型,也包括网游,这也是战网存在的一个巨大意义。到时候,别说RPG,就算是什么竞速类,FPS,一个星际2全部收入囊中。也许用他做出来的其他类型游戏是有些粗糙,但是看看冰封王座你就知道,这不是问题。更何况,通过这样完全可以借个人地图开发者之名,以地图的形式盗取其他类型游戏的优秀之处(比如各种剧情型RPG里面的各式招数),同时这样做还有一个很大的好处就是低风险高收益,无论玩家喜欢什么类型,都不用暴雪操心,市场竞争会让地图开发者去做最受欢迎的游戏类型。现在看来,战网为什么被暴雪提到如此高度,也就不令人费解了。除了正版之名,更是以后暴雪施展吸金大法的绝妙舞台。我们不难想象以后战网上会出现一个Maps Store之类的东西,并且有可能采取苹果App Store的销售模式,这样一来,就算SC2本体卖低一点,照样可以靠规模庞大的地图赚回来。不难想象,现在躺在钞票堆里的暴雪肯定不会满足于身下的这点“小钱”,要知道若是抛开动视单算暴雪的话,其总资产和EA还有相当大的差距,还不知道和SE有没有比头。从魔兽世界的巨大成功,和争霸以及星际一比,落差感油然而生。再加上现在单机游戏界,最吸金的根本不是RTS游戏,所以暴雪毅然决然的开始了新的计划。不知道暴雪以后是不是会出品一个游戏框架,然后把什么类型的游戏全塞进去,这样以来整个单机界玩家全部成了受众。暴雪内心对金钱的欲望已经膨胀到了威胁其游戏质量的边缘,不过他还有点自知之明,知道像EA那样做罐头厂没有前途。但如此走下去,恐怕纯粹的正统RTS将永无翻身之日~~~~~~~~~~~~以上均为个人颠东幻想,这次我换个规矩:有意见别喷,喷了也没意思,无非证明你是暴白或者暴黑或者小白。
奥康,TCL都选择和道和 即时战略帮助中国企业真正解放老板,培养经营人才,实现持续盈利!和道和辅导华电利润增长2亿,TCL利润增长111%,即时战略更有上百家企业取得高利润增长
一个标新立异的论点 可惜用了糟糕的论据。。。
这在核心RTS玩家眼里无异于把自家老婆给别人上一晚上,什么滋味自己心里清楚。……我还真没看到过会有这样的核心RTS玩家连职业rts选手有空时都会去打dota……金钱欲望……你没有吗?能赚钱就说明支持的玩家多,这是双赢的结果
但是,星际2在原本很纯正的基础上,却高调宣布其地图编辑器将会对RPG地图的制作提供强大支援,这在核心RTS玩家眼里无异于把自家老婆给别人上一晚
上,什么滋味自己心里清楚。--------------------------------没这种感觉,有新RPG图玩开心死了。
如果楼主个人有这种看法(高调宣布其地图编辑器将会对RPG地图的制作提供强大支援,这在核心RTS玩家眼里无异于把自家老婆给别人上一晚上。。。),请不要强加到别人头上、表代表别人。
说的没错。。。 所谓 地图编辑器 是BLZ带给RTS倒退之一。。。 原来RTS发展的方向是 自动随机地图!!! BLz的地图编辑器火了之后;后来者都不得不在RPG玩家的要求下,为RTS提供面向RPG玩家的地图编辑器;而彻底放弃了。本来非常方便的,随机地图生成器
这个~话说我语文学的很差~实际上表述能力也很悲剧~我没有强加自己的意愿给别人的意思,我知道不能向粪青那样去代表全国人民~~~~说着说着就说偏了,要相信我本意是好的~暴雪这样做,应该说是RTS游戏的悲剧吧~不过说实话光靠卖RTS真的没法赚钱~
做rts大多数是为了心中的理想,就是兴趣使然rpg肯定更好赚暴雪最卖钱的是和wow
回复:8楼是啊~暴雪已经看清楚现实了~所以才会这样~我真的觉得很有可能出现类似于“MapStore”一样的东西~不过相信总会有办法玩盗版~不是我不支持正版~是支持不起~~~~若是上了大学还可以考虑一下全套正版(游戏本体+经典地图)~~~~~~~~
恩。因为地图编辑器好玩所以说明了blz游戏不好玩。 我很淡定的说,暴黑是不是最近智商普遍比较低
拜托,你们到底玩过星际的RPG图没有啊?有单位数很少的RPG图,也有可操作单位数非常多,甚至不用人口房、没有200上限,更有甚者,连兵都不需要你造,后方会持续给你出兵,你只要指定要出什么兵就可以了。这种图只不过是归到RPG图的大类里面,主要原因可能是在浩方打这种图都是在RPG专房打的。这种图与其说是RPG,还不如说是简化版的RTS。是不是一想到制作RPG地图,就只有刀锋女王带小弟的那种?
“即使是最辉煌的魔兽争霸时代,RTS的光辉也远不及FPS,RPG这几类游戏类型”
哦买高,不解释
回复:11楼那是RTT~
以上均为个人颠东幻想,这次我换个规矩:有意见别喷,喷了也没意思,无非证明你是暴白或者暴黑或者小白。------------------------------------------------------有些人总是喜欢选择性忽略整篇文章中的部分重要字词句篇章,对此我无话可说。我都说了我出发点是好的,只是发表一下个人想法,我是动你老婆了还是动你命根子了,至于开口闭口就暴黑暴黑的叫。说实话,我唯一讨厌星际的地方,就是有那么一小撮星际玩家把星际供奉的高高的,其他RTS完全贬低。不过现在也看开了,其他玩家说什么和我玩什么一点关系都没有。
回复:14楼恩,好伟大。胸襟好开阔。哇哇哇。 又放不下。又要摆高姿态。平时总要攻击某个游戏等到别人还嘴了就变成了别人先攻击的你。 顺便一提。你这个乱立规矩的毛病我感觉很搞笑。
暴雪的老总本来就不是 为了游戏好玩而作游戏的; 据报道此人从不玩游戏; 游戏只是他赚钱的工具;所有BLZ会朝着商业化前进; 而不是推动RTS前进。。就是这样一个原因
我就这么说吧,SC1的地图编辑器可以营造出至少不会输给星际原版的战争。如果想说没有经济系统就不算RTS而是RTT,那很抱歉,要加入经济系统是很容易的事。在这里,你看起来是一块水晶,你以为3农民饱和,其实这块水晶是无数个水晶叠在了一起,这片矿可以支持无数的农民采矿。如果想说规模小,很抱歉,我说过规模可以很大,没有人口限制。如果想说造兵慢,很抱歉,cd时间都是可以改的。我的目的只有一个,那些动不动就说地图编辑器是RTS的退步这种言论的人,请了解了再说。我就得纠正一下,总是以为RPG图就是dota之类吗?
星际地图编辑器能做出个横扫千军吗?
RPG图就是 RPG图。。不是RTS。。。 就这样。。。魔兽3地图编辑的“强大”和RTS无关
估计难,毕竟星际本身的限制摆在那。起码像指挥官辅助加速建造不好做到。不过像一些TAfan批评的种族差异,在地图编辑器里很好解决,初期给你许多三族农民,你自由发展好了,这样的话你就可以有三族的单位,单位总数还是单位种类数都很丰富。达不到TA那种夸张的1500人口,不过达到600人口都是很简单的事。另外提一下,韩国的一些比赛地图中那种广阔的斜坡可能除了利用地图编辑器,还用了其他方法,单纯靠地图编辑器也不是万能的。老实说地图编辑器我不会用,我也就是见识过03年那段时间的一些星际的RPG图。
人口上限一个 补丁就解决了。。。 问题是 你还得有配套的 经济系统来支持
配套的暴兵系统来支持
配套的指挥系统来支持; 你星际 开多少分矿 才能 支持 500 Vs 500的战斗消耗? 要多少兵营生产速度才跟的上 。。 指挥系统的12个编队上限。。。500兵你怎么指挥? 然后 战场需要多大 才能满足 500兵的机动需要; 然后 你的小地图要如何改造;才能让500兵显示的清晰? 这些都不是
你的地图编辑器 能轻易解决的; 地图编辑器万能是迷信
当然不是说完全一样
我对这不感兴趣混沌崛起也有这东西,但我都不想理RTS要有RTS的样子
回复:15楼很好笑?那你笑就完了嘛,还要站出来说:“哈哈哈哈你好好笑哦~”连鬼都会对你无语~看看这楼里的其他人,哪一个像你那样完全不就事论事,只要我提到暴雪你马上开始冷嘲热讽。那用词还真是恰如其分呢,可以想象你应该有潜力做郭敬明二代嘛,这样大的才华到我这里来,是不是委屈你了?
WE做的都不是RTS,它只是证明了WC3本身的对战模式不受欢迎。
星际2包括星际1,本来就是一个小规模的,突出战略战术操作等等方面的游戏战略是指大方面,包括你出小狗还是出飞龙,升速度还是升攻击,战术操作不用多说就是为了突出紧张感,突出战术的多样性,因为部队数量相对少,操作相对简单,容易突出选手的技战术水平,而且并不妨碍你多线分兵和用任何战术,包括什么包围迂回等,这个就不多说了,因此,星际系列是战场的缩影,包含了真正战场一个很重要的因素=操作 提到操作,应该认识到三点 1 这是观众一个很大的兴奋点 2 目前来说选手能灵活控制的单位规模是有限的 3 因为人注意力和技术能力的限制,你显示全景越广,你显示局部就越粗糙,你显示局部越细,则全景就越不广,而且人都是或者注意全景,或者注意局部,是一心不能两用的,因此一般RTS都有小地图显示全景,画面来显示局部,即便你有超级大屏幕,而能既显示全景又显示足够细致的局部也是很麻烦的,因为那样你的脑袋就得或者朝上面三米看,或者朝右边2米看,不但颈椎容易受损,而且麻烦 -----------------因此,星际我认为应该保持自己的风格,让最指来保持最指的特色,没必要将星际最指化,这一点老虎说的不错,正因为一个游戏的一切都是配套的,因此不能单改一个人口就变成另一个游戏,星际2的地形是为堵口设计,但如果你有海量的部队,任何路口都堵不住,除此之外还有地图的大小以及其他相关设计等,所以无需将星际2弄成几百人口的游戏,毕竟游戏和游戏从设定、目的等等来说都是不同的
哎呦呦,终于开始恼羞成怒了。你好笑为什么我不能笑了。你在这里贻笑大方还不许别人指出来了吗?就那两个问题你就全都避而不谈转而说我的态度问题,好一双选择性遗失的眼睛。最可怕的是你居然还要说我是“选择性无视”。好一个包容天下的胸襟。 恩,果然还是“因为编辑器好玩所以blz的rts不好玩,因为编辑器强大所以导致blz的rts倒退,blz的rts倒退导致所有rts倒退” 顺便这句。。“即使是最辉煌的魔兽争霸时代,RTS的光辉也远不及FPS,RPG这几类游戏类型”。。。rts可真是比楼主还要非主流丫。受捕鸟呀受捕鸟
to 21L你信不信一个矿就可以支持500人口只要地图作者愿意?你是不是都不看我17l的回复的?不好意思,我忘说气矿了,气矿不能像水晶一样叠起来,不过刷刷两排还是没问题的。而且单位的价格是可以改的啊,50矿50气的坦克见过没?怎么可能存在经济支撑不了呢?造兵速度跟不上?cd时间是可以改的。何况TA你要提高速度,除了用辅助加速外,不也是一造就造好几个车间、船坞?造兵一次只能5个不能自动生产?很抱歉,这个还真的可以做到,你只需要在兵营里点一下,就会持续不断的出兵;你只需要点另一个兵的图标一下,就可以改变你要出的兵;你只需要点ESC一下,就可以停止造兵。不过好像做不到单个兵营一会造这个,一会造那个的生产方式,不过这个你只需要多添一个兵营就可以解决。地图小?星际的地图确实不算大,不过大到3V3,人口(不是单位数)还是可以的。另外,我从来不认为编辑器是万能的,想必那副图的作者还用了其他方法。但是,至少,要造出个和原版不一样的RTS还是可以的。我只是认为编辑器可以突破游戏本身的玩法,给人以另一种玩法。比如用编辑器,估计是无法实现TA的模拟弹道了。编辑器最大的制约因素恰恰是游戏本身。
星际有一种模式,你可以选择3个种族的起始农民,如果全部选择一个种族的话,则有800人口
另外,至少RTS在电竞领域是无可取代的,现在RTS在电竞方面的地位和影响力,已经基本超过了车枪球游戏,也超过了格斗游戏,在全世界各国都有职业战队,都有一大批研究和练习的职业玩家和选手,并且养活了很多专业电竞电视台---电竞方面,星际和魔兽等RTS表现都还是不错的,当然我希望大作不断涌现百花齐放 因此,电竞本身就可以让星际2大卖了,因为你要看录像,包括你要切磋,就要买星际2并且还有社区,更关键一点是星际2不耽误你太多时间--这一点是非常关键的,切磋一局大概用个十几二十分钟,符合现代人紧张时间不多的生活方式,并且看录像的时间也短,目前星际2为求推广,已经简化了不少微操作弄得更智能,也对于大众接受有好处 所以其实电竞行业本身就能给暴雪推广星际2不少助力,再加上游戏适当的时间规模限制,并不会耽误玩家太多时间,可以集中精力研究战术操作等,估计成功还是可期的
贴吧热议榜
使用签名档&&
保存至快速回贴【求助】魔兽人物操作界面为什么有些会不一样?_魔兽地图编辑器吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:51,389贴子:
【求助】魔兽人物操作界面为什么有些会不一样?
是根据什么改变的?并不是导入替换的那种,是魔兽本身有的。
365编辑器是一款拥有海量素材,动图图库,提供高效图文排版的内容编辑器. 支持实时预览,一键秒刷,多平台一键同步功能,极大提高小编工作效率的必备编辑工具编辑器
这天大的秘密终于被你发现了,低级炸鱼晋太元中苟
问题已解决~
…喵呜这…喵呜
你没玩过魔兽吧
各种族……
贴吧热议榜
使用签名档&&
保存至快速回贴魔兽争霸3的地图编辑器到底有多厉害? - 知乎有问题,上知乎。知乎作为中文互联网最大的知识分享平台,以「知识连接一切」为愿景,致力于构建一个人人都可以便捷接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,发现更大的世界。<strong class="NumberBoard-itemValue" title="被浏览<strong class="NumberBoard-itemValue" title="4,968分享邀请回答68146 条评论分享收藏感谢收起457200 条评论分享收藏感谢收起[模型问题]平面模型弄上贴图后,在编辑器里改变视角模型出BUG_魔兽地图编辑器吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:51,389贴子:
[模型问题]平面模型弄上贴图后,在编辑器里改变视角模型出BUG
如图,稍微改变一下视角模型就这样。。
365编辑器是一款拥有海量素材,动图图库,提供高效图文排版的内容编辑器. 支持实时预览,一键秒刷,多平台一键同步功能,极大提高小编工作效率的必备编辑工具编辑器
绿苹果是这样的
在线求问中
太低了 掉地面里面去了
仅仅调了下视角,结果模型从正常位置翻折到了图2位置。0.0
再来一个惊悚的栗子~~1个装饰物
有这种情况,一直不明原因。
…喵呜z轴不够高
…喵呜或者贴图问题
第一眼给我黑魂的感觉。。
如果照我的理论来说...........你可以在编辑器里重复这种bug新建一张地图,然后疯狂往里面塞各种单位,最后拉高镜头即可(如果没有问题,就接着塞更多的单位,这个问题总会出现的)模型由多边形组成,贴图结附在多边形上,形成编辑器中的可观测世界然后磨兽争霸每一帧刷新的能力有限,制图师的野心总会触及其底线,放置了过多的多边形和贴图最后魔兽(或者你的电脑)每一帧无法刷新这么多多边形(或者多边形上面的贴图什么的....细节我也不懂)上一帧的工作便会留到下一帧,依此类推,画面不能正常刷新,因而撕裂所以,我能想到的替代方案是:1.降低模型多边形数量2.降低贴图质量3.降低地形装饰物数量4.tj并开始下一张地图以上的胡言乱语如果吸引了真正的大神,希望您礼貌性的表达轻蔑后帮楼主解决这个问题,不要只做前一步,多谢最后祝楼主制图顺利,不要轻易选择第四步
来一张搞定后的地形~
很好,很好
像一个恐怖游戏??
画风不错羡慕
贴吧热议榜
使用签名档&&
保存至快速回贴【教程】没人能看懂的刷兵教程_魔兽地图编辑器吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:51,389贴子:
【教程】没人能看懂的刷兵教程
按照惯例,1L祭天防抽。
365编辑器是一款拥有海量素材,动图图库,提供高效图文排版的内容编辑器. 支持实时预览,一键秒刷,多平台一键同步功能,极大提高小编工作效率的必备编辑工具编辑器
(?o??ωo???)2l插队,前排卖座
如题,刷兵系统这种东西已经烂大街了,没什么新意。为什么还要写这个玩意?因为上一次有人问过我怎么做刷兵,小兵在行进的路上被网了或者根须缠绕了就不走了怎么办?所以既然有人问了,我就再做一个演示吧。
但是这演示恐怕不会有什么作用就是了,因为不要说问我的那个人看不懂了,连我自己都被绕了一会。
那这样说来的话为什么还要写这篇演示?还特意写这么长一串说明?不是闲的蛋疼么?
诶……反正都已经做了,就顺便把说明给写了吧。
魔兽这玩意都已经出了十多年了,当年玩魔兽的人都快成家了,然而WE在有了无数前人经验的情况下,仍然有一大堆人每天在问各种各样的问题。“一个已经被解决的问题不应该被解决第二次”,发生这种事情确实挺让人觉得可悲的。我觉得这不是因为我们的教程写得不够多,而是因为很多人都缺乏一种“分析并解决问题”的能力。通常情况下一谈到群众素质问题就可以立刻甩锅给教育,比如说中国的教育导致从这个体系中走出来的人习惯了“抄作业和背答案”,在做游戏的时候也是只求“这个技能怎么做”而不会去思考其背后的原理和思路,又或者碰到自己想不出的问题就求“这个东西怎么做”而不会去想自己会做什么,自己要做什么,自己缺少什么……
然而这还是扯淡,要是什么事情都能这么容易的找到一个背锅的,那这个世界未免也太轻松了吧……所以说上面的这么一大段话完全就是在放屁。还是让我们回到“该怎么做一个刷兵系统”的问题上来吧?
所以就按照上面说的,来看看这个问题要怎么“分析并解决”吧。
首先问一下你自己——刷兵是什么样的?——你自己得先对问题有一个清楚的认识,这样才能想出解决问题的方法呀?——哦,于是乎我觉得刷兵大概是这么一回事——
“每隔一段时间,从某个固定点产生一些单位,这些单位具有一定的种类和数量,被刷出来之后会沿着一条路线不停的进攻”
大概就是这么一回事吧?于是乎现在问题的答案立刻就变得明显起来了。
刷兵是每隔一段时间发生的,也就是说要实现刷兵,必须要想办法实现“每隔一段时间做一系列动作”这件事情。至于刷兵具体怎么刷,咱们先不管。那关于这件事情你有什么主意么?要是没有的话就说明你对魔兽的触发器究竟有哪些功能还不熟悉,这就需要你自己打开触发器重新看看触发器里究竟都有哪些事件和动作了。要实现跟时间相关的东西的话,用计时器,或者触发器的每隔一段事件触发一次的事件都可以。所以现在时间我们有了。2.
从某个固定点产生一些单位。固定点也很简单,魔兽有“点”类型的数据,同样也有在某个点创建单位的函数,所以说在某个点上创建单位应该是不难的。3.
刷出来的单位要有一定的种类和数量,拿DOTA来打比方,一波要刷出来4个近战兵和一个远程兵,隔了几波之后还要多刷几个兵再加上一个投石车。这个该怎么做?首先创建5个小兵无非就是把创建一个小兵的过程重复了五遍而已,这没什么大不了的。然后比较有问题的地方就是每隔几波兵加一个投石车,这就要求我们必须得想办法弄清楚现在已经刷了多少波兵,然后每当波数满足间隔的条件的时候就多刷一些兵。4.
被刷出来的小兵会沿着一条路线不停的进攻。哇哦,这句话就比较复杂了。首先,让单位朝着某个地方进攻是很简单的,只需要对单位发布一个进攻的命令就OK了。问题就在于这里很复杂,是要小兵沿着一条路径进攻,这样的话怎么办?而且小兵还要不停的进攻,万一小兵脑残了,被卡住了,或者被放了技能困住了之后发呆了,都不行。而且只有刷出来的小兵会沿着兵线进攻,地图上的其他小兵都必须不动,每条兵线的小兵进攻的路线都不一样。这问题,感觉好复杂呀……嗯,所以说去考虑这样一个复杂的问题肯定是没戏的,本着“复杂问题简单化”的原则,让我们来看看怎么把这个问题拆分成几个更加简单的问题:a)
首先,该怎么让小兵进攻我们已经知道了b)
第二,小兵的进攻不能停止,这个……要怎么做呢?这就需要你发挥一下想象力了,比如说我们可以每隔一段时间就对单位发布一次攻击命令,这样单位即使停下来了,也会在几秒钟之后又继续进攻。听起来这个主意不错。不过我比较喜欢另一个方法,那就是每隔零点几秒检查一次单位的当前命令是否是在进攻,假如不是,就重新对小兵发布进攻命令,因为这样单位的进攻要更顺畅一些。c)
第三是小兵要沿着一条路径进攻,这样子就有点复杂了呀……让我们来研究一下“沿着一条路线进攻”到底是怎么一回事吧。首先,我们研究一下小兵沿着一条直线进攻的情况——这TM就简单到爆了,我只需要不停的让小兵朝着直线的另一头进攻就行了。那么我们再把情况复杂一点——直线路径被折了一下,中间有一个拐角处,单位要沿着这样的路线进攻。这种路径其实也不复杂,就是两条直线路径的组合体而已,但是问题就在于当单位走到拐角处的时候,怎么样让单位沿着另外一条直线路径前进?我们来理一下这个过程吧:
单位沿着当前的直线路径前进,这个没有问题。
单位跑到了拐角处——且不论单位到了拐角处怎么拐弯,我们要怎样才能知道单位到了拐角处呢?这个“到了拐角处”又是什么意思呢?“拐角处”在哪里?多大算拐角处?——魔兽里实现这种事情的方法也有很多,比如说我可以假设拐角处是一个矩形区域,单位进入了矩形区域就算是到了拐角处了,再或者我们可以假设拐角处是一个点,我们可以判断单位与点的距离小于一定的范围就算到了拐角处了。
既然知道单位到了拐角处了,怎么样让单位沿着下一条路径前进呢?我们之前说过直线路径进攻很简单,单位在直线的这一头,就只需要对单位发布朝着直线的另一头前进的命令就OK了。所以说沿着另外一条直线进攻,无非就是单位进攻的目标点被转换了而已。那我们只需要在单位到了拐角处之后,改变单位的进攻目标点就行了。
改变单位的进攻目标点?等等你说的话我开始有点不明白了……魔兽里面的点有技能释放点,转化坐标点之类的这些点我知道,但是一个变化的点,那是什么玩意?要是你确实不知道这是怎么一回事,就说明你还没了解过一个叫做变量的东西。这个东西要解释起来就太长了,我还是给你推荐一个视频吧:bilibili.com/video/av2726389。我们可以用一个点变量把单位进攻的目标点给装起来,这样就只需要在拐角的时候把这个变量里装的点换成另外一个就OK啦~至于一整条路径,那不过是这个过程的不停重复而已。5.
除了这些事情之外,还有一件事情,那就是地图上不止有一个兵线,也不止有一个点在刷怪。这样的话事情会稍微变得复杂一点,举个例子——刷兵每隔一段时间进行,假如不同刷兵点的刷兵时间不同怎么办?什么?你说DOTA都是同时刷兵的?好吧那当我没说过……那么不同兵线的兵刷在不同点这总是肯定的吧?所以说“兵线”跟“刷兵点”是要捆绑在一起的东西,至于怎么捆,咱们暂时先不考虑。还有兵种的数量和类型,不过对于DOTA而言似乎每个兵线的兵种数量和类型都是一样的,但是天灾和近卫双方刷出来的兵是不一样的。这个要有点差别,所以说兵的种类是要跟兵线捆在一起的。诶,还有不同的兵线有不同的进攻路径点,这仿佛是一句废话。啊,好了问题就这么多了。
于是乎这个问题大概就这么分析完了,虽然说看上去好像蛮长的,但是跟着思路来理一理的话……好像也不简单啊……这就取决于你对编辑器的熟悉程度了。我个人一直相信“工欲善其事,必先利其器”,对工具的熟练也是一方面的——如果你连编辑器有哪些功能都不清楚,又谈什么做游戏地图呢?所以说宁愿先花个半年把编辑器的功能弄熟了,也好过边学边做然后把地图项目拖个一年半载的,中间还要被各种想爆脑袋都想不出的问题困扰,岂不是自讨苦吃? 在想明白这些事情之后我们就来看看这个事该怎么解决吧。虽然说现在一提到刷兵大家想到的好像都是DOTA那种三条兵线的刷兵,但是我们也不确定真的就要做那种刷兵啊?而且万一以后自己反悔了想要改刷兵怎么办?那还要把刷兵系统给大改一通不是太麻烦了?所以凡事都给自己留条后路比较好,我们不要把刷兵做得太死,比如小兵就只能从这里刷出来,沿着这条线走,没准以后地形一改,又要重新做过呢? 以灵活为基础考虑,也就是说刷兵过程中的很多东西,能用变量代替就用变量代替会比较好,这样万一以后我们想改,就只需要改一个变量的值就OK了。我们之前说过不同兵线的刷怪点,兵线,时间之类的东西都有可能不同,换而言之就是这些东西都要绑定在一起,不同兵线各用各的的,那么这个绑在一起,其实是有很多的方法的。先来看看我整理了一下有哪些东西是要绑的:
Player Owner(出的兵是哪个玩家的):字面意思,这条兵线出的兵是哪个玩家的兵。
Location Point(出兵点):字面意思,这条兵线刷的兵是从哪里刷的。
private Squad SpawningSquad(目前正在生成的小队):先不管这个。 Location[32] PathList(兵线的路径点):这个要理解起来似乎会更困难一些。简单点说就是,既然我们实现小兵沿着兵线进攻的方法是到了转折点就更改进攻目标点,那么所谓的兵线就完全可以看成是一堆转折点的集合体。我们可以把这些进攻转折点按照进攻的顺序排成一个列表。考虑到计算机中的存储容量并不是没有上限的,在计算机中尤其是如此,所以我给了一个数量上限——32。Int PathSize(路径点的数量):每一条兵线路径点的上限是32,但是实际上未必每条兵线的路径点都一定有32个。另一个方面,每条兵线的路径点数量也未必相同,有些兵线可能转折比较多呢?所以说路径点数量也要跟不同的兵线绑定在一起。 UnitType[32] UnitList(刷兵种类表):同样的,我们也不确定一条兵线会刷多少种兵,虽然说我知道你肯定会说DOTA确定了最多三种,但是风暴英雄里还有一个让兵线多刷小兵的英雄呢……所以凡事别这么绝对。所以和路径点列表一样,我们也需要一张表来记录刷兵类型的情况,上限就也定为32种兵吧。我还没见过哪个DOTA类游戏一次刷出32种兵的。Int UnitSize(刷兵种类的数量):同上,并不是一个兵线一定会刷32种兵,只是上限如此而已。我们要知道究竟刷多少种兵,也就是这个刷兵的列表有多长。Int[32] UnitNum(每种兵的数量):每种兵刷多少呢?比如DOTA是近战兵4个,远程兵1个,这些也是要记录的。Int[32] UnitInterval(每隔多少波刷一次):这种类型的兵多少波刷一次呢?比如DOTA里的投石车……呃,我也不记得多少波刷一次了。Int Wave(目前刷了多少波兵):就像我之前说过的一样,你得知道已经刷了多少波兵,才能知道这波兵该不该刷某些有间隔的兵。 Real Period(每一波刷兵间隔):刷兵间隔,很好理解吧?因为我觉得不一定每个兵线刷兵的时间都是一样的,没准你能通过什么道具或者技能来延缓刷兵时间呢?
Real Time(刷兵时间记数):这个跟实现隔一段时间刷兵的原理有关,暂时不说。
private Real SpawningTime(创建单位间隔时间记数):这个是某人的要求,某人觉得像DOTA那样小兵一下子就冒出来了不好看,要每隔0.5秒一个一个排队刷出来才比较好看。所以这个跟那个有关,别太在意。private Int SpawningUnit(正在创建的单位的索引):既然某人要求了小兵要一个一个的刷出来,我自然也就要知道每隔0.5秒刷的什么兵,又过了0.5秒该刷什么兵咯?
好啦,拖了半天了,这些东西究竟怎么绑在一起啊?诶……这个说起来,有点复杂。方法很多,但是我比较喜欢的是我自己的“面向对象”的那一套——原理太多了,我不会在这里解释,有兴趣的可以去我的帖子里看:tieba.baidu.com/p/?pn=2,注意第46楼。把这些东西绑在一起,在面向对象里叫做“封装”——虽然说这么解释既不全面也不完全正确,但是只要看得懂的人知道我在说什么,看不懂的人觉得好像是这么一回事就行了。
简单点说就是,我新建了以下数组变量:
Spawn_Owner
Spawn_PathList
Spawn_PathSize
Spawn_Period
Spawn_Point
Spawn_Time
Spawn_UnitInterval
Spawn_UnitList
Spawn_UnitNum
Spawn_UnitSize
Spawn_Wave
p_Spawn_SpawningSquad
p_Spawn_SpawningTime
p_Spawn_SpawningUnit
这些数组就是上我上面提到过的那些要绑定在兵线上的东西。然后我们假设“红方上路兵线”对应的编号为1,那我只需要在访问这些数组的时候都访问索引为1的位置,并将红方上路兵线的所有信息也存储在索引为1的位置,不就借助相同的索引把这些信息全部都关联起来了嘛?当然,PathList这种要更复杂一些,这个要借助模拟二维数组的访问规则,具体也请去查看我的教程吧:tieba.baidu.com/p/?pn=2,注意第40楼。
啊,那接下来的事情就很简单明了了……我假设其他兵线的编号分别是23456,那么红方中路的刷兵点就是Spawn_Point[2],绿方上路刷出来的小兵的拥有者玩家就是Spawn_Owner[4]……所有的属性都借助相同的索引捆在一起了。
关于这个编号是怎么来的,有一套专门的算法:
在这之前,我们先要声明两个整数数组变量:
Obj_Spawn_Num
然后这个算法是这样的:
Obj_Spawn_Allocate
设置 this =Obj_Spawn[0]
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
this 不等于 0
Then - 动作
设置 Obj_Spawn[0] = Obj_Spawn[this]
Else - 动作
设置 Obj_Spawn_Num = (Obj_Spawn_Num + 1)
设置 this = Obj_Spawn_Num
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
this 大于 8190
Then - 动作
设置 this = 0
Else - 动作
设置Obj_Spawn[this] = -1
之后我们只需要运行这个触发器,this变量中就会自动装着我们给某个兵线分配的编号,你只需要在设置相关兵线的时候运行这个触发器就够了。
同理,你也可能会发现这样的话这种编号的上限是8190,因为魔兽的数组大小是有上限的。这样下去的话就会有分配的编号太多,达到上限的风险。所以就好像魔兽里的点需要排泄一样,用过的编号也是需要回收的。回收的算法也是和分配的算法对应的:
Obj_Spawn_Deallocate
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
this 不等于 0
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Obj_Spawn[this] 小于 0
Then - 动作
设置 Obj_Spawn[this] = Obj_Spawn[0]
设置 Obj_Spawn[0] = this
Else - 动作
Else - 动作
在运行过这个触发器之后,this中装着的编号就会被回收,并在今后的分配中被重新分配给新的兵线——虽然说DOTA里面总共也就6个兵线,创建了也不需要回收。
这么讲似乎有些跨度太大了,因为好些人肯定都不会习惯触发器不加事件的这种做法。简单点说就是,我们可以把经常用,但是又非常长的动作单独放在一个触发器里面,然后我们就可以像使用BLZ给我提供的函数和动作一样,使用我们自制的“函数触发器”。只不过这种玩意的参数和返回值都要装在公共变量里而已。这里的参数(要回收的编号)和返回值(被分配的编号)就都装在this变量里。对于很多技能来讲也是同理,游戏里总是要有那么几个冲锋之类的技能,实际上无非就是改了个参数而已,却要重新再做一个触发器——这样不会很累么?所以单独把它们做成一个触发器,然后不同的参数用公共的变量来传递,就很轻松了。
这样的话我们就做到了随时给需要的兵线(DOTA的话就只在游戏开始的时候有需要)分配编号,然后将这个编号当做索引,就可以从数组中获取到对应兵线的属性这件事情了。不过还不光是兵线,还有另一组需要捆在一起的东西——那就是刷出来的小兵的各种属性:Group G(小队内的单位):首先我确定了刷出来的小兵是以小组为单位进行行动的。那么怎么确认一个小组里有哪些单位呢?——当然是把一波刷出来的小兵都装在一个单位组里了。这样只需要对单位组里的单位发布动作,就可以控制刷出来的一波小兵该如何进攻了。Location Dest(进攻目标点):小兵目前应该往哪里进攻?我们只需要维持小兵对这个目标点的进攻命令,然后在适当的时候改变目标点,就能做出各种歪歪扭扭的兵线了。 Location[32] Path(小队行动的路径点):同样也是路径点的……表格,但是小队的行动表格跟兵线存着的表格不大一样。这个之后会解释——这是一种队列结构。Int PathHead(小队行动的路径点的首节点索引):同上,之所以不是Size而是Head和Rear是跟这个队列结构有关的。
Int PathRear(小队行动的路径点的尾节点索引):同上
这些刷兵点啊,刷兵间隔啊,刷兵类型啊,都是刷兵兵线的属性,就好像人的名字和年龄一样。那么人还有吃喝拉撒睡之类的行为,兵线的行为是什么呢?——
诶……等一下,这样讲好像又有点太过头了——为什么要去想兵线的行为呢?兵线又不是活着的东西,怎么会有行为这种东西啊。
实际上这算是解决问题的思路的一部分。简单点说就是,我们可以分析一下一个问题中出现了哪些事物,这些事物具有哪些属性和行为,然后再琢磨怎么安排这些事物的属性和行为来解决问题。所以说为了解决刷兵的问题,就要想清楚兵线的“行为”,以及怎么利用它们来解决这个问题。
我觉得要做成刷兵系统这么一回事,需要兵线来完成以下这些事情:
staticCreate(GobPlayer(出的兵是哪个玩家的),GobPointX(出兵点),GobReal1(刷兵间隔))-&this:首先是创建,光给兵线分配一个编号还不够,兵线的一些属性是需要初始化的。反正兵线的某些属性都是非设置不可的,干脆就放到一个触发器里吧,省了一大堆的麻烦事。另外你可能发现了我写这些东西大概是有一个语法的。Static的意思是“静态的”,表示这个行为并不是某个兵线的行为,而是属于兵线这个整体概念的行为。兵线的创建本身并不是某个兵线的行为,只有在创建了之后才会存在兵线的“对象”。Create是这个行为的名字,创建,很好理解。()里面的是进行这个行为所需要的参数,比如说创建一个兵线你就必须得指定创建的单位属于哪个玩家,出兵点在哪里,刷兵的间隔是多少。这三个属性是逃不过,一定要设置的。最后是-&this,表明这个行为最终会返回一个结果,这个结果是保存在this这个变量里的,也就是创建出来的兵线对象。Destroy():然后是销毁。之前在教程中说排泄的时候我也提过了,任何数据,在被创建了之后,都要在没用的时候把它们重新回收,只要BLZ给你提供了回收的手段就要这么做。对于我们自己构造的对象,这条规则也同样适用。当然,DOTA的兵线并不需要销毁,因为DOTA的兵线是一直存在的。 StartSpawn():开始刷怪。诶……为什么会有这个东西?因为某人跟我说DOTA那样一次性就把所有兵刷出来不够帅,要一只一只的刷出来才好看。所以说刷一波兵,实际上还要分成一只一只刷出来的过程。这个行为的意思就是“刷怪开始”,然后慢慢的读取整个刷怪列表,把怪物慢慢刷完。
StopSpawn():同上,这个是用于停止刷怪的复位的行为。privateSpawnAction():这个行为有一个private的关键字,意思就是说这个行为是兵线自身私有的行为,不能在外部被调用。诶?真的吗?只需要给触发器的名字加一个p_的开头这个触发器就不能在兵线相关的触发器以外的地方调用了?——当然是不可能的啦……所以说private,static什么的这些关键字,都只是按照规则起名字给自己一个提醒罢了。你想遵守也好,不想遵守也罢了。啊,回到正题,这个行为是真正刷出小兵的行为,负责刷出从小兵列表里面读取出的小兵,因为这个行为必须在严格规定的流程支配下,刷兵才能正常进行,所以将其设置为了private,禁止兵线刷兵内部机制以外的调用,免得出乱子。 AddPath(GobPointX(添加的路径点)):添加路径点的动作。诶,按照思路来讲的话,路径点列表完全可以靠我们自己预设好,不需要专门做成一个自动的行为。不过一来是我嫌麻烦,二来是假如游戏中要求动态向兵线中增加新的路径点的话,手动添加就会比较麻烦了。所以这个行为是往路径点列表的末端新增加节点的。RemovePath(GobInt2(删除的路径点索引)):同上,既然有添加节点,就要有相应的删除节点嘛。虽然说没有也可以……因为这个功能并不算完善。GetPath(GobInt2(路径点索引))-&GobPointX:我们既然把路径点塞进了列表里,那么要怎么取出来呢……?诶,好像直接访问Spawn_PathList就行了吧?为何还要专门做成一个行为?这是因为在实际应用中存在一个问题,那就是点是存在列表里的,但是当把路径点添加给刷出来的小兵的时候,是需要生成兵线存储的路径点的副本的。除此之外,那一大堆的索引公式也很烦人。所以我就做成了一个行为来简化这个操作。SetPath(GobInt2(路径点索引),GobPointX):同理,假如说想动态的修改某个节点,比如说路径中的某个节点是会移动的,或者兵线的小兵进攻路线是可以改变的,那么就需要用到这个行为了。 AddUnit(GobUnitType(加入的兵种类型),GobInt1(兵种数量),GobInt2(兵种隔几波刷一次)):这个行为的意思是往小兵列表里面塞小兵。原理和路径点列表是一样的,只不过这个行为要塞的东西比较多而已。这个行为也是支持在游戏的过程中往刷兵列表里加单位的,比如说某个英雄会让兵线里多一只蝗虫之类的。RemoveUnit(GobUnitType(移除的兵种类型),GobInt1(兵种数量),GobInt2(兵种间隔)):有添加就做一个删除吧,没准会用得上呢?GetUnitIndex(GobUnitType(兵种类型),GobInt1(兵种数量),GobInt3(兵种间隔))-&GobInt2(兵种信息索引):这个是获取列表中小兵的索引。假如说我的列表里有一个“每隔3波刷一只的步兵”,我想把步兵改成骑士,但是我又不知道它存的索引怎么办?这个时候就需要这样一个行为来做这件事情,把它的索引返回在GobInt2里面。然后就可以配合SetUnitState使用了。GetUnitState(GobInt2(兵种信息索引))-&GobUnitType(兵种类型),GobInt1(兵种数量),GobInt2(兵种间隔)):同理,这个是用来获取列表中单位信息的。SetUnitState(GobInt2(兵种信息索引),GobUnitType(兵种类型),GobInt1(兵种数量),GobInt3(兵种间隔)):这个是用来设置对应位置上的单位信息的。
啊啊,这样一看真是觉得好多啊,实际上做起来也花了我几个小时的感觉。不过这个就先不管这么多吧,我们再来看看小队,需要做什么:
staticCreate()-&this:同上,也是创建。但是小队要更简单一点,没有什么需要传入的参数,只是单位组必须得新建,所以还是做了一个创建的行为。
Destroy():同上,销毁也是必要的。 InPath(GobPointX(进队列的路径点)):往队列里添加路径点。说起来我之前就讲过了,兵线存储路径点使用的是顺序表的结构,但是小队使用的是队列的结构呢。队列的结构是个神毛?简单点说就是类似于排队的结构,先来后到。一个队列结构有两种操作,一种是进队,一种是出队。出队是把队列中的第一个节点抽出来,进队是把新的节点加在队列的结尾。所以对于小队的路径节点也是一样的,先加入的节点会被先抽出来,这样只需要每经过一个转折点就清空当前目标路径点,换成从路径队列中抽出的节点就OK了。路径队列中的节点会按照兵线的路径顺序被抽出来,这样就做到按照兵线前进了。要是不太明白可以去看我的教程:tieba.baidu.com/p/?pn=2,注意第43楼。
OutPath()-&GobPointX(出队列的路径点):同上,这是抽出的行为。 MoveAction():小队真正的移动行为,包括该怎么移动的逻辑全部都包含在里面。这个不是private行为的原因在于小队有可能因为莫名的原因卡住,也有可能因为发布命令有间隔导致进攻不顺畅,没准我们还会需要在别的地方调用它以维持进攻的正常。
好,现在行为我们都列完了,是不是该来看看如何利用这些玩意把问题解决了? 首先既然咱们玩的是触发器,对这个东西的依赖性如此之大,那么对象具有的东西除了属性和方法(也就是之前所说的行为,换了个叫法而已)以外,还应该有个触发器才对。不管是刷兵也好,进攻也好,都是跟时间相关,要周期性进行的动作。所以对于兵线(Spawn,虽然说英文不是兵线的意思)和Squad(小组,刷出来的一波小兵)来讲,都需要一个以时间作为事件的触发器,来周期性的控制它们的行为:
Static MainLoop:这两个东西我都加了这样一个触发器,用来遍历所有的Spawn和Squad对象,指挥它们做自己该做的事情。
首先是Spawn,Spawn(兵线)的MainLoop逻辑是这样的:
Spawn_s_t_MainLoop
时间 - 每当游戏逝去 0.01 秒
Spawn_s_Switch 等于 TRUE
循环动作[循环整数A]从 1 到Obj_Spawn_Num, 运行 (Loop - 动作)
Loop - 动作
设置 this = 循环整数A [R]
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Obj_Spawn[this] 小于或等于 0
Then - 动作
设置 Spawn_Time[this] =(Spawn_Time[this] + 0.01)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningUnit[this] 大于 0
Then - 动作
设置 p_Spawn_SpawningTime[this] =(p_Spawn_SpawningTime[this] + 0.01)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningTime[this] 大于或等于 0.50
Then - 动作
设置 p_Spawn_SpawningTime[this] = 0.00
设置 p_Spawn_SpawningUnit[this] =(p_Spawn_SpawningUnit[this] + 1)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningUnit[this]小于或等于Spawn_UnitSize[this]
Then - 动作
触发器 - 运行 p_Spawn_SpawnAction &预设& (检查条件)
Else - 动作
触发器 - 运行 Spawn_StopSpawn &预设& (检查条件)
Else - 动作
Else - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Spawn_Time[this] 大于或等于 Spawn_Period[this]
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Spawn_UnitSize[this] 大于 0
p_Spawn_SpawningUnit[this] 等于 0
Then - 动作
触发器 - 运行 Spawn_StartSpawn &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningUnit[this] 小于或等于 Spawn_UnitSize[this]
Then - 动作
触发器 - 运行 p_Spawn_SpawnAction &预设& (检查条件)
Else - 动作
触发器 - 运行 Spawn_StopSpawn &预设& (检查条件)
Else - 动作
Else - 动作
Else - 动作
让我们来分析一下这个触发器的逻辑是怎么一回事:
首先,事件是每当游戏逝去0.01秒,这个很好理解,毕竟刷兵是周期性进行的动作。
然后条件里有一个Spawn_s_Switch等于true,这个Spawn_s_Switch相当于刷兵系统的开关,设置为false刷兵系统就会停止运作。
那么动作是循环整数1~Obj_Spawn_Num。Obj_Spawn_Num的意思是现在已经分配出去了多少个Spawn对象的地址,只需要循环1~Obj_Spawn_Num,就可以将所有存在的Spawn对象都遍历一遍。所以只需要设置this = 循环整数A,就可以针对所有存在的Spawn对象进行操作了。当然未必所有已经被分配的编号都是正在工作的,有些可能已经被回收了,对于被回收的东西就没有继续让它工作的必要了。所以要加个条件,Obj_Spawn[this]小于或等于0,别问我为什么,反正按照之前那套allocate和deallocate的原理,Obj_Spawn[this]小于或等于0就表示this里面装着的编号还没被回收。
没被回收的话要干什么?
首先是要 设置 p_Spawn_SpawningTime[this] = (p_Spawn_SpawningTime[this] + 0.01),p_Spawn_SpawningTime是Spawn对象的时间计时。
然后在 Spawn_Time[this] 大于或等于 Spawn_Period[this] ,也就是时间计时达到了刷兵的间隔的时候,就要执行关于刷兵的动作——也就是 触发器 - 运行 Spawn_StartSpawn &预设& (检查条件) 了。我们来看看这个方法干了些什么?:
Spawn_StartSpawn
触发器 - 运行 GobStackPushReg &预设& (检查条件)
触发器 - 运行 GobStackPushArray &预设& (检查条件)
-------- 设置当前刷兵列表索引--------
设置p_Spawn_SpawningUnit[this] = 1
-------- 重置计时器 --------
设置Spawn_Time[this] = 0.00
设置GobIntArray[0] = 3
设置GobIntArray[2] = this
触发器 - 运行 GobStackPushThis &预设& (检查条件)
-------- 新建Squad对象 --------
触发器 - 运行 Squad_s_Create &预设& (检查条件)
-------- 添加路径队列--------
循环动作[GobInt3]从 1 到 Spawn_PathSize[GobIntArray[2]], 运行 (Loop - 动作)
Loop - 动作
设置 GobInt2 = (((GobIntArray[2] - 1) x 32) + GobInt3)
设置 GobPointX = Spawn_PathList[GobInt2]
触发器 - 运行Squad_InPath &预设& (检查条件)
设置GobIntArray[1] = this
触发器 - 运行 GobStackPopThis &预设& (检查条件)
-------- 设置当前刷兵小队对象--------
设置p_Spawn_SpawningSquad[this] = GobIntArray[1]
触发器 - 运行 GobStackPopArray &预设& (检查条件)
触发器 - 运行 GobStackPopReg &预设& (检查条件)
老天……从这里开始我好像有点看不懂了,或者说我其实一开始就没看懂?
这些GobStackPushXXX和GobStackPopXXX是干什么用的?
这个是用来解决一些问题了。因为大家观察了可能都发现了,我最常用的整数变量,也就只有GobInt1,GobInt2,GobInt3,GobInt4这四个而已,而且它们各自有各自的用法。并不是我懒得申请更多的变量,因为变量太多的话,管理起来会很麻烦,而太少的话,又会不够用,所以我觉得四个是非常合适的。但是就算非常合适,这里也还会有一个问题——假如我在使用这四个变量的时候,里面就已经存了其他我不想丢掉的数据怎么办?
尤其是在我这种把触发器当成函数用的情况下更是如此,常常会发生我调用其他的触发器,结果在这些触发器里面又使用过这些变量,导致我在调用这些触发器之前存在变量里面的数据丢失了。啊,当然,YDWE有一个非常屌的方法来解决这一切问题,那就是——不使用全局变量,全用局部变量,全局变量只用来传递参数和返回值。但是我没用这个方法(纯粹的自讨苦吃),所以我用了栈来解决这个问题——在调用触发器的一开始先把变量里面的值存在栈(Stack)里面,然后中间我可以随便的乱用这些变量,完事了之后再把保存在栈里的值重新取回变量里,这样这些变量就好像我没有用过一样,仍然保存着之前的值。这不就很完美啦?而且用栈来做这件事情,不管你调用多少层触发器都没事——额,这倒不是真的,最多只能调用2000重触发器而已……
反正就是这么一回事。其中GobStackPushReg是把4个整数变量的值给存起来了,Reg是寄存器的意思。至于GobStackPushArray,是把GobIntArray里面的值给存了起来。
后面的事情就更容易看懂一些了。
设置 p_Spawn_SpawningUnit[this] = 1 是在设置当前刷兵列表索引,表示刷兵从列表的第一项开始刷,你不爽的话改成直接从第二项开始刷也可以,这样列表中的第一个就会被忽略掉。我把p_Spawn_SpawningUnit[this]是否为0当做现在有没有开始进入刷兵状态的条件。
然后是 设置 Spawn_Time[this] = 0.00,这个的意思是重置刷兵的计时周期,让刷兵的计时重新开始工作。
设置 GobIntArray[0] = 3 的意思是申请使用GobIntArray中1~3的空间,在这个触发器中我使用了GobIntArray,如果我再调用什么也使用了GobIntArray的触发器,那个触发器里面就应该也会运行GobStackPushArray触发器,把1~3中的数据保存起来,末了再读取回来,这样就不会影响我申请的空间的使用了。
设置 GobIntArray[2] = this 是把this给保存起来了。因为接下来涉及到另外一个对象的操作,this里面装的是现在操作的对象,因此必须要先保存。不过这个保存是交给了GobStackPushThis的,存在数组里是为了之后我们能使用这个this,也就是目前正在操作的兵线(Spawn)对象。
然后就是新建Squad对象了。因为是刷出来的小兵都是以Squad为单位进行活动的,所以刷兵的过程中要把创建的小兵都装在一个Squad里面。所以这里运行了触发器 - 运行 Squad_s_Create &预设& (检查条件)。这个触发器里面是这样的:
Squad_s_Create
触发器 - 运行 Obj_Squad_Allocate &预设& (检查条件)
设置Squad_G[this] = (新建的空单位组)
设置Squad_PathHead[this] = 0
设置Squad_PathRear[this] = 0
恩,没啥复杂的,就是新建了一个单位组,初始化了一下Squad的路径队列而已。然后this就变成了新建的这个Squad对象了。
然后我们对这个Squad进行操作,把兵线的路径点列表里的路径点都加到新建的Squad对象里,也就是:
循环动作[GobInt3]从 1 到 Spawn_PathSize[GobIntArray[2]], 运行 (Loop - 动作)
Loop - 动作
设置 GobInt2 =(((GobIntArray[2] - 1) x 32) + GobInt3)
设置 GobPointX =Spawn_PathList[GobInt2]
触发器 - 运行 Squad_InPath &预设& (检查条件)
最后把this存到IntArray[1]里面,待会要用。然后就可以PopThis了,此时的this就不是我们新建的Squad了,而是之前就在操作的Spawn。然后设置 p_Spawn_SpawningSquad[this] =GobIntArray[1],之后在SpawnAction里面创建的小兵就都会被添加到我们之前创建的Squad对象里。最后运行一下Pop触发器,把之前存进来的东西读回去。这个触发器就运行完了。
你看,这并不复杂……个屁啊。好吧我承认我自己都有点晕了(不过事实证明这套东西还是有点用处的,毕竟我把系统做出来了嘛。
回到MainLoop的逻辑来,运行Spawn_StartSpawn有两个前提条件,1是UnitSize大于0,意思就是说这个兵线要有兵可刷,要不然的话刷不出兵还运行StartSpawn干嘛。2是p_Spawn_SpawningUnit等于0,否则就表示现在已经开始刷兵了,就没有再次启动刷兵的必要了。 接下来是判定SpawningUnit是否大于UnitSize,要是大于就说明兵已经刷完了,就应该调用Spaw_StopSpawn,否则就应该调用p_Spawn_SpawnAction,实际的把兵刷出来……诶,等一下,为什么这个东西会出现在这里?因为StartSpawn之后就要刷第一波兵呀。 然后是加在计时累加下面的:如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningUnit[this] 大于 0
Then - 动作
设置 p_Spawn_SpawningTime[this] = (p_Spawn_SpawningTime[this] + 0.01)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningTime[this] 大于或等于 0.50
Then - 动作
设置 p_Spawn_SpawningTime[this] = 0.00
设置 p_Spawn_SpawningUnit[this] = (p_Spawn_SpawningUnit[this] + 1)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
p_Spawn_SpawningUnit[this] 小于或等于 Spawn_UnitSize[this]
Then - 动作
触发器 - 运行 p_Spawn_SpawnAction &预设& (检查条件)
Else - 动作
触发器 - 运行 Spawn_StopSpawn &预设& (检查条件)
Else - 动作
Else - 动作 这个是什么意思?首先p_Spawn_SpawningUnit[this] 大于 0 的意思就是目前正在刷兵中,开始刷兵了才执行关于刷兵的动作。然后设置 p_Spawn_SpawningTime[this] = (p_Spawn_SpawningTime[this] + 0.01) 是刷兵的时间累加,之前那个时间累加是刷兵间隔的时间累加。假如p_Spawn_SpawningTime[this] 大于或等于 0.50,就说明过了0.5秒,可以刷刷兵列表上的下一项兵了。首先要设置p_Spawn_SpawningTime[this] = 0.00,重置一下刷兵的间隔,然后再设置 p_Spawn_SpawningUnit[this] =(p_Spawn_SpawningUnit[this] + 1),也就是读取刷兵列表中的下一个刷兵项目。最后就是刷兵,但是假如列表读到尽头了,就运行StopSpawn。 这个逻辑……并不难——个鬼啊!算了算了咱们还是来看看SpawnAction是怎么做的吧: p_Spawn_SpawnAction
触发器 - 运行GobStackPushReg &预设& (检查条件)
设置 GobInt2 = (((this - 1) x 32) + p_Spawn_SpawningUnit[this])
循环动作[GobInt3]从 1 到Spawn_UnitNum[GobInt2], 运行 (Loop - 动作)
Loop - 动作
设置 GobUnitActor = (新建 Spawn_Owner[this] 的 Spawn_UnitList[GobInt2] 在 Spawn_Point[this] 面向角度:(Spawn_Point[this] 到 Spawn_PathList[(((this - 1) x 32) + 1)] 的角度) 度)
AI - 忽视 GobUnitActor 的警戒点
单位 - 对 GobUnitActor发布 攻击移动命令到目标点:Squad_Dest[p_Spawn_SpawningSquad[this]]
单位组 - 为Squad_G[p_Spawn_SpawningSquad[this]] 添加 GobUnitActor
触发器 - 运行 GobStackPopReg &预设& (检查条件) 这个不难看懂。首先因为这里面用了四个整数变量中的一个,所以要调用一下Push触发器把它们存起来再取出去。然后是设置GobInt2为换算出的访问索引,也就是目前正在刷的兵的索引。最后来个循环,循环的数量等于要刷的兵的数量,然后创建单位,忽略警戒点(要不然单位会往回跑),发布攻击命令,再把单位加到我们之前创建过的Squad里面。这事就这么成了。 至于StopSpawn呢: Spawn_StopSpawn
设置 p_Spawn_SpawningUnit[this] = 0
设置 p_Spawn_SpawningSquad[this] = 0 这玩意更简单,无非就是把正在创建的单位索引和正在创建的小队都归零了而已。这样MainLoop就会判断目前不处于刷兵状态。于是乎刷兵的逻辑差不多就是这么一回事了——把所有创建的Spawn对象过一遍,累加它们的时间,要是到了就开始刷兵然后重置事件,然后刷兵时间也累加,每到0.5s就刷一次兵,直到列表里的兵刷完为止。
至于什么往列表里添加节点,往列表里添加单位,我们待会再来看。先来看看Squad的进攻是怎么做的吧: Squad_s_t_MainLoop
时间 - 每当游戏逝去 0.50 秒
循环动作[循环整数A]从 1 到 Obj_Squad_Num, 运行 (Loop - 动作)
Loop - 动作
设置 this = 循环整数A [R]
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Obj_Squad[this] 小于或等于 0
Then - 动作
触发器 - 运行 Squad_MoveAction &预设& (检查条件)
Else - 动作 相比之下Squad的MainLoop真是简单啊,就是遍历一遍所有的Squad然后运行一下Squad_MoveAction就完事了,真是轻松。那再来看看MoveAction是怎么做的吧: Squad_MoveAction
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(Squad_G[this] 中的单位数量) 大于 0
Then - 动作
设置 GobPointY = (坐标(0.00, 0.00))
单位组 - 选取Squad_G[this] 内所有单位做动作
Loop - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
((选取单位) 是存活的) 等于 TRUE
Then - 动作
点 - 移动 GobPointY 到(((GobPointY 的X轴坐标) + ((选取单位) 所在X轴坐标)),((GobPointY的Y轴坐标) + ((选取单位) 所在Y轴坐标)))
Else - 动作
单位组 - 为 Squad_G[this] 删除 (选取单位)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(Squad_G[this] 中的单位数量) 小于或等于 0
Then - 动作
触发器 - 运行 Squad_Destroy &预设& (检查条件)
触发器 - 运行 GobStackPopReg &预设& (检查条件)
跳过剩余动作
Else - 动作
点 - 移动 GobPointY 到(((GobPointY 的X轴坐标) / (转换(Squad_G[this] 中的单位数量) 为实数)),((GobPointY 的Y轴坐标) / (转换(Squad_G[this] 中的单位数量) 为实数)))
设置 GobReal1 = (Squad_Dest[this] 和 GobPointY 之间的距离)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
GobReal1 小于 400.00
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Squad_PathRear[this] 不等于 Squad_PathHead[this]
Then - 动作
触发器 - 运行 Squad_OutPath &预设& (检查条件)
点 - 清除 Squad_Dest[this]
设置 Squad_Dest[this] = GobPointX
Else - 动作
Else - 动作
单位组 - 选取Squad_G[this] 内所有单位做动作
Loop - 动作
设置 GobPointX = ((选取单位) 的位置)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(GobPointX 和 GobPointY 之间的距离) 大于或等于 500.00
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
((选取单位) 的当前命令ID.) 不等于 (转换 move 为命令ID)
Then - 动作
单位 - 对 (选取单位) 发布 移动 命令到目标点: GobPointY
Else - 动作
Else - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
((选取单位) 的当前命令ID.) 不等于 (转换 attack 为命令ID)
Then - 动作
单位 - 对 (选取单位) 发布 攻击移动 命令到目标点: Squad_Dest[this]
Else - 动作
点 - 清除 GobPointX
点 - 清除 GobPointY
Else - 动作
触发器 - 运行Squad_Destroy &预设& (检查条件)
触发器 - 运行GobStackPopReg &预设& (检查条件) 恩,首先GobStackPushReg这个没啥好讲了,因为这个触发器里也用到了那四个整数变量,我不希望我在别的地方调用了一下这个触发器然后整数变量里的值就莫名其妙的变了。然后就是判定一下Squad_G[this]中的单位数量大于0,不然的话小队里连兵都没有,这还进攻个毛啊?——假如没兵,就把这个小队销毁掉。要不然的话小队的数量上限只有255个,除以6的话刷四十多波兵……好像一盘DOTA也打完了吧……算了,总而言之养成没用的东西就销毁掉是好习惯。那假如小队里面还有人,就先新建一个点装在GobPointY里面,然后选取小队里的所有单位,将它们的坐标值累加到这个点上,把死了没用的单位剔除掉,最后除以单位组中单位数量,就求出了小队所有单位的平均坐标,也就是中心点了。注意要判定一下单位组中的单位数量在被删掉没有用的单位之后是不是为0了,为0了就要直接终止当前触发器,不然就会出除0BUG,游戏就直接崩溃了。求出小队的中心坐标有什么用?我们的进攻是以小队为单位的,所以我们可以判定一下小队离当前目标点的距离,假如距离小于400了,就说明小队在这个目标转角点附近了,这样我们就可以将其设置为下一个转角点了,然后单位就会接着往下一个点进攻——这样曲折的进攻路线不就做出来了嘛!然后就是再次选取Squad_G[this]里面的单位做动作,这里加了一个判断单位离小队中心的距离,假如太远就说明这个单位脱队了,这样的话就命令这个单位往小队中心赶,并且发布的是移动命令,就算旁边有人在打你,赶回小队才是最重要的。假如没脱队的话,就往当前目标点进攻吧。注意不要太频繁的发布进攻命令,因为WAR3的寻路就是个辣鸡,这么频繁的发布进攻命令魔兽会处理不过来。所以要判定一下单位当前已经在移动或者进攻的话,就不发布命令了。 好,现在刷兵和进攻就都做好了……只剩下在游戏的一开始创建Spawn对象了,在创建了之后这些Spawn对象就会自动开始刷兵。
Spawn_s_onInit
地图初始化
设置 Spawn_s_Switch = TRUE
-------- 红色上路 --------
设置 GobPlayer = 玩家1(红色)
设置 GobPointX = (坐标(-1900.00, -1750.00))
设置 GobReal1 = 30.00
触发器 - 运行Spawn_s_Create &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(-1800.00, -700.00))
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(-.00))
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(-00.00))
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(-00.00))
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(500.00, 2450.00))
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (坐标(50.00))
触发器 - 运行 Spawn_AddPath&预设& (检查条件)
点 - 清除 GobPointX
设置 GobPointX = (炮塔 0019 &预设& 的位置)
触发器 - 运行Spawn_AddPath &预设& (检查条件)
点 - 清除 GobPointX
设置 GobUnitType = 步兵
设置 GobInt1 = 1
设置 GobInt2 = 1
触发器 - 运行 Spawn_AddUnit&预设& (检查条件)
设置 GobUnitType = 步兵
设置 GobInt1 = 1
设置 GobInt2 = 1
触发器 - 运行Spawn_AddUnit &预设& (检查条件)
设置 GobUnitType = 步兵
设置 GobInt1 = 1
设置 GobInt2 = 1
触发器 - 运行Spawn_AddUnit &预设& (检查条件)
设置 GobUnitType = 步兵
设置 GobInt1 = 1
设置 GobInt2 = 1
触发器 - 运行Spawn_AddUnit &预设& (检查条件)
设置 GobUnitType = 矮人火枪手
设置 GobInt1 = 1
设置 GobInt2 = 1
触发器 - 运行Spawn_AddUnit &预设& (检查条件) 因为这个触发器里面初始化了六个刷兵器,略微有点长,所以我把剩下五个都去掉了。这个初始化的过程很简单,首先设置Spawn_s_Switch为true,这样就表示刷兵系统开始运作了,之后再设置参数变量,GobPlayer里面装的是红色上路刷出来的兵的拥有者,GobPoint装的是刷兵点,GobReal1装的是刷兵间隔,然后运行Spawn_s_Create,就会自动读取这些信息创建Spawn对象: Spawn_s_Create
触发器 - 运行Obj_Spawn_Allocate &预设& (检查条件)
设置 Spawn_Owner[this] = GobPlayer
设置 Spawn_Point[this] = (坐标((GobPointX 的X轴坐标),(GobPointX 的Y轴坐标)))
设置 Spawn_Period[this] = GobReal1
设置 Spawn_Time[this] = 0.00
设置 p_Spawn_SpawningTime[this] = 0.00
设置p_Spawn_SpawningUnit[this] = 0
设置 Spawn_Wave[this] = 0 这个没什么好说的,就是设置对应的属性而已。 然后还有销毁的触发器: Spawn_Destroy
点 - 清除Spawn_Point[this]
设置 p_Spawn_SpawningSquad[this] = 0
循环动作[循环整数A]从 1 到 Spawn_PathSize[this], 运行 (Loop - 动作)
Loop - 动作
设置 GobInt2 = (((this - 1) x 32) + 循环整数A [R])
点 - 清除Spawn_PathList[GobInt2]
设置 Spawn_PathSize[this] = 0
循环动作[循环整数A]从 1 到 Spawn_UnitSize[this], 运行 (Loop - 动作)
Loop - 动作
设置 GobInt2 = (((this - 1) x 32) + 循环整数A [R])
设置 Spawn_UnitList[GobInt2] = 没有单位类型
设置 Spawn_UnitNum[this] = 0
设置 Spawn_UnitInterval[this] = 0
设置 Spawn_UnitSize[this] = 0
设置 Spawn_Wave[this] = 0
设置 Spawn_Period[this] = 0.00
设置 Spawn_Time[this] = 0.00
设置 p_Spawn_SpawningTime[this] = 0.00
设置 p_Spawn_SpawningUnit[this] = 0
触发器 - 运行Obj_Spawn_Deallocate &预设& (检查条件) 这个触发器也跟创建差不多,但是把PathList里面的点和UnitList里面的单位都给清空了。
接下来就是要用到AddPath了,调用它们的方式之前已经说过了,所以就不再讲了。来看看这个触发器具体是怎么做的吧: Spawn_AddPath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Spawn_PathSize[this] 小于 32
Then - 动作
设置 Spawn_PathSize[this] = (Spawn_PathSize[this] + 1)
设置 GobInt2 = (((this - 1) x 32) + Spawn_PathSize[this])
设置 Spawn_PathList[GobInt2] = (坐标((GobPointX 的X轴坐标),(GobPointX 的Y轴坐标)))
Else - 动作
触发器 - 运行GobStackPopReg &预设& (检查条件) 这个触发器的内容也很简单,就是把PathSize加一,然后换算出真正的索引装在GobInt2里面,最后再设置Spawn_PathList为复制GobPointX的副本。没啥难懂的。 Spawn_RemovePath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(0 大于 GobInt2) 且 (GobInt2 小于或等于 Spawn_PathSize[this])
Then - 动作
设置 GobInt2 = (((this - 1) x 32) + GobInt2)
点 - 清除Spawn_PathList[GobInt2]
设置 GobInt4 = (((this - 1) x 32) + Spawn_PathSize[this])
循环动作[GobInt3]从 GobInt2 到 GobInt4, 运行 (Loop - 动作)
Loop - 动作
设置 Spawn_PathList[GobInt3] =Spawn_PathList[(GobInt3 + 1)]
设置 Spawn_PathList[GobInt4] = (坐标(0.00, 0.00))
点 - 清除Spawn_PathList[GobInt4]
设置 Spawn_PathSize[this] = (Spawn_PathSize[this] - 1)
Else - 动作
触发器 - 运行GobStackPopReg &预设& (检查条件) RemovePath跟添加差不多,把对应索引上的点删掉,然后再把其他的点往前移,再把原来是最靠后的那个点删掉,最后把pathSize减一,就完成了从列表中删除一个点的操作。Spawn_GetPath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(0 小于 GobInt2) 且 (GobInt2 小于或等于 Spawn_PathSize[this])
Then - 动作
设置 GobInt2 = (((this - 1) x 32) + GobInt2)
设置 GobPointX = (坐标((Spawn_PathList[GobInt2] 的X轴坐标),(Spawn_PathList[GobInt2] 的Y轴坐标)))
Else - 动作
触发器 - 运行GobStackPopReg &预设& (检查条件) GetPath就是读个点而已,没啥好讲的。 Spawn_SetPath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
(0 大于 GobInt2) 且 (GobInt2 小于或等于 Spawn_PathSize[this])
Then - 动作
设置 GobInt2 = (((this - 1) x 32) + GobInt2)
点 - 移动Spawn_PathList[GobInt2] 到((GobPointX 的X轴坐标),(GobPointX的Y轴坐标))
Else - 动作
触发器 - 运行 GobStackPopReg&预设& (检查条件) SetPath同理GetPath。 Spawn_AddUnit
触发器 - 运行GobStackPushReg &预设& (检查条件)
触发器 - 运行GobStackPushArray &预设& (检查条件)
设置 GobIntArray[1] = GobInt1
设置 GobIntArray[2] = GobInt2
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Spawn_UnitSize[this] 小于 32
Then - 动作
设置 Spawn_UnitSize[this] = (Spawn_UnitSize[this] + 1)
设置 GobInt2 = (((this - 1) x 32) + Spawn_UnitSize[this])
设置 Spawn_UnitList[GobInt2] = GobUnitType
设置 Spawn_UnitNum[GobInt2] = GobInt1
设置 Spawn_UnitInterval[GobInt2] = GobInt2
Else - 动作
触发器 - 运行GobStackPopArray &预设& (检查条件)
触发器- 运行 GobStackPopReg &预设& (检查条件) AddUnit同理AddPath。 Spawn_RemoveUnit
触发器 - 运行GobStackPushReg &预设& (检查条件)
触发器 - 运行GobStackPushArray &预设& (检查条件)
设置 GobIntArray[0] = 2
设置 GobIntArray[1] = GobInt1
设置 GobIntArray[2] = GobInt2
设置 GobInt2 = 0
循环动作[GobInt3]从 (((this - 1) x 32) + 1) 到 (((this - 1) x 32) + Spawn_UnitSize[this]), 运行 (Loop - 动作)
Loop - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
GobUnitType 等于 Spawn_UnitList[GobInt3]
GobIntArray[1] 等于 Spawn_UnitNum[GobInt3]
GobIntArray[2] 等于 Spawn_UnitInterval[GobInt3]
Then - 动作
设置 GobInt2 = GobInt3
Else - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
GobInt2 不等于 0
Then - 动作
设置 Spawn_UnitList[GobInt2] = 没有单位类型
设置 Spawn_UnitNum[GobInt2] = 0
设置 Spawn_UnitInterval[GobInt2] = 0
设置 GobInt4 = (((this - 1) x 32) + Spawn_UnitSize[this])
循环动作[GobInt3]从 GobInt2 到 GobInt4, 运行 (Loop - 动作)
Loop - 动作
设置 Spawn_UnitList[GobInt3] =Spawn_UnitList[(GobInt3 + 1)]
设置 Spawn_UnitNum[GobInt3] =Spawn_UnitNum[(GobInt3 + 1)]
设置 Spawn_UnitInterval[GobInt3] =Spawn_UnitInterval[(GobInt3 + 1)]
设置 Spawn_UnitList[GobInt4] = 没有单位类型
设置 Spawn_UnitNum[GobInt4] = 0
设置 Spawn_UnitInterval[GobInt4] = 0
设置 Spawn_UnitSize[this] = (Spawn_UnitSize[this] - 1)
Else - 动作
触发器 - 运行GobStackPopArray &预设& (检查条件)
触发器 - 运行GobStackPopReg &预设& (检查条件) RemoveUnit要更加复杂一点,因为RemoveUnit的参数并不是某个索引,而是兵种类型,数量和间隔,这就需要你想办法去从列表中检索出对应的项目,然后再将其删掉。不过检索并不是很难,过一遍用条件判断一下就OK了,然后就跟RemovePath一个道理了。 Spawn_GetUnitIndex
触发器 - 运行GobStackPushCX &预设& (检查条件)
触发器 - 运行GobStackPushArray &预设& (检查条件)
设置 GobIntArray[0] = 2
设置 GobIntArray[1] = GobInt1
设置 GobIntArray[2] = GobInt2
设置 GobInt2 = 0
循环动作[GobInt3]从 (((this - 1) x 32) + 1) 到 (((this - 1) x 32) + Spawn_UnitSize[this]), 运行 (Loop - 动作)
Loop - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
GobUnitType 等于 Spawn_UnitList[GobInt3]
GobIntArray[1] 等于 Spawn_UnitNum[GobInt3]
GobIntArray[2] 等于 Spawn_UnitInterval[GobInt3]
Then - 动作
设置 GobInt2 = GobInt3
Else - 动作
触发器 - 运行GobStackPopArray &预设& (检查条件)
触发器 - 运行GobStackPopCX &预设& (检查条件) GetUnitIndex就是把RemoveUnit里面的检索操作给额外抽出来了,因为SetUnitState方法要配合这个使用。 Spawn_GetUnitState
设置 GobUnitType = Spawn_UnitList[(((this - 1) x 32) + GobInt2)]
设置 GobInt1 = Spawn_UnitNum[(((this - 1) x 32) + GobInt2)]
设置 GobInt2 = Spawn_UnitInterval[(((this - 1) x 32) + GobInt2)] GetUnitState更是简单的一笔。 Spawn_SetUnitState
触发器 - 运行GobStackPushReg &预设& (检查条件)
触发器 - 运行GobStackPushArray &预设& (检查条件)
设置 GobIntArray[0] = 2
设置 GobIntArray[1] = GobInt1
设置 GobIntArray[2] = GobInt3
设置 GobInt2 = (((this - 1) x 32) + GobInt2)
设置 Spawn_UnitList[GobInt2] = GobUnitType
设置 Spawn_UnitNum[GobInt2] = GobIntArray[1]
设置 Spawn_UnitInterval[GobInt2] = GobIntArray[2]
触发器 - 运行GobStackPopArray &预设& (检查条件)
触发器 - 运行GobStackPopReg &预设& (检查条件) SetUnitState就需要你用GetUnitIndex来找出你想要修改的兵种项目,然后用这个修改成你想要的样子。 在了解完这些触发器怎么工作之后,onInit触发器里面之后的添加路径点和单位列表的操作就都明了了。没啥好讲的。
那么Squad的添加路径点呢?好像跟这个不太一样?来看看吧,这两个触发器是这样的: Squad_InPath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
((Squad_PathRear[this] + 1) mod 32) 不等于 Squad_PathHead[this]
Then - 动作
设置 GobInt2 = (((this - 1) x 32) + Squad_PathRear[this])
设置 Squad_PathList[GobInt2] = (坐标((GobPointX 的X轴坐标),(GobPointX 的Y轴坐标)))
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Squad_PathHead[this] 等于 Squad_PathRear[this]
Then - 动作
设置 Squad_Dest[this] =Squad_PathList[GobInt2]
Else - 动作
设置 Squad_PathRear[this] = ((Squad_PathRear[this] + 1) mod 32)
Else - 动作
触发器 - 运行GobStackPopReg &预设& (检查条件) 这个队列是循环队列,简单点说就是当点存到32的时候,本来应该是没地方存了,但是会重新绕到1另外开始存。循环队列为空的条件是Head = Rear,为满的条件是(Rear+1)%32 = Head。这个结构是比较复杂,假如说你觉得不方便的话做成跟列表一样的结构也可以。总之这个触发就是先用((Squad_PathRear[this] + 1) mod 32) 不等于 Squad_PathHead[this] 判断队列是否为满,满了就不存了。没满,就把点存在Rear所指的位置上,然后Rear+1。假如Head = Rear,就说明此时队列还是空的,那按道理来讲Squad的目标点应该也还没设置,这样就设置一下目标点吧。 另外就是OutPath了: Squad_OutPath
触发器 - 运行GobStackPushReg &预设& (检查条件)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 动作)
Squad_PathRear[this] 不等于 Squad_PathHead[this]
Then - 动作
设置 GobInt2 = (((this - 1) x 32) + Squad_PathHead[this])
设置 GobPointX = (坐标((Squad_PathList[GobInt2] 的X轴坐标),(Squad_PathList[GobInt2] 的Y轴坐标)))
点 - 清除Squad_PathList[GobInt2]
设置 Squad_PathHead[this] = ((Squad_PathHead[this] + 1) mod 32)
Else - 动作
触发器 - 运行GobStackPopReg &预设& (检查条件) OutPath就是把InPath的过程给反过来了,先是判定队列是否为空,然后把Head所指的点给抽出来,再将Head+1.这样的话不停的抽抽抽——Head的值就会慢慢的追上Rear,然后Head = Rear就为空了。而要是不停的增加节点,就会让Rear变大,超过32的话又会从1开始,最后变成Rear爆了Head的菊,这个队列就放满了。差不多就是这种感觉吧。
于是乎这个刷怪系统就讲完了,然而我觉得应该没多少人会喜欢看别人废话个4万字就为了讲一个破刷兵系统,尤其是YDWE都自带刷兵了。所以说地图我就直接传网盘了,不喜欢看这么一大堆的就直接把触发器挪到自己的地图里用吧。
楼主你确定有人能看完?
雾草,0基础
好长,不想看了
为什么楼主总会有那么多的精力投放到这上面呢
太长不看。
有意思吗……话说你都知道自带了还发这么长……
好,但是我没看完
mark,慢慢看
膜拜大神,不过我觉得楼楼可以做一个超简单的刷兵,然后让新手自己去扩张,给点提示就好了~
贴吧热议榜
使用签名档&&
保存至快速回贴

我要回帖

更多关于 魔兽地图编辑器吧 的文章

 

随机推荐