魔兽首页最新地图防守地图对抗地图角色剧情TD塔类图标准战役ORPG地图其它地图
魔兽论坛攻略秘籍补丁工具RPG 录像制图教学制图资源魔兽战队新图试玩通魔作坊

您的位置:魔兽争霸U9网 >> 制图教学

通魔之路(WE主讨论区):[教程] ◆内存释放完全版◆

作者:illlusion    文章来源:U9论坛    点击数:    更新时间:2006-8-30 17:55:31
今天看完了这个受益非浅 拿来给大家分享 写的非常全面彻底 只懂T不懂jass的看前半部分就足够 懂jass的可以看看后半部分(对于运算量超大的程序一定看看最后几段  刚才可解决了我的大问题~~)

这个是原网页有色彩的http://www.infor.org/~n1048/WESe ... cles/MemoryLeak.htm

〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓

記憶體漏失(Memory Leak)


By Danny



一、什麼是記憶體漏失

很多國外的WEer常常把談Memory Leak(記憶體漏失)掛在嘴邊,這是指有些創造出來的物件,已經不會再被用到了,卻沒有被刪掉,因而佔用記憶體空間的情形。
例如:Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

其中(Center of (Playable map area))就是一個點。可以想成,我要電腦在操場中間產生一個武士,但是電腦不懂什麼叫做地圖中間。所以我到操場中間插一個旗子(也就是一個Point),之後我就命令電腦在那個旗子的位置產生一個武士。好了,現在武士產生了,那麼旗子呢?因為我沒有刪掉它,所以它會一直留在記憶體中。一兩個不打緊,但是如果這一類的動作很多,記憶體裡堆了數十萬個沒有用的東西,跑起來效率自然大打折扣。

同樣的情形也發生在其它的物件中。對了,什麼是「物件」?籠統地說,只要是遊戲中一個具體的東東就是物件,除了布林(boolean)、整數(integer)、字串(string)、實數(real)、程式碼(code)不是以外,其它類型的變數皆屬之 。有些物件像單位、物品是可以看得到的;而有些像計時器、點、單位群組,卻是看不見的。有些物件通常並不會大量產生,而且很多都是可重覆利用的,因此並不需要太注意它 們的刪除。
當你執行了一些函數,就會產生物件,例如點或單位群組的函數,只要呼叫一次就創造一個點(單位群組)。

最常見堆積記憶體的動作如:

Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
建立了一個點
Unit Group - Pick every unit in (Units owned by Player 7 (Green) of type Barracks) and do (Unit - Create 1 Footman for Player 7 (Green) at (Position of (Picked unit)) facing Default building facing degrees)
建立了一個單位群組及一個點
Unit Group - Pick every unit in (Last created unit group) and do (Unit - Order (Picked unit) to Attack-Move To (Center of Region 000 <gen>))
建立了一個單位群組及一個點
Special Effect - Create a special effect at (Target point of issued order) using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
建立了一個點和一個特效
其中紅色和粗字的部分就是建立而沒有被刪除的物件。

二、記憶體漏失的解決方法(實用篇)

記憶體漏失不是太複雜的一件事,但是概念並不是很容易理解。而且此問題從小到大都有,如果你真的要解決所有的記憶體漏失,那麼你會寸步難行,一行簡單的觸發都必須被寫得複雜百倍。因此這裡先提供最實用的幾個技巧,基本上能掌握住這個部分,你的地圖已經沒什麼大問題了。

重覆利用既有的物件
假設你要製作一張類似DotA或三國無雙的地圖,像這一類的攻擊觸發應該是免不了的:
  Unit Attack 1
 Events
  Unit - A unit enters HumanBase1 <gen>
 Conditions
 Actions
  Unit - Order (Entering unit) to Attack-Move To (Center of DemonBase1 <gen>)

但是,每當有一個單位進入了HumanBase1,就要產生一個點(Center of DemonBase1 <gen>),是不是太多餘了?反正點都是同樣的位置,何不重覆利用呢?
所以為了環保起見,我們可以改寫成這樣:
  Map Init
 Events
  Map initialization
 Conditions
 Actions
  Set DemonBase[1] = (Center of DemonBase1 <gen>)
  Set DemonBase[2] = (Center of DemonBase2 <gen>)
  Set DemonBase[3] = (Center of DemonBase3 <gen>)
Unit Attack 1
 Events
  Unit - A unit enters HumanBase1 <gen>
 Conditions
 Actions
  Unit - Order (Entering unit) to Attack-Move To DemonBase[1]

也就是預先把可以多次利用的物件用變數記錄下來,然後直接套用以減少新物件的產生。
刪除使用過且不再需要的新建物件

首先介紹刪除的方法,有一些要用到JASS:
trigger (Trigger)--Custom script: call DestroyTrigger(xxx)
location (Point)--Custom script: call RemoveLocation(xxx)
group (Unit Group)--Custom script: call DestroyGroup(xxx) ※注意Clear Group是清除單位群組中的單位資料,而不是把整個單位群組刪除
force (Player Group)--Custom script: call DestroyForce(xxx) ※注意ForceClear是清除 玩者群組中的玩者資料,而不是把整個玩者群組刪除
Unit--死亡的單位於屍體消失之際,系統會自動移除。所以不用特別去管它。像隱藏施法單位這種用後不理的,要刪的話可以用GUI的Unit - Remove、Unit - Kill、Unit - Add Expiration Timer,甚至把生命回復設成負值讓它自動死亡都可以
Item--被用掉的物品,系統會自動移除。所以不用特別去管它。真的要刪的話用GUI的Item - Remove即可
lightning (Lightning)--用GUI的Lightning - Destroy Lightning Effect
effect (Special Effect)--用GUI的Special Effect - Destroy
texttag (Floating Text)--用GUI的Floating Text - Destroy、Floating Text - Change Lifespan皆可。前者是直接刪除;後者是設定它的壽命,時間一到會自動被刪除
image、ubersplat、quest、……--同樣用GUI就能刪掉,廢話不多話了
刪除特效--
創造特效後要移除,只要你沒刪掉,即使它只出來一下就會消失,看起來好像沒了,但是實際上它還是存在,會佔用記憶體的空間。
而建立在單位身上的特效,在單位死亡屍體腐爛後,特效就看不到了,但是和前面一樣,只要你沒用觸發刪掉它,它還是會佔用記憶體。
刪除的方法就是用Special Effect - Destroy (Last created special effect)。
創造出特效後立刻移除它,特效還是會播放至少一次,所以對於只播一次的特效,順手刪掉它吧。
例如:
  Special Effect - Create a special effect attached to the overhead of (Triggering unit) using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
Special Effect - Destroy (Last created special effect)

如果你要讓它持續播放一段時間,可以先利用變數存起來,時間到再刪掉。
刪除觸發--把執行一次就用不到的觸發刪除(關掉(Turn Off)可讓它不再執行,但是仍會佔用空間。刪除比較一勞永逸)。
方法是在動作的最前面加上Custom script: call DestroyTrigger(GetTriggeringTrigger())。例如:
  Melee Initialization
 Events
  Map initialization
 Conditions
 Actions
  Custom script:  call DestroyTrigger(GetTriggeringTrigger())
  Melee Game - Use melee time of day (for all players)
  Player - Set Player 1 (Red) Current gold to 100000000
  Player - Set Player 1 (Red) Current lumber to 100000000

刪除點--
點是最容易產生的垃圾物件,所以特別要注意怎麼刪除臨時建立的點。除了如之前所述,可以先用變數記錄常用的點以外,還有一個簡單的方法可以清除這些垃圾。之前的範例我們也可以改用這個方法:
  Unit Attack 1
 Events
  Unit - A unit enters HumanBase1 <gen>
 Conditions
 Actions
  Set P1 = (Center of DemonBase1 <gen>)
  Unit - Order (Entering unit) to Attack-Move To P1
  Custom script:  call RemoveLocation(udg_P1)

簡單的說,就是先用變數記錄打算要用到的點,對它進行操作,然後刪掉它。
特別注意第三行,由於b社會把所有觸發編輯器裡定義的變數加上字首udg_,所以這裡要填入udg_P1,而不是P1。

另外像這樣的寫法常常有人會疏忽:
  Unit - Move (Triggering unit) instantly to ((Position of (Triggering unit)) offset by 500.00 towards (Facing of (Triggering unit)) degrees)

實際上這一行接連產生了兩個點,而不是一個。
首先Position of (Triggering unit)就像是在單位的位置插一支旗子,回傳之。
後一步的((Position of (Triggering unit)) offset by 500.00 towards (Facing of (Triggering unit)) degrees)就是在那個旗子位移後的位置再插一支旗子,回傳之。
所以想把點刪乾淨就得像這樣寫:
  Set P1 = (Position of (Triggering unit))
Set P2 = (P1 offset by 500.00 towards (Facing of (Triggering unit)) degrees)
Unit - Move (Triggering unit) instantly to P2
Custom script: call RemoveLocation(udg_P1)
Custom script: call RemoveLocation(udg_P2)


使用這個方法,一個地圖裡只需要一、兩個像P1、P2這樣的臨時變數就夠了,不必動用大量的變數及陣列。
刪除單位群組--
對於單位群組的移除,最簡單的方法是用Custom script: set bj_wantDestroyGroup = true。
當Blizzard.j裏的Unit Group相關函數執行時會檢查bj_wantDestroyGroup, 再決定是否移除傳入的Unit Group。
例如:
  Custom script: set bj_wantDestroyGroup = true
Unit Group - Pick every unit in (Units owned by Player 1 (Red)) and do (Unit - Kill (Picked unit))

執行到Pick Every Unit In group...動作時,電腦會檢查bj_wantDestroyGroup這個變數是否為真,如果為真,就會在進行完動作後,把傳入的group(此例中就是(Units owned by Player 1 (Red)))刪除掉,並且自動把變數bj_wantDestroyGroup設為假。

但請注意,使用自訂變數的Group千萬不要亂刪,除非你曉得自己在做什麼。例如: Unit Group - Pick every unit in ToTGroup and do (Actions)
 Loop - Actions
  Unit - Remove (Picked unit) from the game
前面千萬不要加set bj_wantDestroyGroup = true ,否則那個變數會被砍掉,以後再也不能用來儲存單位。

還有Units Of Type使用此用法會有bug,所以也不要對它這樣用。

如果你不能放心地使用這個指令,也可以參照刪除點的作法。不過同樣要記得加上udg_: Set TempGroup = (Units owned by Player 1 (Red))
Unit Group - Pick every unit in TempGroup and do (Unit - Kill (Picked unit))
Custom script:  call DestroyGroup(udg_TempGroup)

不要產生物件
要建立單位於一特定地點,在觸發中是Create Units Facing Angle、Create Units Facing Point,對應的JASS函數則是CreateNUnitsAtLoc、CreateNUnitsAtLocFacingLocBJ。但是在JASS中還有像這樣的函數可用:
native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit
也就是說,你可以給座標,而不用創造點。
例如:Unit - Create 1 Footman for Player 1 (Red) at (Position Of Triggering Unit) facing Default building facing degrees
用JASS可以改寫成:call CreateUnit( Player(0), 'hfoo', GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit), bj_UNIT_FACING )
如果你要寫一整段的JASS,可以考慮用座標來傳送,就可以避免創造不必要的點。

[ 本帖最后由 illlusion 于 2006-3-17 00:40 编辑 ]
责任编辑:瞳瞳
进入论坛参与针对本文章的讨论
文中部分附件请进入论坛下载
本文章地址:
  • 上一篇:通魔之路(WE主讨论区):真·dota无敌斩演示(Trigger)
  • 下一篇:
  • 相关文章

    进入论坛参与针对本文章的讨论用户评论

    地图 攻略
    热门搜索: 仙之侠道 真三国无双 Dota Allstar

    地图专区导航

    热门地图攻略

    热门地图周排行

    最新推荐地图

    地图下载总排行

    关于我们  -  联系我们  -  广告优势  -  广告服务
    建议意见:玩家点击留言  商务合作:客户点击留言
    西安优久数码科技有限公司 版权所有 陕ICP证08000654号