System Apex

13lade619

is now a game developer :)
Reaction score
399
A P E X
Advanced Projectile EXperiments

Arced Projectiles + Collision Missiles

+ VERTICAL COLLISION
- the projectile can 'leap' above units, can hit flying while ignoring the units below
and will hit ground units when they are close enough.

+ HORIZONTAL ARC
- you can make projectiles arc horizontally, with different settings.
- just like the famous Wild Axes spell.

v5
Code:
v2
Uses T32 (kingkingyyk3)
Some other code optimizations

v3
Reduced arguments on the create method.
Created separate methods for the optional Horizontal arc and collision.

v4
Added periodic method
Uses GroupUtils

v5
Removed GroupUtils, better group utilization.
new onStart method
new create, you can now set the dummy used.

System Code:
Apex (Latin for top, peak, summit)

JASS:
library APEX requires T32

//=======================================================================================
//                      __     ___
//         _  ____ ____\  \   /  /
//        /_\ | - \  __\\  \/  /      Advanced
//       / _ \| -,/  _|_ >    <        Projectile        by 13lade619
//      / / \_\_| |____//  /\  \        EXperiments
//     /_/             /_ /  \__\   v5
//
//  DISCLAIMER : The values used in this system are NOT based on the 
//               Obect Editor measures. You as the user WILL need to 
//               EXPERIMENT to get what shape of trajectory you really
//               want to create.
//  
//  Credits : Jesus4Lyf, for the T32 System.
//          : kingkingyyk3 for helping with the T32 implementation
//          : Romek, for UAC's optional methods algorithm, and UAC as a basis for coding.
//          : emjlr3, for his Wild Axes spell algorithm (provides horizontal arc)
//          : Vexorian, for his Caster System arc algorithm (provides vertical arc)
//
//  PROS    :   Supports VERTICAL COLLISION.
//          :   Supports HORIZONTAL ARC.
//          :   Can be used as collision missiles and/or AoE missiles.
//
//  CONS    :   Only POINT TO POINT targeting.
//          :   ..too much maths for movement., even i cant understand.
//
//  
//  SYSTEM METHODS / FUNCTIONS <Summary>
//
//          method onStart          takes nothing returns nothing defaults nothing
//          method onPeriod          takes nothing returns nothing defaults nothing
//          method onCollision    takes unit u returns nothing defaults nothing
//          method cfilter        takes unit u returns boolean defaults false
//          method onEnd          takes nothing returns nothing defaults nothing
//
//              yourvar.horizontal( real H_LAUNCH, real X_ARC )
//              yourvar.settick( real t )
//              yourvar.size( real COLLISION )
//
//
//
//  SYNTAXES <Explained> :   
//              < Struct >
//              struct yourstruct extends APEX
//              
//              < Create >
//              local yourstruct yourvar = yourstruct.create(CASTER, START_X, START_Y, START_Z, 
//                                                          END_X, END_Y, END_Z, Z_ARC,
//                                                          SPEED, MODEL, DUMMY)
//
//                      DUMMY               >   code for dummy unit to be used.
//                      Z_ARC real 0-3      >   vertical arc, experiment with values 0-2 and find a decent shape..
//                      SPEED real (.01-.1) >   NO DIRECT CONVERSION TO WC3 UNITS.
//                                          >   lower values are slower, close to .1 are pretty fast.
//
//              < Methods >
//
//              yourvar.settick( real t )
//                      > sets the timeout/frequency for the onPeriod method
//
//              yourvar.size( real COLLISION )
//
//                      COLLISION           >   collision size of the missile, be sure you have the collision function
//                                              and the filter.
//            
//              yourvar.horizontal( real H_LAUNCH, real X_ARC )
//
//                      H_LAUNCH real -45 - +45 >   launch angle relative to unit facing.
//                      X_ARC real 0-1000...    >   horizontal arc width, again experiment with wide/narrow.
//
//              yourvar.scale( real s )
//
//              < Optionals >
//
//              method onStart          takes nothing returns nothing defaults nothing
//                      > if you want to manipulate anything else before the projectiles move.
//
//              method onPeriod          takes nothing returns nothing defaults nothing
//                      > if you want to do other stuff besides move the projectile per tick, do it in this method.
//                      > you can set the rate method fires via the .settick(t) method
//
//              method onCollision    takes unit u returns nothing defaults nothing
//                      > manipulate the unit u when it enters collision range.
//
//              method cfilter        takes unit u returns boolean defaults false
//                      > filter for units that will enter range.
//
//              method onEnd          takes nothing returns nothing defaults nothing
//              
//
//======================================================================================

globals
    private real TIMEOUT = 0.03125
endglobals

private interface APEXInterface
    method onStart        takes nothing returns nothing defaults nothing
    method onPeriod       takes nothing returns nothing defaults nothing
    method onCollision    takes unit u returns nothing defaults nothing
    method cfilter        takes unit u returns boolean defaults false
    method onEnd          takes nothing returns nothing defaults nothing
endinterface

struct APEX extends APEXInterface
            unit caster
            unit proj     
    private real x1        
    private real y1        
    private real x2        
    private real y2        
    private real z1        
    private real z2        
    private real arcspeed   
    private real arc       
    private real face    
    private effect fx
            group dg
    private real range
    
    private real tick
    private real tc
    private boolean first
    
    private real A
    private real outx      
    private real outy
    private real s2     
    

    //===================================================================================
    
    method settick takes real t returns nothing
        set .tick = I2R(R2I(t/TIMEOUT))*TIMEOUT
    endmethod
    
    method scale takes real s returns nothing
        call SetUnitScale(.proj,s,s,s)
    endmethod
    
    method size takes real r returns nothing
        set .range = r
    endmethod
    
    method horizontal takes real angle, real width returns nothing
        set .outx = .x1+ width *Cos(Atan2(.y2-.y1,.x2-.x1)+(angle))
        set .outy = .y1+ width *Sin(Atan2(.y2-.y1,.x2-.x1)+(angle))
    endmethod
    
    //===================================================================================
    
    method move takes nothing returns nothing
        local real nx
        local real ny
        local real fly = GetUnitFlyHeight(.proj)
        
        //Calculations from Vexorian's Projectile System.
        //     calculates the vertical arc.
        local real od = SquareRoot(Pow(GetUnitX(.proj)-.x2,2) +  Pow(GetUnitY(.proj)-.y2,2))
        local real time = od / .arcspeed
        local real zspeed = (.z2-fly+0.5*.arc*time*time)/time

        //Calculataions from emjlr's Wild Axes spell.
        //     calculates the horizontal arc.
        local real b = 1.-.A
            
        //VERTICAL ARC, from Vexorian 
        call SetUnitFlyHeight(.proj,fly+zspeed*.035,0)
        call SetUnitAnimationByIndex(.proj,R2I(Atan2(zspeed,.arcspeed)* bj_RADTODEG)+90) //Thanks infrane!
        
        //Corrective Facing >by me, 13lade619<
        set nx = .x1*.A*.A+.outx*2*.A*b+.x2*b*b
        set ny = .y1*.A*.A+.outy*2*.A*b+.y2*b*b
        call SetUnitFacingTimed(.proj, bj_RADTODEG*Atan2(ny - GetUnitY(.proj), nx - GetUnitX(.proj)), 0)
        
        //HORIZONTAL ARC, from emjlr.
        call SetUnitX(.proj,nx)
        call SetUnitY(.proj,ny)
        set .A = .A-.s2
    endmethod
    
    method collisionhandler takes nothing returns nothing
        local unit u
        local group g = CreateGroup()
        
        call GroupEnumUnitsInRange(g,GetUnitX(.proj),GetUnitY(.proj),.range,null)
        
        loop
            set u = FirstOfGroup(g)
            call GroupRemoveUnit(g,u)
            exitwhen u == null
            
            if not IsUnitInGroup(u,.dg) and .cfilter(u) and SquareRoot(Pow((GetUnitFlyHeight(.proj)-GetUnitFlyHeight(u)),2))<=.range then
                call GroupAddUnit(.dg,u)
                call .onCollision(u)
            endif
        
        endloop
        
        call DestroyGroup(g)
        set g = null
        set u = null
    endmethod
    
    method periodic takes nothing returns nothing
        set .tc = .tc+TIMEOUT
        
        if .onStart.exists and .first==true then
            call .onStart()
            set .first = false
        endif
            
        if (.A <= 0) then
            if .onEnd.exists then
                call .onEnd()
            endif
            call .stopPeriodic()
            call .destroy()
        else
            call .move()
            if .onCollision.exists and .cfilter.exists then
                call .collisionhandler()
            endif
            if .onPeriod.exists and .tc>=.tick then
                call .onPeriod()
                set .tc = 0
            endif
        endif
    endmethod
    
    implement T32x
    
    //===================================================================================     
    
    method onDestroy takes nothing returns nothing    
        call DestroyEffect(.fx)
        call SetUnitExploded(.proj, true)
        call KillUnit(.proj)
        call GroupClear(.dg)
        set .proj = null    
    endmethod
    
    //===================================================================================     
    
    static method create takes unit caster, real x1, real y1, real z1, real x2, real y2, real z2, real varc, real speed, string model, integer dummy returns thistype
        local thistype this = thistype.allocate()
        
        set .caster = caster
        
        if .dg == null then
           set .dg = CreateGroup()
        endif
        
        set .range = 0
        set .x1 = x1
        set .y1 = y1
        set .x2 = x2
        set .y2 = y2
        
        set .z1 = z1
        set .z2 = z2
        
        set .tick = TIMEOUT
        set .tc = 0
        
        set .face = Atan2(.y2-.y1,.x2-.x1)*bj_RADTODEG
        
        // VERTICALS / Vexorian
        set .arcspeed = 2200
        set .arc = (varc) * 6000
        
        // HORIZONTALS / emjlr3
        set .A = 1
        set .outx = .x1
        set .outy = .y1                        
        set .s2 = speed // Affects the REAL SPEED of the projectile, lower is slower. always<1
            
        // PROJECTILE
        set .proj = CreateUnit(GetOwningPlayer(.caster),dummy,.x1,.y1,.face)
        set .fx = AddSpecialEffectTarget(model,.proj,"origin")
        call SetUnitFlyHeight(.proj,.z1,0)
        
        set .first = true
        call .startPeriodic()
        
        return this
    endmethod
endstruct
endlibrary


Sample Usage:
Upon casting, 3 phoenix models are launched from the caster, each time with random speed.

JASS:
struct proj extends APEX


    method onPeriod takes nothing returns nothing
        call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl",.proj,"origin"))
    endmethod
    
    method cfilter takes unit u returns boolean
        return IsUnitAliveBJ(u) and u!=.caster
    endmethod
    
    method onCollision takes unit u returns nothing
        call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl",u,"origin"))
        call KillUnit(u)
    endmethod
    
    method onEnd takes nothing returns nothing
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(.proj),GetUnitY(.proj)))
    endmethod
    
    method onStart takes nothing returns nothing
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(.caster),GetUnitY(.caster)))
    endmethod
endstruct

function Trig_Sample_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Sample_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    
    local proj p = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",'e001')
    local proj k = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",'e001')
    local proj j = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",'e001')
    
    call p.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
    call j.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
    call k.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
    
    call p.size(64)
    call j.size(64)
    call k.size(64)
    
    call p.settick(.03125)
    call j.settick(.03125)
    call k.settick(.03125)

    set caster = null
endfunction

//===========================================================================
function InitTrig_Sample takes nothing returns nothing
    set gg_trg_Sample = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Sample, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Sample, Condition( function Trig_Sample_Conditions ) )
    call TriggerAddAction( gg_trg_Sample, function Trig_Sample_Actions )
endfunction


Demo Map v5:
 

Attachments

  • Apex.PNG
    Apex.PNG
    330.2 KB · Views: 422
  • APEX_13lade.v5.w3x
    56.5 KB · Views: 276

13lade619

is now a game developer :)
Reaction score
399
ok... sorry if i'm a bit behind on the whole efficiency game.

i'll try to use t32..
and if you know better ways to make the system more efficient please recode.

EDIT..
'cant really figure out how to use T32 at the moment... if anyone can quickly code this into T32 then please do.

anyways, please comment on the concept for now.
 

Nexor

...
Reaction score
74
Casting the spell on the unit's portrait ( 0 distance) will cause the phoenixes NOT to disappear. anyway it looks good :)
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
library APEX requires T32

//=======================================================================================
//                      __     ___
//         _  ____ ,___\  \   /  /
//        /_\ | - \  __\\  \/  /      Advanced
//       / _ \| -,/  _|_ \    \        Projectile        by 13lade619
//      /_/ \_\_| |____//  /\  \        EXperiments
//                     /_ /  \__\   v1
//
//  DISCLAIMER : The values used in this system are NOT based on the 
//               Obect Editor measures. You as the user WILL need to 
//               EXPERIMENT to get what shape of trajectory you really
//               want to create.
//  
//  Credits : Jesus4Lyf, for the KT System.
//          : Romek, for UAC's optional methods algorithm, and UAC as a basis for coding.
//          : emjlr3, for his Wild Axes spell algorithm (provides horizontal arc)
//          : Vexorian, for his Caster System arc algorithm (provides vertical arc)
//
//  PROS    :   Supports VERTICAL COLLISION.
//          :   Supports HORIZONTAL ARC.
//          :   Can be used as collision missiles and/or AoE missiles.
//
//  CONS    :   Only POINT TO POINT targeting.
//          :   ..i think .create() has too many arguments..
//          :   ..too much maths for movement., even i cant understand.
//
//
//  SYNTAX  :   struct yourstruct extends APEX
//              
//              local yourstruct yourvar = yourstruct.create(CASTER, START_X, START_Y, START_Z, 
//                                                          END_X, END_Y, END_Z, Z_ARC, X_ARC, 
//                                                          H_LAUNCH, SPEED, MODEL, COLLISION)
//                  
//                      Z_ARC real 0-2      >   vertical arc, experiment with values 0-2 and find a decent shape..
//                      X_ARC real 0-1000...>   horizontal arc width, again experiment with wide/narrow.
//                      H_LAUNCH real -45 - +45 >   launch angle relative to unit facing.
//              
//                      SPEED real (.01-.1) >   NO DIRECT CONVERSION TO WC3 UNITS.
//                                          >   lower values are slower, close to .1 are pretty fast.
//
//======================================================================================

private interface APEXInterface
    method onCollision    takes unit u returns nothing defaults nothing
    method cfilter        takes unit u returns boolean defaults false
    method onEnd          takes nothing returns nothing defaults nothing
endinterface

struct APEX extends APEXInterface
            unit caster
            unit proj     
    private real x1        
    private real y1        
    private real x2        
    private real y2        
    private real z1        
    private real z2        
    private real arcspeed   
    private real arc       
    private real face    
    private effect fx
            group dg
    private real range
    
    private real A         // from emjlr's Wild Axes spell
    private real outx      
    private real outy
    private real s2     
        
    method move takes nothing returns nothing
        local real nx
        local real ny
        //Calculations from Vexorian's Projectile System.
        //     calculates the vertical arc.
        local real od = SquareRoot(Pow(GetUnitX(.proj)-.x2,2) +  Pow(GetUnitY(.proj)-.y2,2))
        local real time = od / .arcspeed
        local real zspeed = (.z2-GetUnitFlyHeight(.proj)+0.5*.arc*time*time)/time

        //Calculataions from emjlr's Wild Axes spell.
        //     calculates the horizontal arc.
        local real b = 1.-.A
            
        //VERTICAL ARC, from Vexorian 
        call SetUnitFlyHeight(.proj,GetUnitFlyHeight(.proj)+zspeed*.035,0)
        call SetUnitAnimationByIndex(.proj,R2I(Atan2(zspeed,.arcspeed)* bj_RADTODEG)+90) //Thanks infrane!
        
        //Corrective Facing >by me, 13lade619<
        set nx = .x1*.A*.A+.outx*2*.A*b+.x2*b*b
        set ny = .y1*.A*.A+.outy*2*.A*b+.y2*b*b
        call SetUnitFacingTimed(.proj, bj_RADTODEG*Atan2(ny - GetUnitY(.proj), nx - GetUnitX(.proj)), 0)
        
        //HORIZONTAL ARC, from emjlr.
        call SetUnitX(.proj,nx)
        call SetUnitY(.proj,ny)
        set .A = .A-.s2
    endmethod
    
    method collisionhandler takes nothing returns nothing
        local unit u
        local group g = CreateGroup()
        
        call GroupEnumUnitsInRange(g,GetUnitX(.proj),GetUnitY(.proj),.range,null)
        
        loop
            set u = FirstOfGroup(g)
            call GroupRemoveUnit(g,u)
            exitwhen u == null
            
            if not IsUnitInGroup(u,.dg) and .cfilter(u) and SquareRoot(Pow((GetUnitFlyHeight(.proj)-GetUnitFlyHeight(u)),2))<=.range then
                call GroupAddUnit(.dg,u)
                call .onCollision(u)
            endif
        
        endloop
        
        call DestroyGroup(g)
        set g = null
        set u = null
    endmethod
    
    method periodic takes nothing returns nothing
        local boolean r = false
        //local group g
        //local code groupcall = function thistype.collisionhandler
        
        if (.A <= 0) then
            if .onEnd.exists then
                call .onEnd()
            endif
            call DestroyEffect(.fx)
            call SetUnitExploded(.proj, true)
            call KillUnit(.proj)
            set .proj = null
            call DestroyGroup(.dg)
            set .dg=null
            call .destroy()
            set r = true
            call .stopPeriodic()
        else
            call .move()
            if .onCollision.exists and .cfilter.exists then
                call .collisionhandler()
            endif
        endif
    endmethod
    
    implement T32x
    
    //===================================================================================        
    static method create takes unit caster, real x1, real y1, real z1, real x2, real y2, real z2, real varc, real width, real angle, real speed, string model, real range returns thistype
        local thistype this = thistype.allocate()
        
        set .caster = caster
        set .dg = CreateGroup()
        set .range = 100
        set .x1 = x1
        set .y1 = y1
        set .x2 = x2
        set .y2 = y2
        
        set .z1 = z1
        set .z2 = z2
        
        set .face = Atan2(.y2-.y1,.x2-.x1)*bj_RADTODEG
        
        // VERTICALS / Vex
        set .arcspeed = 2200    // affects the rate where the arc changes, lower generates bigger arc. calc by Vexorian.
        set .arc = (varc) * 6000 // vertical arc. change only within the (). calculation by Vexorian.
        
        set .A = 1 // variable from emjlr.. dont change.
        
        // HORIZONTALS / emjlr3
        set .outx = .x1+ width *Cos(Atan2(.y2-.y1,.x2-.x1)+(angle))
        set .outy = .y1+ width *Sin(Atan2(.y2-.y1,.x2-.x1)+(angle))
        // Affects the REAL SPEED of the projectile, lower is slower. always<1
        set .s2 = speed
            
        //Starting movement, move to the PMove Function.
        set .proj = CreateUnit(GetOwningPlayer(.caster),'e001',.x1,.y1,.face)
        set .fx = AddSpecialEffectTarget(model,.proj,"origin")
        call SetUnitFlyHeight(.proj,.z1,0)

        //call TimerStart(.T, .03125, true, callback)
        call .startPeriodic()
        
        return this
    endmethod
    //===================================================================================
endstruct

endlibrary

Here you go.

IMO :
JASS:
call SetUnitFlyHeight(.proj,GetUnitFlyHeight(.proj)+zspeed*.035,0)]
//Store fly height by using a variables, this saves a function call. = =

        loop
            set u = FirstOfGroup(g)
            call GroupRemoveUnit(g,u)
            exitwhen u == null
            
            if not IsUnitInGroup(u,.dg) and .cfilter(u) and SquareRoot(Pow((GetUnitFlyHeight(.proj)-GetUnitFlyHeight(u)),2))<=.range then
                call GroupAddUnit(.dg,u)
                call .onCollision(u)
            endif
        
        endloop
        //
        set .dg = CreateGroup()
        call DestroyGroup(.dg)
        //Recycle the group?
        //Use filter unit is faster and saves function call.
        
//Extra : Recycle the projectile since they use same dummy model.

//Since the .create() has long parameter, it is better to let user set the variables 1 by 1.
 

Hatebreeder

So many apples
Reaction score
381
So... This is basically a summery of Arc functions that were modified and made into a library?

~_~
Mostly, I see stuff from Emj and Vex.
Did they give you permission for use?
Or are these Open source functions?
 

13lade619

is now a game developer :)
Reaction score
399
Updated with v3.
//Recycle the group?
//Use filter unit is faster and saves function call.
how do i recycle the group?

just create one at struct initialization and then only clear (not destroy) it?..
explain filter unit, how exactly?.

(well i really don't go into systems making in vJASS that much..)

//Extra : Recycle the projectile since they use same dummy model.

So... This is basically a summery of Arc functions that were modified and made into a library?

well, yes.. i saw that horizontal arc was requested much and hard to code,
i thought i'd make a system that made projectiles like those since i never seen one myself.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
library APEX requires T32, GroupUtils

private interface APEXInterface
    method onPeriod       takes nothing returns nothing defaults nothing
    method onCollision    takes unit u returns nothing defaults nothing
    method cfilter        takes unit u returns boolean defaults false
    method onEnd          takes nothing returns nothing defaults nothing
endinterface

struct APEX extends APEXInterface
    private static conditionfunc cf
    private static thistype this
            unit caster
            unit proj     
    private real x1        
    private real y1        
    private real x2        
    private real y2        
    private real z1        
    private real z2        
    private real arcspeed   
    private real arc       
    private real face    
    private effect fx
            group dg
    private real range
    
    private real tick
    private real tc
    
    private real A
    private real outx      
    private real outy
    private real s2     
    

    //===================================================================================
    
    method settick takes real t returns nothing
        set .tick = I2R(R2I(t/T32_PERIOD))*T32_PERIOD
    endmethod
    
    method scale takes real s returns nothing
        call SetUnitScale(.proj,s,s,s)
    endmethod
    
    method size takes real r returns nothing
        set .range = r
    endmethod
    
    method horizontal takes real angle, real width returns nothing
        set .outx = .x1+ width *Cos(Atan2(.y2-.y1,.x2-.x1)+(angle))
        set .outy = .y1+ width *Sin(Atan2(.y2-.y1,.x2-.x1)+(angle))
    endmethod
    
    //===================================================================================
    
    method move takes nothing returns nothing
        local real nx
        local real ny
        local real fly = GetUnitFlyHeight(.proj)
        
        //Calculations from Vexorian's Projectile System.
        //     calculates the vertical arc.
        local real od = SquareRoot(Pow(GetUnitX(.proj)-.x2,2) +  Pow(GetUnitY(.proj)-.y2,2))
        local real time = od / .arcspeed
        local real zspeed = (.z2-fly+0.5*.arc*time*time)/time

        //Calculataions from emjlr's Wild Axes spell.
        //     calculates the horizontal arc.
        local real b = 1.-.A
            
        //VERTICAL ARC, from Vexorian 
        call SetUnitFlyHeight(.proj,fly+zspeed*.035,0)
        call SetUnitAnimationByIndex(.proj,R2I(Atan2(zspeed,.arcspeed)* bj_RADTODEG)+90) //Thanks infrane!
        
        //Corrective Facing >by me, 13lade619<
        set nx = .x1*.A*.A+.outx*2*.A*b+.x2*b*b
        set ny = .y1*.A*.A+.outy*2*.A*b+.y2*b*b
        call SetUnitFacingTimed(.proj, bj_RADTODEG*Atan2(ny - GetUnitY(.proj), nx - GetUnitX(.proj)), 0)
        
        //HORIZONTAL ARC, from emjlr.
        call SetUnitX(.proj,nx)
        call SetUnitY(.proj,ny)
        set .A = .A-.s2
    endmethod
    
    static method unithandler takes nothing returns boolean
        local unit u = GetFilterUnit()
        local thistype this = thistype.this
        if not IsUnitInGroup(u,.dg) and .cfilter(u) and SquareRoot(Pow((GetUnitFlyHeight(.proj)-GetUnitFlyHeight(u)),2))<=.range then
            call GroupAddUnit(.dg,u)
            call .onCollision(u)
        endif
        return false
    endmethod
    
    method collisionhandler takes nothing returns nothing
        set thistype.this = this
        call GroupEnumUnitsInRange(ENUM_GROUP,GetUnitX(.proj),GetUnitY(.proj),.range,thistype.cf)
    endmethod
    
    method periodic takes nothing returns nothing
        set .tc = .tc+T32_PERIOD
        
        if (.A <= 0) then
            if .onEnd.exists then
                call .onEnd()
            endif
            call .stopPeriodic()
            call .destroy()
        else
            call .move()
            if .onCollision.exists and .cfilter.exists then
                call .collisionhandler()
            endif
            if .onPeriod.exists and .tc>=.tick then
                call .onPeriod()
                set .tc = 0
            endif
        endif
    endmethod
    
    implement T32x
    
    //===================================================================================     

    method onDestroy takes nothing returns nothing    
        call DestroyEffect(.fx)
        call SetUnitExploded(.proj, true)
        call KillUnit(.proj)
        call ReleaseGroup(.dg)
        call GroupRefresh(.dg)
        set .proj = null    
    endmethod
    
    //===================================================================================     
    
    static method create takes unit caster, real x1, real y1, real z1, real x2, real y2, real z2, real varc, real speed, string model returns thistype
        local thistype this = thistype.allocate()
        
        set .caster = caster
        set .dg = NewGroup()
        set .range = 0
        set .x1 = x1
        set .y1 = y1
        set .x2 = x2
        set .y2 = y2
        
        set .z1 = z1
        set .z2 = z2
        
        set .tick = T32_PERIOD
        set .tc = 0
        
        set .face = Atan2(.y2-.y1,.x2-.x1)*bj_RADTODEG
        
        // VERTICALS / Vexorian
        set .arcspeed = 2200
        set .arc = (varc) * 6000
        
        // HORIZONTALS / emjlr3
        set .A = 1
        set .outx = .x1
        set .outy = .y1                        
        set .s2 = speed // Affects the REAL SPEED of the projectile, lower is slower. always<1
            
        // PROJECTILE
        set .proj = CreateUnit(GetOwningPlayer(.caster),'e001',.x1,.y1,.face)
        set .fx = AddSpecialEffectTarget(model,.proj,"origin")
        call SetUnitFlyHeight(.proj,.z1,0)

        call .startPeriodic()
        
        return this
    endmethod
    
    static method onInit takes nothing returns nothing
        set thistype.cf = Condition(function thistype.unithandler)
    endmethod
    
endstruct
endlibrary

Optimized the usage of unit group. :)

Update : I just found a bug. The missile will freeze when the spell is casted to caster itself.
 

Romek

Super Moderator
Reaction score
963
GroupUtils is full of fail

Since you're using structs anyway, just use group recycling through the struct.
JASS:
struct Example
   group g

   static method create takes nothing returns thistype
       local thistype this = .allocate()
       if .g == null then
           set .g = CreateGroup()
       else
           call GroupClear(.g)
       endif
       return this
   endmethod
   
endstruct

That's all there is to it. You could also clear the group in an onDestroy method instead of in the create method, though it makes no difference whatsoever.
 

13lade619

is now a game developer :)
Reaction score
399
UPDATE!!

v5
Removed GroupUtils, better group utilization.
new onStart method
new create, you can now set the dummy used.

That's all there is to it. You could also clear the group in an onDestroy method instead of in the create method, though it makes no difference whatsoever.
 

Viikuna

No Marlo no game.
Reaction score
265
Well, even though you dont use GroupUtils, you should use somekind of EnumGroup. ( Your collinsionhandler method sucks terribly, currently )
 

Romek

Super Moderator
Reaction score
963
Many of those methods should be private.

In your collisionHandler method, you could use a single, static group instead of constantly creating and destroying groups. You could also put those group actions into a group filter, which will increase speed/efficiency.

.cFilter should default true. If an onCollision method exists, I'd assume that it would filter all units unless the cFilter method states otherwise.

[ljass]Pow(x, 2)[/ljass] should simply be [ljass]x*x[/ljass].

Also, the TIMEOUT constant isn't needed. Simply use the T32x constant (I believe it's public).
 

Viikuna

No Marlo no game.
Reaction score
265
Also method.exists is slow. You should only use it when projectile is created and save that information to some boolean members for later use.


The biggest problem really is that this lacks most of cool features I expect a proper projectile system to have. ( I can make you a list later, gotta take my pizza out of the whatever-it-is-called-in-english -thingy )
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top