Trong tutorial này, tôi (Andrewgosu) sẽ giới thiệu cơ bản về sử dụng struct. Làm thế nào để tạo, xóa, "gắn" (attach = gắn) và các thao tác với struct. Để tiếp tục, bạn cần: - World Editor - Jass NewGen Pack - Hiểu biết ở mức trung bình về Jass Các bước mà tôi định dạy: - Struct là gì và làm thế nào để khai báo một struct - Thêm các "component" ( "thành phần", nghe ko hay lắm, hay dịch là "phần tử" đi) cho một struct - Tạo một struct trong một hàm và truy nhập các phần tử của một struct - "gắn" struct vào một "handle" dùng các hệ thống "gắn" để nhận lại struct đã "gắn" - Xóa một struct - Kết thúc Bước 1 - Struct là gì và làm thế nào để khai báo một struct - struct là gì ? To put it simple, structs are parallel globals arrays with a nice indexing system. No game cache involved, whatsoever. Because structs are globals arrays, they have an instance limit, 8191, if to be exact (Fancy trivia, god I love it). But don't be frightened, as you will normally not meet this limit. Khai báo struct thì rất đơn giản: đầu tiên, bạn cần gõ từ khóa "struct", sau đó gõ tên struct và cuối cùng đóng struct với từ khóa "endstruct" Ví dụ: Mã: struct structname endstruct Thế là ta đã có struct tên là structname Bước 2 - Thêm các "phần tử" cho một struct Một struct mà trống thì chả sử dụng đc gì. Sau khi khai báo struct, bạn phải thêm các phần tử cho nó - là những thứ mà bạn muốn "lưu" Và việc này còn dễ hơn khai báo struct Mã: struct structname unit whichPanda real facing real x real y integer level endstruct Các phần tử của struct có thể có giá trị khởi tạo: Mã: struct structname real fullAngle = 90. integer maxNumber = 69 endstruct Về "mảng" trong một struct, ko có vấn đề gì, nhg thật ra có một Khi khai báo "mảng" trong một struct, bạn phải đặt "array index limit" (giới hạn chỉ số của mảng) Mã: struct structname integer array level[100] endstruct Điều này có nghĩa là bạn chỉ có thể sử dụng level với chỉ số mảng từ 0 -> 99, nếu bạn dùng với 100 hoặc hơn thì khi kiểm tra code, sẽ có lỗi đc báo. Bước 3 - Tạo một struct trong một hàm và truy nhập các phần tử của một struct Để tạo một struct, sẽ có cũ pháp vJass. Nhưng ko nên thấy lo và nhầm lẫn Mã: function functionname takes nothing returns nothing local structname data = stuctname.create() endfunction Tôi chắc là "local" quá quen thuộc với bạn rồi, nhg sao "structname" lại là type của local variable này vì ko có type "structname" mà chỉ có unit, integer, real,.. Đúng, nhg bây giờ thì có rồi. Tên của struct mà bạn khai báo, bạn phải dùng tên nó như là type của variable khi tạo nó trong một hàm. Ví dụ: Mã: function functionname takes nothing returns nothing local pandamonium data = pandamonium.create() local thehelper info = thehelper.create() local apple worm = apple.create() endfunction "pandamonium", "thehelper" và "apple" là tên struct, và "data", "info", "worm" chỉ là tên của struct đc tạo ra. Sau khi tạo struct, bạn có quyền truy nhập vào các phần tử của nó. Và hãy chú ý đến cũ pháp: Mã: function functionname takes nothing returns nothing local structname data = stuctname.create() local unit caster = GetTriggerUnit() set data.whichPanda = caster set data.facing = GetUnitFacing(caster) set data.x = GetUnitX(caster) set data.y = GetUnitY(caster) set data.level = GetHeroLevel(caster) endfunction Bạn dùng struct có tên "data" (tên này do bạn đặt, là gì cũng đc) để truy nhập các phần tử của struct có tên là "structname" Thêm vài ví dụ: Mã: function functionname takes nothing returns nothing local haxxor gamer = haxxor.create() set gamer.realX = 270. set gamer.RealY = 90. endfunction function functionname takes nothing returns nothing local sheep grass = sheep.create() set grass.killer = GetKillingUnit() endfunction Bước 4 - "gắn" struct vào một "handle" dùng các hệ thống "gắn" để nhận lại struct đã "gắn" Đã có nhiều "hệ thống gắn/liên kết". Tôi sẽ sử dụng các hệ thống thông dụng Tôi sẽ "gắn" struct vào một timer tên là "callback", timer này có "function callback" là callbackfunc Kattana's Handle Variables Mã: function callbackfunc takes nothing returns nothing local structname data = GetHandleInt(callback, "whichStruct") endfunction function functionname takes nothing returns nothing local structname data = structname.create() call SetHandleInt(callback, "whichStruct", data) endfunction Vexorian's CSData Mã: function callbackfunc takes nothing returns nothing local structname data = GetCSData(callback) endfunction function functionname takes nothing returns nothing local structname data = structname.create() call SetCSData(callback, data) endfunction Cohadar's ABC Mã: function callbackfunc takes nothing returns nothing local structname data = GetTimerStructA(callback) endfunction function functionname takes nothing returns nothing local structname data = structname.create() call SetTimerStructA(callback, data) endfunction Cũng ko quá khó. Bước 5 - Xóa một struct Struct phải bị xóa, (location phải bị remove, group phải bị destroy,... ) Ko xóa struct, đơn giản là leak Cú pháp để xóa một struct: Mã: function callbackfunc takes nothing returns nothing call data.destroy() endfunction Vài ví dụ nữa: Mã: function callbackfunc takes nothing returns nothing call data.destroy() call info.destroy() call worn.destroy() endfunction Bước 6 - Kết thúc Sau khi đã biết cơ bản về struct, bạn đã biết làm thế nào để tạo, gắn, nhận lại và xóa struct Ví dụ cuối: Mã: // Khai báo struct struct sheepfall // tạo một danh sách các phần tử unit whichSheep integer SheepLevel real facing endstruct function callbackfunc takes nothing returns nothing // nhận lại struct local sheepfall data = GetCSData(GetExpiredTimer()) // Destroy the struct call data.destroy() endfunction function funcname takes nothing returns nothing local unit sheep = GetTriggerUnit() local timer t = CreateTimer() // tạostruct local sheepfall data = sheepfall.create() // đặt giá trị cho các phần tử set data.whichSheep = sheep set data.SheepLevel = GetHeroLevel(sheep) set data.facing = GetUnitFacing(sheep) // gắn struct call SetCSData(t, data) call TimerStart(t, 10., false, function callbackfunc) endfunction Credit: Thanks to Andrewgosu for making this tutorial, this is his original post: http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=79426 ------------------------------ Đến đây, Tom sẽ dùng struct tạo một hàm Knockback (Tom chọn Knockback vì nó dễ hiểu :) ) Ta cần(nên dùng) CSData và CSSafety của Vexorian. Tom có struct sau: Mã: struct knockbackdata unit whichUnit //unit bị knockback real angle //góc knock integer tick //tik tak, tik tak, số lần "move" unit real distance //khoảng cách mỗi lần "move", tức là tống khoảng cách knock là (distance * tick) string sfx //effect knockback endstruct Và hàm để "gọi" knockback, hàm này sẽ lấy unit bị knockback, khoảng cách knockback (tổng khoảng cách), góc knock, effect và duration để xác định số tick và xác định khoảng cách mỗi lần "move" Mã: function KnockBack takes unit whichUnit, real distance, real angle, real duration, string sfx returns nothing endfunction Có struct rồi, tạo struct, nhập giá trị cho các phần tử thôi: Mã: function KnockBack takes unit whichUnit, real distance, real angle, real duration, string sfx returns nothing local knockbackdata data = knockbackdata.create() set data.whichUnit = whichUnit set data.angle = angle set data.tick = R2I( duration / 0.04 ) //ta sẽ dùng 0.04s timer, vậy tick = duration / 0.04 set data.distance = distance / data.tick //nhớ là distance trong struct sẽ là khoảng cách mỗi lần "move", vậy nó sẽ = tống khoảng cách / số tick set data.sfx = sfx endfunction Bây giờ ta tạo callback function cho một timer, tạo timer rồi dùng CSData "gắn" struct vừa tạo vào timer này Mã: function KnockBackE takes nothing returns nothing endfunction function KnockBack takes unit whichUnit, real distance, real angle, real duration, string sfx returns nothing local knockbackdata data = knockbackdata.create() local timer ti = NewTimer() // sử dụng CSSafety, dùng NewTimer thay cho CreateTimer set data.whichUnit = whichUnit set data.angle = angle set data.tick = R2I( duration / 0.04 ) //ta sẽ dùng 0.04s timer, vậy tick = duration / 0.04 set data.distance = distance / data.tick //nhớ là distance trong struct sẽ là khoảng cách mỗi lần "move", vậy nó sẽ = tống khoảng cách / số tick set data.sfx = sfx call SetCSData( ti , data ) //struct sẽ đc coi như một integer call TimerStart( ti, 0.04, true, function KnockBackE ) set ti = null //local handle -> phải null endfunction Sang "callback function" tên là KnockBackE, ta sẽ nhận lại struct đã "gắn", tất nhiên là dùng CSData Mã: function KnockBackE takes nothing returns nothing local timer ti = GetExpiredTimer() local knockbackdata data = GetCSData( ti ) endfunction Vậy là từ struct, ta sẽ có unit, distance, angle, sfx, tick tiến hành knockback thôi: function KnockBackE takes nothing returns nothing local timer ti = GetExpiredTimer() local knockbackdata data = GetCSData( ti ) local location loc = GetUnitLoc( data.whichUnit ) //Position of whichUnit local location loc2 = PolarProjectionBJ( loc, data.distance, data.angle ) //Point with Polar Offset call AddSpecialEffectLocBJ( loc2, data.sfx ) //Create Special Effect call DestroyEffectBJ( GetLastCreatedEffectBJ() ) // Destroy Special Effect call SetUnitPositionLoc( data.whichUnit, loc2 ) //move unit call RemoveLocation( loc ) call RemoveLocation( loc2 ) set loc = null //dùng xong các local handle thì phải null, ko thì leak đấy set loc2 = null set data.tick = data.tick - 1 //giảm tick if data.tick <= 0 then // dùng <= 0 cho an toàn call data.destroy() call ReleaseTimer( ti ) // sử dụng CSSafety, dùng ReleaseTimer thay cho DestroyTimer endif set ti = null endfunction Rồi, cuối cùng ta sẽ có: Mã: struct knockbackdata unit whichUnit real angle integer tick real distance string sfx endstruct function KnockBackE takes nothing returns nothing local timer ti = GetExpiredTimer() local knockbackdata data = GetCSData( ti ) local location loc = GetUnitLoc( data.whichUnit ) local location loc2 = PolarProjectionBJ( loc, data.distance, data.angle ) call AddSpecialEffectLocBJ( loc2, data.sfx ) call DestroyEffectBJ( GetLastCreatedEffectBJ() ) call SetUnitPositionLoc( data.whichUnit, loc2 ) call RemoveLocation( loc ) call RemoveLocation( loc2 ) set loc = null set loc2 = null set data.tick = data.tick - 1 if data.tick <= 0 then call data.destroy() call ReleaseTimer( ti ) endif set ti = null endfunction function KnockBack takes unit whichUnit, real distance, real angle, real duration, string sfx returns nothing local knockbackdata data = knockbackdata.create() local timer ti = NewTimer() set data.whichUnit = whichUnit set data.angle = angle set data.tick = R2I( duration / 0.04 ) set data.distance = distance / data.tick set data.sfx = sfx call SetCSData( ti , data ) call TimerStart( ti, 0.04, true, function KnockBackE ) set ti = null endfunction Sử dụng hàm Knockback trên, đơn giản, gọi function KnockBack thôi Tạo lại cái skill Storm Hammer trong map demo Slide Mã: function StormHammerAct takes nothing returns nothing local unit c = GetAttacker() local unit u = GetTriggerUnit() local integer lvl = GetUnitAbilityLevel( c , 'A000' ) local location loc local location loc2 if lvl == 0 or ( lvl > 0 and GetRandomInt(1,100) > 17 ) then //chưa có ability hoặc có nhg chance random > 17 set c = null set u = null return endif call SetUnitAnimation(c,"attack slam") call UnitDamageTarget( c, u, 25. * lvl, true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, null ) set loc = GetUnitLoc(c) set loc2 = GetUnitLoc(u) //gọi hàm Knockback call KnockBack( u, 90. + 30*lvl, AngleBetweenPoints(loc,loc2), 0.8, "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" ) call RemoveLocation( loc ) call RemoveLocation( loc2 ) set loc = null set loc2 = null set c = null set u = null endfunction //=========================================================================== function InitTrig_StormHammer takes nothing returns nothing set gg_trg_StormHammer = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_StormHammer, EVENT_PLAYER_UNIT_ATTACKED ) call TriggerAddAction( gg_trg_StormHammer, function StormHammerAct ) endfunction --- Một ví dụ đơn giản, dễ hiểu, hy vọng đến đây các bạn (những ai đọc Tutorial này) đã hiểu đôi chút về struct, biết cách sử dụng. Happy Mapping P/S: có map demo Tom gửi kèm ở dưới
cách dùng ??? như WE bình thường chả có gì khác cả Cái Custom Script là 1 lệnh bằng jass đưa vào trong GUI, vì trong GUI ko có.
anh tom: haha khá lắm......lâu lâu trở lại thấy box mình khác hẳn...(project đã bị dẹp)...........thanks
Anh Tom ơi,có cách nào xây dựng struct = gui ko? Em định làm skill rồng đuổi thế này: -Lv 1->5: 1 rồng,6->10: 2 rồng,11->15: 3 rồng,16->20: 4 rồng. -Khi caster chơi skill vào 1 target<enemy> nào đó,sẽ có các con rồng<dummy unit> được tạo song song nhau trước mặt caster----> | | | |.Mỗi con rồng sẽ có tốc độ di chuyển 400/s.Và được gắn 1 cái custom value là 10.Add expire timer cho nó là 2,5s.Và gắn cho nó 1 cái biến loại unit là target<mục tiêu><dùng struct???> -Trigger cứ 0,1s,nếu custom value của dummy unit rồng >1 thì move các con rồng này về hướng trước mặt<facing>1 khoảng cách là 40 đồng thời giảm custom value của nó đi 1.Rồng còn 1,5s thì biến mất. -Lúc này thì cứ 0,1s lại move nó 1 khoảng cách là 40 về hướng giữa nó và target.<có nghĩa là các con rồng bay song song với nhau 1 khoảng cách 400 thì đổi hướng vè mục tiêu của spell cast ở trên> -Có 1 trigger nữa deal dame khi có unit come within 128 of unit type rồng đó. Anh chỉ em cách làm struct gắn mục tiêu bay cho rồng sau 1s nó được tạo ra đi? -Khi cú -Khi custom value