[Tutorial] Basics of Structs

Thảo luận trong 'World Editor' bắt đầu bởi Tom_Kazansky, 5/10/08.

  1. Tom_Kazansky

    Tom_Kazansky

    Tham gia ngày:
    28/12/06
    Bài viết:
    3,454
    Nơi ở:
    Hà Nội
    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ác file đính kèm:

  2. Dark_DragonKing

    Dark_DragonKing Mr & Ms Pac-Man

    Tham gia ngày:
    23/7/08
    Bài viết:
    217
    hay quá ! Đúng cái em cần đây rồi ! Love you :x
    Anh làm tiếp cái nữa về handle đi :;)
    Thx so much :x
     
  3. Exp1111

    Exp1111 Donkey Kong

    Tham gia ngày:
    19/9/08
    Bài viết:
    486
    Nơi ở:
    HN123
    À này, ông chỉ cho tui cái Map Cútom Script để làm ji` đi.
     
  4. Exp1111

    Exp1111 Donkey Kong

    Tham gia ngày:
    19/9/08
    Bài viết:
    486
    Nơi ở:
    HN123
    Ai có thể chỉ tôi cách dùng cái NewGen WE đi, khó hỉu we'
     
  5. Dark_DragonKing

    Dark_DragonKing Mr & Ms Pac-Man

    Tham gia ngày:
    23/7/08
    Bài viết:
    217
    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ó.
     
  6. god_of_the_noob

    god_of_the_noob Mr & Ms Pac-Man

    Tham gia ngày:
    6/3/08
    Bài viết:
    188
    Nơi ở:
    Bốn bể là nhà
    anh tom: haha khá lắm:D:D:D:D:D......lâu lâu trở lại thấy box mình khác hẳn...(project đã bị dẹp)...........thanks
     
  7. lucifekit

    lucifekit The Warrior of Light

    Tham gia ngày:
    25/2/06
    Bài viết:
    2,344
    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
     

Chia sẻ trang này