1. The long-awaited results for Concept Art Contest #11 have finally been released!
    Dismiss Notice
  2. Join Texturing Contest #30 now in a legendary battle of mythological creatures!
    Dismiss Notice
  3. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  4. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  5. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice

[Snippet] Fly

Discussion in 'Graveyard' started by Krogoth, May 5, 2014.

  1. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    Libraries:
    - Curves
    - Fly

    FAQ

    Q: WTF?
    A: Every object's movement in 3-dimensional space can be represented as a composition of XY (surface) and Z (height) movement.
    Most custom maps XY movement is nothing more than simple linear trajectory with constant movespeed. Jump is an obvious example, where specific Z coordinates form parabola. Same maps don't have flying units realistically interact with each other and require those parabolas just as visual.
    Meanwhile our sense of continuity is about 0.025 sec, we are less sensitive to rate of trajectory, so smooth trajectory and right amount of points, connected linearly, look almost same for us. Thus, speed can be updated every 0.1 sec, or 0.2 sec, or even bigger, which depends on situation (the faster is movement the less must be frequency).
    Relatively small amount of points, required to satisfy our senses, makes wise to use constant set of points for geometrically similar curves.
    Curves library is meant to put normalized curves, which can be easily scaled then.
    Example:
    Normalized = {0, 0.75, 1, 0.75, 0} (parabola)
    Scaled (x400) = {0, 300, 400, 300, 0} (parabola)

    Movement algorithm is made so it uses rate of curve, to minimize input data, some inner calculations and opens door for composite Z movement from different sources (by summing up all rates).
    Example:
    Curve = {0, 0.75, 1, 0.75, 0}
    Rate of curve = {0.75, 0.25, -0.25, -0.75}

    Q: How can I do my curve?
    A: Very easy:

    -=- Library Curves -=-

    Code (vJASS):
    //-=-=-=-=--=-=-=-=-=-=-=-
    //-=-=-=-] Curves [-=-=-=-
    //-=-=-=-=-=-=-=--=-=-=-=-

    library Curves
    //-=-=-=- Settings -=-=-=-
    //! textmacro CURVES
        constant integer CURVE_PARABOLA = 0
        constant integer CURVE_PARABOLA5_RATE = 6
        constant integer CURVE_PARABOLA7_RATE = 11
    //! endtextmacro

    //! textmacro CURVES_DATA
        //CURVE_PARABOLA5
        set DATA[0] = 5
        set DATA[1] = 0
        set DATA[2] = .75
        set DATA[3] = 1
        set DATA[4] = .75
        set DATA[5] = 0
        //CURVE_PARABOLA5_RATE
        set DATA[6] = 4
        set DATA[7] = .75
        set DATA[8] = .25
        set DATA[9] = -.25
        set DATA[10] = -.75
        //CURVE_PARABOLA7_RATE
        set DATA[11] = 6
        set DATA[12] = .6
        set DATA[13] = .3
        set DATA[14] = .1
        set DATA[15] = -.1
        set DATA[16] = -.3
        set DATA[17] = -.6
    //! endtextmacro
    //-=-=-=--=-=-=-=-=-=-=-=-

    globals
        //! runtextmacro CURVES()
    endglobals
        struct CURVES extends array
            readonly static real array DATA
            private static method onInit takes nothing returns nothing
            //! runtextmacro CURVES_DATA()
            endmethod
        endstruct
    endlibrary


    -=- Library Fly -=-

    Code (vJASS):
    //-=-=-=-=-=-=-=-=-=-=-
    //-=-=-=-] Fly [-=-=-=-
    //-=-=-=-=-=-=-=-=-=-=-

    library Fly requires Curves, Support
    globals
        private integer I = 0
        private unit array Unit
        private timer array Timer
        private integer array Curve
        private real array Scale
        private real array Speed
        private integer array Node
        private real array Height
    endglobals

        private function Refresh takes nothing returns nothing
            set Support.workTimer = GetExpiredTimer()
            set Support.workInteger = I
            loop
                if Support.workTimer == Timer[Support.workInteger] then
                    set Node[Support.workInteger] = Node[Support.workInteger] + 1
                    set Support.workReal = CURVES.DATA[Curve[Support.workInteger] + Node[Support.workInteger]]
                    set Height[Support.workInteger] = Height[Support.workInteger] + Scale[Support.workInteger] * Support.workReal
                    if Support.workReal < 0 then
                        set Support.workReal = -Speed[Support.workInteger] * Support.workReal
                    else
                        set Support.workReal =  Speed[Support.workInteger] * Support.workReal
                    endif
                    call SetUnitFlyHeight(Unit[Support.workInteger], GetUnitDefaultFlyHeight(Unit[Support.workInteger]) + Height[Support.workInteger], Support.workReal)
                    if Node[Support.workInteger] == CURVES.DATA[Curve[Support.workInteger]] then
                        if Support.workInteger == I then
                            set Unit[Support.workInteger] = null
                        else
                            set Unit[Support.workInteger] = Unit[I]
                            set Timer[Support.workInteger] = Timer[I]
                            set Curve[Support.workInteger] = Curve[I]
                            set Scale[Support.workInteger] = Scale[I]
                            set Speed[Support.workInteger] = Speed[I]
                            set Node[Support.workInteger] = Node[I]
                            set Height[Support.workInteger] = Height[I]
                            set Unit[I] = null
                            set Timer[I] = Support.workTimer
                        endif
                        call PauseTimer(Support.workTimer)
                        set I = I - 1
                    endif
                    return
                endif
                set Support.workInteger = Support.workInteger - 1
            endloop
        endfunction    

        function UnitFly takes unit u, integer curve, real height, real time returns nothing
            set I = I + 1
            set Unit[I] = u
            if Timer[I] == null then
                set Timer[I] = CreateTimer()
            endif
            call TimerStart(Timer[I], time / CURVES.DATA[curve], true, function Refresh)
            set Curve[I] = curve
            set Scale[I] = height
            set Speed[I] = height * CURVES.DATA[curve] / time
            set Node[I] = 1
            set Height[I] = height * CURVES.DATA[curve + 1]
            call SetUnitFlyHeight(u, GetUnitDefaultFlyHeight(u) + Height[I], Speed[I] * CURVES.DATA[curve + 1])
        endfunction
    endlibrary


    Example of usage:
    Code (vJASS):
    call UnitFly(GetTriggerUnit(), CURVE_PARABOLA7_RATE, 300, 2)

    It makes unit fly for 2 seconds with 300 height at maximum
    XY movement is done separately

    Added:
    Btw, if you see some memory leak, point me please
     
    Last edited: May 6, 2014
  2. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,007
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    REAL SCRIPTS HAVE CURVES.

    This curves thing is just really bad man. Document it and describe what the values mean so that people would understand how to create their own trajectories.
     
  3. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,180
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Code (vJASS):

            if Timer[I] == null then
                set Timer[I] = CreateTimer()
            endif
            call TimerStart(Timer[I], time / CURVES.DATA[curve], true, function Refresh)
    derp.. derp.. >.>

    first, I really don't know how to use this, this is something new, unique, but inefficient way to generate the trajectory, I believe you can do it by using one timer and using normal dynamic indexing. Also I see you like textmacro so much, there is no point in using it too often..

    btw
    Code (vJASS):

            private static method onInit takes nothing returns nothing
            //! runtextmacro CURVES_DATA()
            endmethod

    you may use
    module
    to make it more elegant.

    Code (vJASS):

    //! textmacro CURVES
        constant integer CURVE_PARABOLA = 0
        constant integer CURVE_PARABOLA5_RATE = 6
        constant integer CURVE_PARABOLA7_RATE = 11
    //! endtextmacro

    Y U NO replace textmacro & endtextmacro to globals & endglobals?

    Code (vJASS):

        set DATA[0] = 5
        set DATA[1] = 0
        set DATA[2] = .75
        set DATA[3] = 1
        set DATA[4] = .75
        set DATA[5] = 0

    and I think everything must be calculated, not defined by user. Also that means we must declare new variable like
     constant integer CURVE_PARABOLA5_RATE = 6
    to make a new trajectory? that's horrible.
    and
    library Curves
    is actually doing nothing except declaring variables, however, imo this is unaccepatable.. but I like the idea where user may set the estimated time
    function Fly takes unit u, integer curve, real height, real time
     
  4. gorillabull

    gorillabull

    Joined:
    Jul 17, 2011
    Messages:
    1,368
    Resources:
    2
    Spells:
    2
    Resources:
    2
    why not use 3 parametric equations for the trajectory, x and y can be linear and z can be a parabola
     
  5. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    I just that color, man :D

    Well, those constants is nothing compared to triggers. :D
    Declaring comfortable names with constants is usual thing
    I am not sure if I can use module, because set data is put inside function
    I disagree that user must do himself nothing to profit from library. This is still very user-friendly.

    Added:
    Some "documentation" appeard
     
  6. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    Dalvengyr, what you mean by using 1 timer btw?
    Sure, you can
     
  7. Adiktuz

    Adiktuz

    Joined:
    Oct 16, 2008
    Messages:
    9,674
    Resources:
    23
    Models:
    2
    Packs:
    1
    Maps:
    1
    Spells:
    16
    Tutorials:
    1
    JASS:
    2
    Resources:
    23
    It means that instead of using 1 timer per instance, you only use 1 timer that simply loops thru all instances

    and the code looks too confusing with all those textmacros when you don't even need them... and as Maggy said, please document what those values on CURVES does...

    Also instead of hardcoded curves, I would prefer that you simply take an "arc" value and dynamically create the actual parabola movement using a formula...
     
  8. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    Every timer must be supplied with its own period, otherwise it would make no sense.
    The thing is, each curve is set by constant number of points, therefore period is different for different fly time. If one jump is longer than other, it will take more time and use bigger period, that's why timers can't be merged. Also, each of them has own start point.
    But I can merge close timers though.
    Well, I will try something.
    See FAQ
    These curves aren't hardcoded. Calculating actual trajectory is relatively hardcoded.
    Imagine if you have zigzag trajectory. You need to write specific algorithm, which works slower, while going through coords is always same.
     
  9. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,180
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    they can't but you can use real to replace the "duration". but still you need to use one timer..
    what trigger? you dont need any trigger, if so, then still it's better to have 1 trigger than 100 constants perhaps? this is about possibility..
    that is the easiest way to generate a good parabola trajectory: using a formula which I dont remember clearly. and currently this library doesnt event support horizontal parabola movement which most missile systems around here has supported that one..

    you can, but with different way

    this is very not-user-friendly. since they must declare and define ~7 variables first to create ONE trajectory? How if I want to launch 100 missiles and each of them has different arc? so I need to declare/define (7*100 + 100 = 800) variables first? you must be joking

    seriously, that's more like a joke
     
  10. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    :ogre_rage:

    You need to do 100 different algorithms then, which, of course, means more code than 800 variables
    What a shame. :D

    All you need is to read my FAQ. You will see an explanation why the algorithm is good.
     
  11. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,180
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    if you are using the formula that I'm talking about, you just need one or two function then you can launch more than 100 missiles at once without declaring any new variable.. :)
    nope

    just a reference for you, look at how he calculate the trajectory, max height, etc. so that everything is done automatically, not manually like this
    Code (vJASS):
        set DATA[0] = 5
        set DATA[1] = 0
        set DATA[2] = .75
        set DATA[3] = 1
        set DATA[4] = .75
        set DATA[5] = 0



    EDIT:
    here is the easiest formula I have found so far:
    Code (Text):
    ((4.00 x fly_height_max) / distance_max) x (distance_max - distance_current) x (distance_current / distance_max)
    but still, there is no point in making a system like this anymore, there are just too many great similliar systems which doing their job multiple times better than yours, I'm sorry but I'm just trying tbh, so that you don't need to update this uselessly, eventually imo this one will never get approved except if you can make it better than the other existing one, that means you must re-write the whole code bcs this one is obviously inefficient. I'm sorry I can't say this inefficient, but this is just too unfriendly for user, and not dynamic..

    that is the big CON of this system
     
    Last edited: May 6, 2014
  12. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    This is not dialogue, you are completely retarded. My regrets.
    Those parabolas are same 1 curve, not 100. If you were able to read text and understand it same time, you would not argue by such shit.
     
  13. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,007
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Let the user pass in an eccentricity. Generate the curves.
    Don't use this Curves library crap.

    It's code-smell and it has terrible disadvantages like the fact that changing one of the arrays forces you to change every other one. What if I wanted to add an extra value or change a curve completely in the middle of all the declarations? This makes everything much more prone to human error because I have to correctly change the required count and all the required indices in the array settings and the global constant declarations.
     
  14. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    Ty :)
    I can make functions like SetCurve and CurveSetPoint.
    For example:
    Code (vJASS):
    call SetCurve(ROAD_TO_SCHOOL)
    call CurveSetPoint(0)
    call CurveSetPoint(0)
    call CurveSetPoint(0)
    call CurveSetPoint(0)
    call CurveSetPoint(0)
    call CurveSetPoint(0) //first lesson
    call CurveSetPoint(0)
    call CurveSetPoint(0)
    call CurveSetPoint(1)

    Is it acceptable?

    Added:
    My algorithm isn't the best, because I use timer array. There is a lot of improvement I can bring into it.
     
  15. Adiktuz

    Adiktuz

    Joined:
    Oct 16, 2008
    Messages:
    9,674
    Resources:
    23
    Models:
    2
    Packs:
    1
    Maps:
    1
    Spells:
    16
    Tutorials:
    1
    JASS:
    2
    Resources:
    23
    Why not put the FAQ into the header? Do you expect your users to remember those or to always check this thread if they forgot what those numbers are???

    You cannot use a single timer because you need different periods? Ever heard of counters? You can effectively use a single timer for this that uses a .03xxxx period and a counter for each instance... Though if you look at most movement/projectile scripts out there, they don't even use counters, they simply move everything every tick...

    and yeah, I agree with the Dreadlord, we don't need another one of these
     
  16. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    GY, because I have no time for this
     
  17. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,555
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    Alright.

    You can't submit two libraries in one post anyways.