System Dynamic Arcs

Andrewgosu

The Silent Pandaren Helper
Reaction score
715
Description:

A modest system which allows you to create missle arcs in-game with specified parameters.

Features:

- Arc appearance is changeable in-game with a single line code unlike unit missle projectile appearances
- Arc speed is changeable in-game
- Ability to attach your own functions (do damage, knockback, whatever) which trigger when the projectile hits its target
- includes 2 GUI-friendlier location versions

Requires:

CSData, CSSafety and Vexorians dummy unit model.

That's about it.


Any questions, bug finds and feedback is appreciated.


arcs.jpg

JASS:
library DynamicArcs requires CSCache, CSSafety
    globals
        private constant real TIMER_VAL = .03125
        private constant integer DUMMY_ID = 'e000'
        private constant real DEFAULT_CURVATURE = 4.
    endglobals

    private struct arc
        unit arcEffect
        
        effect attachedEffect
        
        real distSeg
        real dist = 0
        real cos
        real sin
        real startX
        real startY
        real maxDist
        real curve
        
        triggeraction tr = null
        trigger onHit = null
        
        integer N = 0
        integer endN

        method onDestroy takes nothing returns nothing
            call DestroyEffect(.attachedEffect)
            call UnitApplyTimedLife(.arcEffect, 'BTLF', 2.)
        endmethod
    endstruct

    private function arc_callback takes nothing returns nothing
        local timer expired = GetExpiredTimer()
        local arc data = GetCSData(expired)
        local real c = (data.dist * 2) / data.maxDist - 1

        set data.dist = data.dist + data.distSeg
        set data.N = data.N + 1

        if (data.N >= data.endN) then
            if (data.onHit != null) then
                call TriggerExecute(data.onHit)
                call TriggerRemoveAction(data.onHit, data.tr)
                call DestroyTrigger(data.onHit)
            endif
            call ReleaseTimer(expired)
            call data.destroy()
        endif
               
        call SetUnitPosition(data.arcEffect, data.startX + data.dist * data.cos, data.startY + data.dist * data.sin) 
        call SetUnitFlyHeight(data.arcEffect, (-c * c + 1) * (data.maxDist / data.curve), 0)
    endfunction
    

    private function arc_execute takes string modelName, integer speed, real curve, real x1, real y1, real x2, real y2, code actionFunc returns nothing
        local arc whichArc = arc.create()
        local real dx = x2 - x1
        local real dy = y2 - y1
        local real maxDist = SquareRoot(dx * dx + dy * dy)
        local real angle = Atan2(y2 - y1, x2 - x1)
        local timer t = NewTimer()
        
        set whichArc.endN = R2I((maxDist / speed) / TIMER_VAL + .5)
        
        set whichArc.arcEffect = CreateUnit(Player(0), DUMMY_ID, x1, x2, angle * bj_RADTODEG)
        call UnitAddAbility(whichArc.arcEffect, 'Aloc')
        set whichArc.attachedEffect = AddSpecialEffectTarget(modelName, whichArc.arcEffect, "origin")
                
        set whichArc.maxDist = maxDist
        set whichArc.curve = curve
        set whichArc.distSeg = speed * TIMER_VAL

        set whichArc.startX = x1
        set whichArc.startY = y1
        set whichArc.cos = Cos(angle)
        set whichArc.sin = Sin(angle)         

        if (actionFunc != null) then
            set whichArc.onHit = CreateTrigger()
            set whichArc.tr = TriggerAddAction(whichArc.onHit, actionFunc)    
        endif
        
        call UnitAddAbility(whichArc.arcEffect, 'Amrf')
        call UnitRemoveAbility(whichArc.arcEffect, 'Amrf') 
        
        call SetCSData(t, whichArc)
        call TimerStart(t, TIMER_VAL, true, function arc_callback)   
    endfunction 

    function CreateArc takes string modelPath, integer speed, real x1, real y1, real x2, real y2 returns nothing
        call arc_execute.execute(modelPath, speed, DEFAULT_CURVATURE, x1, y1, x2, y2, null)
    endfunction
    function CreateArcLoc takes string modelPath, integer speed, location startLoc, location targetLoc returns nothing
        call arc_execute.execute(modelPath, speed, DEFAULT_CURVATURE, GetLocationX(startLoc), GetLocationY(startLoc), GetLocationX(targetLoc), GetLocationY(targetLoc), null)
    endfunction
    
    function CreateArcEx takes string modelPath, integer speed, real curve, real x1, real y1, real x2, real y2, code actionFunc returns nothing
        call arc_execute.execute(modelPath, speed, curve, x1, y1, x2, y2, actionFunc)
    endfunction 
    function CreateArcExLoc takes string modelPath, integer speed, real curve, location startLoc, location targetLoc, code actionFunc returns nothing     
        call arc_execute.execute(modelPath, speed, curve, GetLocationX(startLoc), GetLocationY(startLoc), GetLocationX(targetLoc), GetLocationY(targetLoc), actionFunc)
    endfunction
endlibrary



Andrewgosu
 

Attachments

  • DynamicArcs_Andrewgosu_2008.w3x
    63.9 KB · Views: 181

Dr.Jack

That's Cap'n to you!
Reaction score
108
Looks good. Simple to use, everything is clear, no problems, leaks, bugs etc. I like it, good job. :)

One thing, how about simply calling actionFunc instead of adding it to a trigger and executing the trigger? Should make things faster and easier. Also, how about one time, instead of one per instance? It could definitely make things go smoother.

Anyway, I still like it, good job Andrewgosu. :thup:
 
Reaction score
456
call SetUnitFlyHeight(data.arcEffect, (-c * c + 1) * (data.maxDist / data.curve), 0.00)

I hate reading your codes, because they're almost perfectly coded. Nice screenshots.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Wow, great looking system! :D

I know that your system creates an arc, but have you thought about reusing the code or adding more functionality to it, like collision (distance of X,Y, and Z), or possibly unit targetted arcs (arcs that move towards a unit, rather than a point set at the start)?

Nice work. I wish I knew the game's formula for projectile arc. :p
 

Dr.Jack

That's Cap'n to you!
Reaction score
108
> or possibly unit targetted arcs

Actually that should be quite easy to do. Instead of using the same X and Y valuקs base them on a unit's X and Y value (by simply storing the unit on the struct). Sounds good?
 

Waaaaagh

I lost all my rep and my title being a jerk
Reaction score
70
You really should be using a boolexpr or function interface for your callback, not a trigger action. This would also eliminate your need to dynamically create a trigger. You could either do:

JASS:
call TriggerAddCondition(GlobalDummyTrig,CallbackBoolexpr)
call TriggerEvaluate(GlobalDummyTrig)
call TriggerClearConditions(GlobalDummyTrig)


or

JASS:
call FunctionPointerHandler.execute(<parameters>)


A boolexpr would be 'faster' due to not starting a new thread.
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
715
You are forgetting that the user has to specify the code which will be "attached" to the arc.

As I have heard, waits are not supported in boolean expressions and if the user specified function has waits...you know the rest.
 

Waaaaagh

I lost all my rep and my title being a jerk
Reaction score
70
You are forgetting that the user has to specify the code which will be "attached" to the arc.

As I have heard, waits are not supported in boolean expressions and if the user specified function has waits...you know the rest.


And, I don't know the parameters of the function the user specifies so obviously your second method wouldn't work either.

that's the point of function interfaces though. You define the parameters, so you know what they are.

function interface Callback takes datastruct info returns nothing


And waits are terrible anyway. (notice you've forced me to quote you for my post to make sense. I do *not* appreciate such a thing)
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
715
Sorry, I edited that out because I realised that you cannot have parameters for the code you itself want to pass as a parameter.

Now, if to make elaborate workarounds, the code wouldn't be as efficient anymore...


It works fine the way it is.

Code:
e.g

function noparameters takes nothing returns nothing
endfunction

// the function "noparameters" cannot have parameters because it's inputted as code in the "ForGroup" function
function example takes nothing returns nothing
    call ForGroup(whichGroup, function noparameters)
endfunction
 

Waaaaagh

I lost all my rep and my title being a jerk
Reaction score
70
it is not about parameters. The problem is triggeractions and dynamic triggers.
 
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