作者:[通魔作坊· earst ] 文章来源:本站原创 点击数:26607 更新时间:2009-9-4 =========================== 写在前面的话 ============================ 【我们的目标是:没有蛀牙……】 以下的心得体会是earst在学习、制作地图过程中收集整理的,当然不可排除些许理解或阐述的失误或不严密,希望大家能在浏览之余提出意见或建议……我尽量采用最通俗的语言来阐述,若造成个别比较反胃的现象请浏览者尽量克制情绪~但个人估计如果你把这篇心得当小说或笑话来看应该会掌握到更多的东西,尤其对新人来说,这可比Danny高屋建瓴且强逻辑性的概念论述更合胃口也更易理解。 ----------------------------------------------------------------------------------------------------------------------------------------------- 【地图读取部分】 ================================================================ (1)[在地图初始化(Map Initialization)减少地图中预设置物体] 这里所谓的预设置物体包括单位、物品、可破坏物、地形装饰物、区域、摄影机等,这些物体都是在地图初始化时预读的。 建议将这些非必须预设置的相关物体留待触发器中创建。有兴趣大家不妨做个实验:在地图编辑器中打开自己的地图,汇入档案进程中读取地形装饰物数量过千的请举手?齐刷刷的一大片!数量三五千的也大有人在!!而这些一般都是在地图中预先放置的。之前看过这样一个地图,128*128全范围1/3部分是密密麻麻的花海,之间再点缀了为数不少的藤蔓、蘑菇、碎石、杂草等,而且粗略估计个头都是原始大小200%以上……“春天花会开”?效果是有了,而一想到loading进程我的头皮就发寒…… --------------------------------------------------------------------------------------------------------------------------------------- (2)[减少地图中预设置物体的初步设置] 这里所谓的地图中预设置物体的初步设置是指譬如:单位生命,魔法,等级,三围属性,已备技能,单位死亡掉落物品,区域气候,单位(可破坏物或地形装饰物)的大小比例等,这些也都是在地图初始化时预读的。值得注意的是:别感觉物体个头越大就越“凶悍”,一些朋友喜欢把BOSS设置N倍于原始大小,或者把一些巨大化的自定义地形装饰物(譬如模型为“天神下凡”的自定义地形装饰物)放在地图里,这些东西不仅增加地图读取的LAG,而且也影响到游戏进程的流畅性。 另:这些初步设置中“单位死亡掉落物品”的预设置对地图读取的影响最大。 --------------------------------------------------------------------------------------------------------------------------------------- (3)[合理安排在初始化时响应的触发] 初始化触发也是在地图读取时执行的,越多的初始化触发就将使地图读取时间越长,当然也不能偏激地把全部的初始化触发移至游戏进程中执行,建议把必须的触发放在初始化部分,其余的放置在进入游戏后按若干时差阶段顺次执行,具体操作依个人喜好及地图设置状况而定。 --------------------------------------------------------------------------------------------------------------------------------------- (4)[其他补充] 外部模型、图片、声音等的导入并不会导致地图读取时明显的LAG,所以不要有“地图容量越大就读得越慢”的想法。物体编辑器(Object Editor)中自定义物体越多,相对影响更大是地图编辑器的运行速度而非游戏过程,所以不要有“地图制作中自定义物体越多游戏就越容易卡”的想法,当然不是完全没有影响,建议能修改默认则修改,好的习惯是尽量别动辄就创建新物体。 ================================================================ 【游戏进程部分】 ================================================================ (1)[预先声明] 以下所有关于优化游戏进程流畅性的阐述都是基于常规……或者说一般设置中所应该注意的,而其他一些吹毛求疵的鸡肋手段可以参阅Danny《记忆体漏失(Memory Leak)》(见 WE技术与研究 部分)更为精辟的分析叙述。 另:极个别洁癖Weer还可到U9“通魔之路”地图编辑区和zyl910及red_wolf一干人等深入挖掘研讨并堆楼摆龙门阵以发展站点建设事业,汗~ ---------------------------------------------------------------------------------------------------------------------------------------- (2)[界面可视区域中物体的密度] 我们先来打个这样的比方(情境有点极端化的BT,大家忍耐点~): 情境一:防守地图中敌对单位进攻倒计时30秒读数中……红色玩家的英雄训兽师[小明]停留在主城附近,时不时转转身……周围四个具有多重箭矢技能的防御塔伫立在主城四围…… 分析:这时候移动你的鼠标,左拖右拽,是不是很顺畅?再看训兽师[小明]的转身或移动,是不是很流畅?居然说不是?你的机器是赛扬1G/128M的么……?? 情境二:敌对单位开始进攻并已大部分进入主动攻击范围,其余也都移至主城附近了……本次进攻的是攻击间隔为0.50秒,箭矢投射图象为“腐臭蜂群(箭矢)”的一群巫妖,分四路进攻,共计120个单位……而近战的训兽师[小明]立马就跑到就近的一个巫妖附近狂砍起来……此时四个防御塔也发挥了应有的作用,每个防御塔都可在1250有效射程内针对5个敌对单位进行同时攻击且箭矢投射图象为“红蜉蝣(箭矢)”……在以上描述的进程中触发器里的一条T也适时发挥了作用,事件:单位被攻击。环境:被攻击单位的所有者为中立敌对and被攻击单位的单位类型为巫妖。动作:命令被攻击单位激活霜冻护甲。与此同时,训兽师[小明]释放了一个野兽单位数量极大且射箭技巧改为“烈焰风暴(效果)”持续15秒,绿色的“腐臭蜂群(箭矢)”,红色的“红蜉蝣(箭矢)”,蓝白色的“霜冻护甲(效果)”,橙黄色的“烈焰风暴(效果)”交相辉映,煞是好看…… 分析:这时候移动你的鼠标,怎么样?仔细看看单位们的动作,你能保证每秒能有几帧?最后看看箭矢轨迹,曲线如丝般柔顺么?现在,很高兴地告诉你,LAG了…… ---------------------------------------------------------------------------------------------------------------------------------------- 所谓界面可视区域中物体的密度包含了很多方面,需要注意的有以下几点: A. 尽量避免让过多的单位、特效、地形装饰物、可破坏物等同时出现在游戏屏幕上。 B. 尽量减少投射性武器同时出现在游戏屏幕上,就算出现此类情况,也尽量确保投射性武器的箭矢投射图象少些光影或连带特效。有兴趣的朋友可以尝试下改个远程英雄的箭矢投射图象为丛林守护者幽灵的单位模型,再添加多重箭技能,把攻击数量最大限制设置为0(这样可是有效射程内有多少就打多少),最后把攻击间隔也设置为0,然后摆一圈血厚点的敌对单位在这个远程英雄周围,Ctrl+F9测试个~保证让你汗如雨下…… C. 尽量避免一些非T非J的默认技能修改后的射箭技巧过于奢华。譬如例子中那个改过的[惊吓]技能,再或者把射箭技巧改为“烈焰风暴(效果)”且可对32个单位同时攻击,这些做法并不代表你的技能做得绚,而是代表你的技能做得烂。可以这样看,这些技能效果都是持续叠加出现于屏幕上或零时差创建于屏幕上的,或许光是技能演示还看不出明显LAG,但请大家一定要注意:演示是演示,游戏是游戏……EARST不妨在此说明个~我在地图编辑区也发了不少关于华丽技能的演示了,可能大家认为我就好这一类的,其实不然,有心的朋友可以去看看我的全部演示,没有一个是写上“如果要把这技能用于你的地图,那么就怎样怎样……”的,最多就是建议大家若要用一定要注意控制内存泄漏,为什么?其实我的大部分技能演示还是仅限欣赏的,触发都写得比较潦草,后期制作的可能还会考虑到排除LAG,前期制作的几乎都未释放内存空间。因为真要把技能做到好看又不卡,那要考虑的方面可就多了,以后在触发技能制作中我会再详细说明。包括最近我发的一些华丽技能,演示中我写的是一种触发,而我在自己地图中就算要达到类似效果,重新写触发的又是另外一种,但写的过程可要比我发的演示里的触发罗嗦复杂百倍。 D. 尽量避免同时产生多个单位,就算需要出现此类情况,也应采用等待时间(Wait)来分批处理。 --------------------------------------------------------------------------------------------------------------------------------------- (3)[重复使用的既有点并尽量合理彻底地把无效点从地图里删掉] 我们先来看看以下这个触发模拟: 情境一:防守地图中,循环逝去时间为2.00秒,命令地图中所有中立敌对单位攻击-移动到英雄出生地区域HeroUpArea的中心。 分析:是不是要每间隔2秒就让电脑判断一下什么是英雄出生地区域HeroUpArea的中心呢?这样的话就每间隔2秒就多创建了一个点来占用内存空间了。要不就循环逝去时间为2.00秒,设置HeroUpArea_Point = 英雄出生地区域HeroUpArea的中心,再命令地图中所有中立敌对单位攻击-移动到HeroUpArea_Point,最后RemoveLocation (udg_HeroUpArea_Point),这样就可以了吧?累不累?这里就应该采用既有点的策略,譬如我在地图初始化时就做如下设置:HeroUpArea_Point = 英雄出生地区域HeroUpArea的中心,只要每次命令中立敌对单位直接攻击-移动到HeroUpArea_Point就可以了。不是说应该删除无效点么?关键就在这里,既有点的策略就是创建某个不需释放的点,在后期触发中可重复调用,当然当这个点HeroUpArea_Point在触发失去有效被判断的时候还是得把它删除的。也可以这样来简单定义:地图中一些需要被重复调用的点,我们应该采取创建既有点的方法。换言之,你会每天买个新茶杯喝茶,完了就砸掉隔天再买吗?更不必说每天买个新茶杯喝茶,完了存起来隔天再买一个喝茶再存起来,类推……你家又不是开茶杯店的…… --------------------------------------------------------------------------------------------------------------------------------------- 情境二:一个单位释放某名为[黑奴妈妈生黑奴]的技能(恶汗~),在技能单位的位置位移500方向为技能单位的面向角度的位置创建(1-5之间随机数字)个黑暗之奴。 分析: 首先要摈除理解误区A:“创建既有点Hero_Point = 技能单位的位置。”没那么便宜的事!这里就有个不确定因素的问题,谁知道这个单位在释放技能时会在哪里!?这时只能在技能释放时实时设置技能单位的所在点,之后再删除。由此可知,对既有点的策略应该可以添加这样一个界定:恒定不变且需要重复调用的点才可采用此策略。 其次要摈除理解误区B:“这里只创建了一个点,其目的是创建新的黑暗之奴单位。”思路是对的,但还需要细化一下条理性,我们可以这样来理解,该技能的完成目的是创建(1-5之间随机数字)个黑暗之奴在一个受不确定因素影响的点上,而这个点是由释放技能的单位位置这个点来指向的,所以我们应该这样来设置,事件:单位释放了一个技能。环境:释放的技能是[黑奴妈妈生黑奴]。动作:第一个点变量赋值 Hero_Point1 = 技能单位的位置;第二个点变量赋值 Hero_Point2 = Hero_Point1位移500方向为技能单位的面向角度的位置;在Hero_Point2创建(1-5之间随机数字)个黑暗之奴;RemoveLocation (udg_ Hero_Point1);RemoveLocation (udg_ Hero_Point2),完毕。简言之可以这样认为,Hero_Point1是不确定因素下应设置的点,而Hero_Point2是以Hero_Point1为辅助而创建的点,该触发应创建两个临时的点变量,最终也应删除这两个“临时工”。 --------------------------------------------------------------------------------------------------------------------------------------- 情境三:针对情境二的状况为求彻底删除先Hero_Point1 = Null再RemoveLocation (udg_ Hero_Point1)。 分析:首先要了解下全局变量和局部变量的概念。原始粗略地讲,在地图编辑器里点击[创建变量],这里定义的都是全局变量,全局变量是可由所有函数任意调用的;而在一个固定函数前设置的变量则是局部变量,这个局部变量只有定义其的函数才可调用。而之前情境二中的Hero_Point1,我们可以这样来理解:当单位释放[黑奴妈妈生黑奴]技能时,Hero_Point1 = 技能单位的位置;当技能完毕RemoveLocation后该单位又再接着释放另一个[黑奴爸爸打黑奴]技能时,我们仍旧可以把Hero_Point1设置为其他譬如“目标单位的位置”等,也就是说,全局变量经同类型指向可由任意函数对其进行不同定义的赋值。这里要特别注意的一点是:如果执行这样的操作,Hero_Point1 = 技能单位的位置,接着再Hero_Point1 = 目标单位的位置,那么永远是后者说的算,因为最后指针对应的是目标单位的位置,所以我们应该掌握一个原则就是指针永远的唯一对应,别指望它能帮你分别在技能单位和目标单位的位置都插上旗。由此可知,先Hero_Point1 = Null再RemoveLocation (udg_ Hero_Point1)无意义,严格讲Hero_Point1 = Null这步操作是不必要的。 而若是一个局部变量的话,变量清空(nullifying)就是必须的了,据说是Blizzard程序员偷懒的原因留下的局部变量的BUG。 --------------------------------------------------------------------------------------------------------------------------------------- 这里借用Danny的例子: [采用局部变量] function MyFunc takes nothing returns nothing local trigger T = CreateTrigger() call DestroyTrigger(T) set T = null endfunction --------------------------------------------------------------------------------------------------------------------------------------- [采用全局变量] function MyFunc takes nothing returns nothing set udg_T = CreateTrigger() call DestroyTrigger(udg_T) endfunction 结果是一样的,两种写法都没有内存问题,只是对局部变量需要多个变量清空动作而已。委琐地建议个,别那么麻烦,还是老老实实地在GUI中用全局变量罢……有异议的同志们就当我没说……汗~ --------------------------------------------------------------------------------------------------------------------------------------- (4)[应该如何对付特效或闪电效果] A. 首先应该明确这样的概念:对特效及闪电效果而言,使用后不删除将会很惨。 B. 创建的特效即使只播放一次而未被删除,也一定会占内存空间,要有这样的唯物主义认识:看不见的不代表不存在,只要求播放一遍的特效,创建后就立马直接删掉吧,因为它至少会在完成一次播放后才被释放;还有就是对单位创建特效后,即使该单位死亡,特效也将持续保留于游戏进程中;总的来说就是无需持续时间的就直接删除以释放内存空间;需要持续时间的就定义个特效或闪电效果的变量,等待若干秒后再把这个特效变量剔除。 C. 对有可能出现多个特效(闪电效果)需要持续时间时,建议还是针对相应的触发设置特定的特效(闪电效果)变量,否则万一冲突了留下一两个死亡之指效果什么的挂在地图上就“糗”了……这种情况大家还是得回顾下前面介绍的指针的唯一性问题。 --------------------------------------------------------------------------------------------------------------------------------------- (5)[其他] A. 首先应该就是单位组的问题了。其实本想把这项单列来整理的,但写了好久实在是累坏了,偷懒个~移除单位组的设置set bj_wantDestroyGroup = true大家都知道该在Custom script里加上这一句,但此项操作是如何执行的?当Blizzard.j里的Unit Group相关函数执行时会检查bj_wantDestroyGroup,这个Blizzard.j里定义的布尔型变量存在的目的就是在选取单位组中所有单位做动作前提供被检查的职责,当该变量为ture,则完成动作后将这个单位组删除掉并再set bj_wantDestroyGroup = flase,所以这句自定义脚本应该放在单位组创建之前。什么?为什么要bj_个?!怎么不是经常看到的udg_?!这里额外说明下,udg_字首的是地图制作者自定义的变量,而bj_字首的是魔兽内部的变量,至于为什么要加上这个字首,只是为了防止混淆冲突,起到区别的作用。还有就是关于选取某单位类型(Units Of Type)的单位组不能依照此法删除单位组来进行内存释放,据说存在BUG,尚未实验,可留待达人们阐述解释。对于这些不确定的状况,应该采用如下办法:定义一个单位组变量TempGroup并在动作执行前赋值,譬如说TempGroup = 玩家(中立敌对)所拥有的单位;选取所有单位在单位组(TempGroup)做动作;最后在自定义脚本中call DestroyGroup (udg_TempGroup),把这个单位组删除,效果也是一样的。 B. 循环逝去时间XX秒做XX动作,尽量少点诸如此类的设置,即便非得有,也请在允许的情况下尽量延长这个循环逝去时间的间隔且加上相应触发事件来控制该触发器的执行次数。 C. 对仅使用一次的触发在动作末尾采用在自定义脚本中call DestroyTrigger(GetTriggeringTrigger())将其删除,地图初始化就是块最好的下刀肉,不要混淆“关闭触发器”和“删除触发器”两个概念,前者纵使不再使用但依旧占用内存空间而未被释放。 --------------------------------------------------------------------------------------------------------------------------------------- 整理了好长时间呢……键盘都起茧了。 写在后面的话: 【其实我们的真正目标是:让我们的地图达到基本环保的要求……】 【游久网(U9)责任编辑:初雪】 |
|