1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. Lead your forces to battle in the 15th Techtree Contest. The call is yours, commander!
    Dismiss Notice
  4. The reforging of the races is complete. Come see the 14th Techtree Contest Results.
    Dismiss Notice
  5. It's time to choose your horse in the race - the 32nd Modeling Contest Poll is up!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Solved] Arc Formula Discussion

Discussion in 'Triggers & Scripts' started by dardas, Apr 11, 2011.

  1. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Hey.. before i took a break from WC for a while,
    i used Parabola formula to determinate ARC for projectiles,
    well now i fail at it :D
    and besides, i made it calculate all the ARC values in a seperate function, so i found another bug doing that,
    whenever my real "arcValue" is not equal to 0, whether im calling the calculation or not,
    my all code stops working, and it wont collide with any enemy, and extra to that, the bullet just falls down, and vanishes.
    when its equal to 0, the bullet just flies straight to the point its meant to go to, and then hits anything in its way.. right now i cant find the problem :/
    heres the code:

    Code (vJASS):

    library MissleSystem initializer onInit requires /*
    */
    Vector     /* [url]www.wc3c.net/showthread.php?t=87027[/url]
    */
    ArmorUtils /* [url]www.wc3c.net/showthread.php?t=105849[/url]
    */
    GroupUtils /* [url]http://www.wc3c.net/showthread.php?t=104464[/url]
    */

       
        struct Missle
            public static thistype      t                                       = 0
            public static thistype      t2                                      = 0
            public static location      D_Loc                                   = Location(0, 0)
            public static real          TimerInterval                           = 0.032
            public static integer       Dummy_Unit                              = 'e000'
            public static integer       flight_ability                          = 'Amrf'
            //---------------------------------------------------------------------------------
            public unit                 Object                                  = null
            public unit                 Target                                  = null
            public player               Owner                                   = null
            public vector               Start                                   = 0
            public vector               Pos                                     = 0
            public vector               Reach                                   = 0
            public real                 Velocity                                = 0
            public real                 Damage                                  = 0
            public real                 Angle                                   = 0
            public real                 ArcCurve                                = 0
            public real                 passedDistance                          = 0
            public boolean              ignoreArmor                             = false
            public effect               Model
           
           
            public static method create takes player owner, real x, real y, string SFX, string attachPoint returns thistype
                set t = t + 1
                set t2 = t2 + 1
                    call MoveLocation(D_Loc, x, y)
                    set t.Object                = CreateUnit(owner, Dummy_Unit, x, y, 0)
                    set t.Pos                   = vector.create(x, y, GetLocationZ(D_Loc))
                    set t.Start                 = t.Pos
                    set t.Owner                 = owner
                    set t.Model                 = AddSpecialEffectTarget(SFX, t.Object, attachPoint)
                    set t.Velocity              = 0
                    set t.Damage                = 0
                    set t.Angle                 = 0
                    set t.ArcCurve              = 0
                    set t.passedDistance        = 0
                    set t.ignoreArmor           = false
                    call t.allowHeight()
                return t
            endmethod
           
            private static method DistanceBetweenVectors takes vector a, vector b returns real
                local real dx = b.x - a.x
                local real dy = b.y - a.y
                return SquareRoot(dx * dx + dy * dy)
            endmethod
           
            private static method JumpParabola takes real dist, real maxdist,real curve returns real
            // This function calculates the unit Z for a parabolic arc, by Shadow1500
                local real t = (dist*2)/maxdist-1
                return (-t*t+1)*(maxdist/curve)
            endmethod
           
            private static method GetUnitZ takes unit u returns real
                // finds a unit location Z, instead using another location.
                return GetCoordinateZ(GetUnitX(u), GetUnitY(u))
            endmethod
           
            private static method GetCoordinateZ takes real x, real y returns real
                // finds x/y location Z using a re-used dummy.
                call MoveLocation(D_Loc, x, y)
                return GetLocationZ(D_Loc)
            endmethod
               
            private static method GetZFactor takes real NewX, real NewY, real OldX, real OldY returns real
                // this function caculates the Z offset of 2 locations.
                // this function is by Inferior from hiveworkshop.com
                local real z = 0
                call MoveLocation(D_Loc, NewX, NewY)
                set z = GetLocationZ(D_Loc)
                call MoveLocation(D_Loc, OldX, OldY)
                return z - GetLocationZ(D_Loc)
            endmethod
                   
            private method CaculateArc takes nothing returns nothing
                local real dx = 0
                local real dy = 0
                local real dx2 = 0
                local real dy2 = 0
                local real md = Reach
                local real height = 0
                    set dx = Start.x - Pos.x
                    set dy = Start.y - Pos.y
                    set dx2 = Reach.x
                    set dy2 = Reach.y
                        set height = JumpParabola(SquareRoot(dx * dx + dy * dy), SquareRoot(dx2 * dx2 + dy2 * dy2), ArcCurve)
                        call SetUnitFlyHeight(Object, height, 0)
            endmethod
           
            public method allowHeight takes nothing returns nothing
                call UnitAddAbility(Object, flight_ability)
                call UnitRemoveAbility(Object, flight_ability)
            endmethod
           
            public method destroy takes nothing returns nothing
                call SetUnitExploded(Object, true)
                set Object = null
                set Target = null
                set Owner = null
                set Pos = 0
                set Reach = 0
                set passedDistance = 0
                set Velocity = 0
                call DestroyEffect(Model)
                set Model = null
                set ignoreArmor = false
               
                set t2 = t2 - 1
            endmethod
           
            public method TimeToDistance takes real time returns real
                return time * (Velocity / TimerInterval)
            endmethod
           
            public method SetDestinationTime takes real time returns nothing
                local real a = TimeToDistance(time)
                set Reach = vector.create(Pos.x + a, Pos.y + a, GetCoordinateZ(Pos.x + a, Pos.y + a))
                set Angle = GetUnitFacing(Object)
            endmethod
           
            public method SetDestinationXY takes real x, real y returns nothing
                set Reach = vector.create(x, y, GetCoordinateZ(x, y))
                set Angle = Atan2(Reach.y - Pos.y, Reach.x - Pos.x)
            endmethod
           
            public method SetDestination takes real distance returns nothing
                set Reach = vector.create(Pos.x + distance, Pos.y + distance, GetCoordinateZ(Pos.x + distance, Pos.y + distance))
                set Angle = GetUnitFacing(Object)
            endmethod
           
            private method DummyBer takes nothing returns boolean
                return GetUnitState(Target, UNIT_STATE_LIFE) > 0 and not IsUnitOwnedByPlayer(Target, Owner)
            endmethod
           
            public method onLoop takes nothing returns nothing
                local real armor = 0
                local real damage = 0
                local group g = NewGroup()
               
                call GroupUnitsInArea(g, Pos.x, Pos.y, 75)
                    set Target = FirstOfGroup(g)
                    if not (Target == null) and DummyBer() then
                        set armor = GetUnitArmor(Target)
                        if ignoreArmor == false then
                            set damage = GetReducedDamage(Damage, armor)
                        else
                            set damage = GetFullDamage(Damage, armor)
                        endif
                        call UnitDamageTarget(Object, Target, damage, true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
                        call destroy()
                    endif
                    set Pos.x = GetUnitX(Object) + Velocity * Cos (Angle)
                    set Pos.y = GetUnitY(Object) + Velocity * Sin (Angle)
                    call SetUnitX(Object, Pos.x)
                    call SetUnitY(Object, Pos.y)
                   
                    //call CaculateArc()
                   
                    if passedDistance >= Reach then
                        call destroy()
                    else
                        set passedDistance = passedDistance + Velocity
                    endif
                   
                    call ReleaseGroup(g)
            endmethod
        endstruct
       
        private function loopHandler takes nothing returns nothing
            local integer i = 0
            local integer end = s__Missle_t
           
            if end > 0 then
                loop
                set i = i + 1
                    call s__Missle_onLoop(i)
                exitwhen i == end
                endloop
            endif
        endfunction
       
        private function onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), s__Missle_TimerInterval, true, function loopHandler)
        endfunction
       
    endlibrary
     


    thanks in advance. :goblin_good_job:

    edit: sorry, gah, i forgot its jass, so i wrote code/trigger in bracelets ;/
     
  2. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    There's a really easy way to calculate arcs, and that is by using a gravity constant!
    An example:

    Code (vJASS):

        constant real GRAVITY = -4000.0;
        constant real TIMEOUT = 0.03125;
        constant integer FPS = R2I(1/TIMEOUT);

        struct object {
            ...
            vector vel, pos;

            method fireArc(vector dest, real time) {
                real dz = dest.z - pos.z; // delta z (height difference)
               
                vel.z = dz/(time*FPS); // z speed if the movement was linear
                vel.z = vel.z - GRAVITY*TIMEOUT*TIMEOUT*time*FPS*0.5; // add z-velocity so that zVel becomes 0 when the object has done half of the movement. Acceleration is measured in m/s^2.
            }


    This method is pretty good, and projects a mathematically correct parabola.
    However, it requires you to subtract GRAVITY*TIMEOUT*TIMEOUT from
    vel.z
    every iteration.

    Another solution is this: (I've shamelessly copied it from vexorian)
    Code (vJASS):

        constant real TIMEOUT = 0.03125;
        ....
       
        method calculateZ(unit u, real x1, real y1, real z1, real x2, real y2, real z2, real myArc, real myXYVelocity){
            real a = myArc * 3000.0;
            real d = SquareRoot((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); // distance left to target
            real time = d/myXYVelocity; // 2d velocity
            real v = (z2 - z)/time+a*time/0.5;      // z-ve
            a = z1 + v * TIMEOUT;                     // new fly height
            if (distanceThreshold <= d or a <= 0) {
                // movement finished!
            }
            SetUnitFlyHeight(myUnit, a, 0);        // update fly height
        }


    Those are better than using a parabola function (which you are doing).

    However, if you want to find the problem in your script I'd suggest you take a look at this:
    Code (vJASS):
    set dx2 = Reach.x
    set dy2 = Reach.y

    Since I'm pretty sure that they are supposed to be deltas.
    They should look like this:
    Code (vJASS):

    set dx2 = Reach.x - Start.x
    set dy2 = Reach.y - Start.y

    It would be a good idea to store that distance somewhere, so that you can skip that
    SquareRoot(dx2*dx2+dy2*dy2)
    call every iteration ;)
     
  3. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Actually, look what i did:
    Code (Text):

    private static method ParabolaZ takes real h, real d, real x returns real
                return (4 * h / d) * (d - x) * (x / d)
            endmethod

           
            private method CalculateArc takes nothing returns nothing
                local real h = ArcCurve
                local real d = DistanceBetweenVectors(Start, Reach)
                local real x = DistanceBetweenVectors(Start, vector.create(Object.x, Object.y, 0))
                call SetUnitFlyHeight(Object.Dragged, ParabolaZ(h, d, x), 0)
            endmethod
     
    As simple as that :D
    Thanks for the help, ill re-read your post, since i just quickly took a look at it :p
     
  4. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Which is ideally the same as what I said at the end :p
    (Using your old parabola function)

    Code (vJASS):

    set dx2 = Reach.x - Start.x
    set dy2 = Reach.y - Start.y
    call SetUnitFlyHeight(Object.Dragged, ParabolaZ(SquareRoot(dx1*dx1+dy1*dy1), SquareRoot(dx2*dx2+dy2*dy2), arc), 0)
     


    You're also leaking vectors like a sifter :p
     
  5. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    wait.. vectors leak? :O
     
  6. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,955
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    There is no such type as a vector in WC3.
     
  7. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
     Vector     //www.wc3c.net/showthread.php?t=87027

    Is a library containing a struct called
    vector
    .

    Each time you allocate a vector you'll have to deallocate it when you're done with it.
    Why? Because you can only have around 8191 allocated vector instances simultaneously.
    So if you never deallocate your vectors, the possibility that you'll reach that number becomes dangerously high.

    Deallocating a vector is easy. Just do as you would with your average struct:
    call myVector.destroy()
    !

    Now take a look at this:
    local real x = DistanceBetweenVectors(Start, vector.create(Object.x, Object.y, 0))
    . You're allocating a vector instance, but never deallocating it.
    Thus, each time your system calls the
    private method CalculateArc takes nothing returns nothing
    function, you'll 'leak' one vector.
    If that function is called 32x a second; you'll 'leak' 32 * t vectors every second.
    (Your instance counter is declared as t)
     
  8. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Okay, fixed it, i made every single vector i found (using Search option of Newgen),
    as a local variable, then wrote localVariableName.destroy()
    and it should be done..
    about another thing, what's wrong with this calculation?
    Code (vJASS):

    private static method GetZFactor takes real NewX, real NewY, real OldX, real OldY returns real
                return GetCoordinateZ(NewX, NewY) - GetCoordinateZ(OldX, OldY)
            endmethod
       
            private method CalculateTerrain takes nothing returns nothing
                local real Distance = 50
                local real TH1 = GetCoordinateZ(Object.x, Object.y) + GetUnitFlyHeight(Object.Dragged)
                local real FZ = 0
                if TH1 > Reach.z then
                    //Current Loc is higher then the second loc.
                    set FZ = GetZFactor(Reach.x, Reach.y, Object.x, Object.y)
                    call SetUnitFlyHeight(Object.Dragged, GetUnitFlyHeight(Object.Dragged) - FZ, 0)
                elseif Reach.z > TH1 then
                    //Second Loc is higher then the Current loc.
                    call destroy()
                endif
            endmethod
     


    it works, but not correctly,
    it doesnt keep same height all the time, it just makes a random thing,
    and another math problem:
    Code (vJASS):

    set b = GetUnitFlyHeight(t[i].Dragged) - GetUnitFlyHeight(u) >= 0 and   /*
                                    */
         GetUnitFlyHeight(t[i].Dragged) - GetUnitFlyHeight(u) <= 50
     


    again, doesnt work too well, if i hit unit on exact spot, it wont do anything, but a bit to any of its sides, will hit it perfectly, any idea what could cause it?

    Thanks in advance.
     
  9. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Alright so the first problem is that you want the missile to have a consistent height?

    Then you'll have to do this sort of calculation:
    Code (vJASS):

    // when you create your object
    vector pos = vector.create(GetUnitX(myUnit), GetUnitY(myUnit), 0);
    MoveLocation(someLoc, pos.x, pos.y);
    pos.z = GetLocationZ(someLoc) + startingHeight;
    ..
    ...
    // when you update the z height
    MoveLocation(someLoc, pos.x, pos.y);
    pos.z = pos.z + (pos.z - JumpParabola(...) - GetLocationZ(someLoc));
    pos.x = pos.x + vel.x;
    pos.y = pos.y + vel.y;
    MoveLocation(someLoc, pos.x, pos.y);
    SetUnitFlyHeight(pos.z - GetLocationZ(someLoc), Object.Dragged, 0);
    ..

    No promises on that one, since I'm only used to dealing with velocities instead of parabolas :p

    An alternate version would be:
    Code (vJASS):

    SetUnitX(unit, GetUnitX(unit) + vel.x);
    SetUnitY(unit, GetUnitY(unit) + vel.y);
    MoveLocation(loc, GetUnitX(unit), GetUnitY(unit));
    SetUnitFlyHeight(unit, JumpParabola(...) - GetLocationZ(loc), 0);
    ..
     


    On the second problem, could you post the entire collision code?
    What you posted seems to be correct, it will only work if the object is above or on the same height, however. You should replace 0 with -50.
     
  10. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Well, my code spreads over 2 libraries,
    1 is RealityMissle, another is RealityKnockback, so right now i figured something odd,
    since i added the FactorZ part, it showed some odd stuff, like Arc doesnt work correctly, etc, and this is the entire code,
    and for info, this are the values knockback system uses:
    Code (vJASS):

    public static thistype count = 0
            public unit Dragger
            public unit Dragged
            public real Velocity
            public real Distance
            public real Damage
            public real Angle
            public boolean DestroyTrees
            public boolean CrushOnUnits
            public boolean behingDragged
            public real x
            public real y
            public boolean isMissle
            public boolean ignoreArmor
            public boolean ignoreTerrain
     


    heres the missle code:

    Code (vJASS):

    library RealityMissle initializer onInit requires /*
    */
    Vector     /* [url]www.wc3c.net/showthread.php?t=87027[/url]
    */
    ArmorUtils /* [url]www.wc3c.net/showthread.php?t=105849[/url]
    */
    GetNearest /* [url]www.wc3c.net/showthread.php?t=108907[/url]
    */
    RealityKnockback /* Part of this system.
    */

       
        struct Missle
            public static thistype      t                                       = 0
            public static thistype      t2                                      = 0
            public static location      D_Loc                                   = Location(0, 0)
            public static real          TimerInterval                           = 0.032
            public static integer       Dummy_Unit                              = 'e000'
            public static integer       flight_ability                          = 'Amrf'
            //---------------------------------------------------------------------------------
            public KbTarget             Object                                  = 0
            public unit                 Target                                  = null
            public player               Owner                                   = null
            public vector               Start                                   = 0
            public vector               Reach                                   = 0
            public real                 ArcCurve                                = 0
            public boolean              ignoreArmor                             = false
            public effect               Model
           
           
            public static method create takes player owner, real x, real y, string SFX, string attachPoint returns thistype
                local unit missle = null
                set t = t + 1
                set t2 = t2 + 1
                    call MoveLocation(D_Loc, x, y)
                    set missle                  = CreateUnit(owner, Dummy_Unit, x, y, 0)
                    set t.Object                = KbTarget.create(null, missle, 0, 0, 0, 0, true)
                    set t.Start                 = vector.create(x, y, GetLocationZ(D_Loc))
                    set t.Owner                 = owner
                    set t.Model                 = AddSpecialEffectTarget(SFX, t.Object.Dragged, attachPoint)
                    set t.ArcCurve              = 0
                    set t.ignoreArmor           = false
                    call t.allowHeight()
                return t
            endmethod
           
            public method Initiate takes nothing returns nothing
                local vector v = vector.create(Object.x, Object.y, 0)
                set Object.Distance = DistanceBetweenVectors(v, Reach)
                set Object.ignoreArmor = ignoreArmor
                call KnockbackUnit(Object)
                call v.destroy()
            endmethod
           
            private static method DistanceBetweenVectors takes vector a, vector b returns real
                local real dx = b.x - a.x
                local real dy = b.y - a.y
                return SquareRoot(dx * dx + dy * dy)
            endmethod
           
            private static method AngleBetweenVectors takes vector a, vector b returns real
                return bj_RADTODEG * Atan2(b.y - a.y, b.x - a.x)
            endmethod
           
            private static method ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
                local real A = (2*(y0+y1)-4*h)/(d*d)
                local real B = (y1-y0-A*d*d)/d
                return A*x*x + B*x + y0
            endmethod
           
            private static method ParabolaZ takes real h, real d, real x returns real
                return (4 * h / d) * (d - x) * (x / d)
            endmethod

            private method CalculateArc takes nothing returns nothing
                local vector v = vector.create(Object.x, Object.y, 0)
                local real h = ArcCurve
                local real d = DistanceBetweenVectors(Start, Reach)
                local real x = DistanceBetweenVectors(Start, v)
               
                call SetUnitFlyHeight(Object.Dragged, ParabolaZ(h, d, x), 0)
                call v.destroy()
            endmethod
           
            private static method GetZFactor takes real NewX, real NewY, real OldX, real OldY returns real
                return GetCoordinateZ(NewX, NewY) - GetCoordinateZ(OldX, OldY)
            endmethod
       
            private method CalculateTerrain takes nothing returns nothing
                local real Distance = 50
                local real z1 = GetCoordinateZ(Object.x, Object.y) + GetUnitFlyHeight(Object.Dragged)
                local real x = Object.x + Distance * Cos (Object.Angle)
                local real y = Object.y + Distance * Sin (Object.Angle)
                local real z2 = GetCoordinateZ(x, y)
                local real FZ = 0
                if z1 > z2 then
                    //Current Loc is higher then the second loc.
                    set FZ = GetZFactor(x, y, Object.x, Object.y)
                    call SetUnitFlyHeight(Object.Dragged, GetUnitFlyHeight(Object.Dragged) - FZ, 0)
                elseif z2 > z1 then
                    //Second Loc is higher then the Current loc.
                    call destroy()
                endif
            endmethod
           
            private static method GetCoordinateZ takes real x, real y returns real
                // finds x/y location Z using a re-used dummy.
                call MoveLocation(D_Loc, x, y)
                return GetLocationZ(D_Loc)
            endmethod
           
            public method allowHeight takes nothing returns nothing
                call UnitAddAbility(Object.Dragged, flight_ability)
                call UnitRemoveAbility(Object.Dragged, flight_ability)
            endmethod
           
            public method destroy takes nothing returns nothing
                call SetUnitExploded(Object.Dragged, true)
                set Target = null
                set Owner = null
                call Start.destroy()
                call Reach.destroy()
                call DestroyEffect(Model)
                set Model = null
                set ignoreArmor = false
               
                set t2 = t2 - 1
            endmethod
           
            public method TimeToDistance takes real time returns real
                return time * (Object.Velocity / TimerInterval)
            endmethod
           
            public method SetDestinationTime takes real time returns nothing
                local real a = TimeToDistance(time)
                call SetDestination(a)
            endmethod
           
            public method SetDestinationXY takes real x, real y returns nothing
                set Reach = vector.create(x, y, GetCoordinateZ(x, y))
                set Object.Angle = AngleBetweenVectors(Start, Reach) * bj_DEGTORAD
            endmethod
           
            public method SetDestination takes real distance returns nothing
                local real an = GetUnitFacing(Object.Dragged) * bj_DEGTORAD
                local real x = Object.x + distance * Cos (an)
                local real y = Object.y + distance * Sin (an)
                set Reach = vector.create(x, y, GetCoordinateZ(x, y))
                set Object.Angle = an
            endmethod
           
            public method Homing takes unit target returns nothing
                set .Target = target
                set Reach = vector.create(GetUnitX(Target), GetUnitY(Target), GetCoordinateZ(GetUnitX(Target), GetUnitY(Target)))
            endmethod
           
            private method onLoop takes nothing returns nothing
                local vector v
                //Arc methods here
                if ArcCurve > 0 then
                    call CalculateArc()
                endif
                //Homing methods here
                if not (Target == null) then
                    set v = vector.create(Object.x, Object.y, 0)
                    set Reach.x = GetUnitX(Target)
                    set Reach.y = GetUnitY(Target)
                    set Reach.z = GetCoordinateZ(GetUnitX(Target), GetUnitY(Target))
                    set Object.Angle = AngleBetweenVectors(v, Reach) * bj_DEGTORAD
                    call v.destroy()
                endif
                //Terrain Collision Check
                if Object.ignoreTerrain == false and ArcCurve == 0 then
                    call CalculateTerrain()
                endif
               
                //Function Interfaces here
               
                //Ending missle when it reaches its distance
                if Object.behingDragged == false then
                    call destroy()
                endif
            endmethod
        endstruct
       
        private function loopHandler takes nothing returns nothing
            local integer i = 0
            local integer end = s__Missle_t
           
            if end > 0 then
                loop
                set i = i + 1
                    call s__Missle_onLoop(i)
                exitwhen i == end
                endloop
            endif
        endfunction
       
        private function onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), s__Missle_TimerInterval, true, function loopHandler)
        endfunction
       
    endlibrary
     


    the dummy spell code:

    Code (vJASS):

    library exampleCode initializer onInit requires RealityMissle, RealityKnockback
       
        private function actions takes nothing returns nothing
            local unit caster = GetTriggerUnit()
            local real x = GetLocationX(GetSpellTargetLoc())
            local real y = GetLocationY(GetSpellTargetLoc())
            local Missle m = Missle.create(GetOwningPlayer(caster), GetUnitX(caster), GetUnitY(caster), "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl", "origins")
           
            call m.SetDestinationXY(x, y)
            set m.Object.Damage = 100
            set m.Object.Velocity = 35
            set m.Object.DestroyTrees = true
            set m.Object.CrushOnUnits = true
            set m.ArcCurve = 500
            call m.Initiate()
           
            set caster = null
        endfunction
       
        private function conditions takes nothing returns boolean
            return GetSpellAbilityId() == 'A000'
        endfunction
       
        private function onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
           
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
           
            call TriggerAddAction( t, function actions)
           
            call FogEnableOff()
            call FogMaskEnableOff()
        endfunction
       
    endlibrary
     


    thanks in advance.

    btw, the code i posted above about FactorZ used Reach.z, Reach.x, Reach.y, then i figured it should have a specific distance, i changed it, distance was the real, i forgot thats what i intended to do, since i went to watch a movie..
    and it still doesnt work correctly.
     
  11. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Ah, I see.
    Okay, this is going to be really hard.

    For the collision detection to work correctly you'll need to know the current x/y/z, and the next x/y/z.
    You only know the current x/y/z, since the actual x/y movement is done in another library.

    A really inefficient method could be something like this:
    Code (vJASS):

            private method CalculateArc takes nothing returns nothing
                local vector v = vector.create(Object.x, Object.y, 0)
                local real h = ArcCurve
                local real d = DistanceBetweenVectors(Start, Reach)
                local real x = DistanceBetweenVectors(Start, v)
                local real z = ParabolaZ(h, d, x)
               
                local real nx = v.x + Object.Velocity * Cos(Object.Angle)
                local real ny = v.y + Object.Velocity * Sin(Object.Angle)
                local real dz
               
                call MoveLocation(loc, v.x, v.y)
                set dz = GetLocationZ(loc)
                set z = z + dz
                call MoveLocation(loc, nx, ny)
                set dz = dz - GetLocationZ(loc)
               
                if (dz*dz >= 32*32) then // square delta, square height threshold
                    // missile has/is going to hit a cliff
                else
                    // do some proper height modifying instead of this probably incorrect method
                    call SetUnitFlyHeight(Object.Dragged, z - GetLocationZ(loc) , 0)
                    // continue as normal
                endif
               


                call v.destroy()
            endmethod
     
     
  12. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Okay, your code works, but heres the problem,
    it only works 1 time:O
    the arc stops after 1 time of working, for example, i shoot a missle,
    it has a correct arc, etc.
    i shoot it again, no arc at all, i restart, again, and so on..
    Any idea what could cause this? i've changed the code a bit, here:
    Code (vJASS):

    library RealityMissle initializer onInit requires /*
    */
    Vector     /* [url]www.wc3c.net/showthread.php?t=87027[/url]
    */
    ArmorUtils /* [url]www.wc3c.net/showthread.php?t=105849[/url]
    */
    GetNearest /* [url]www.wc3c.net/showthread.php?t=108907[/url]
    */
    RealityKnockback /* Part of this system.
    */

       
        struct Missle
            public static thistype      t                                       = 0
            public static thistype      t2                                      = 0
            public static location      D_Loc                                   = Location(0, 0)
            public static real          TimerInterval                           = 0.032
            public static integer       Dummy_Unit                              = 'e000'
            public static integer       flight_ability                          = 'Amrf'
            //---------------------------------------------------------------------------------
            public KbTarget             Object                                  = 0
            public unit                 Target                                  = null
            public player               Owner                                   = null
            public vector               Start                                   = 0
            public vector               Reach                                   = 0
            public real                 ArcCurve                                = 0
            public boolean              ignoreArmor                             = false
            public effect               Model
           
           
            public static method create takes player owner, real x, real y, string SFX, string attachPoint returns thistype
                local unit missle = null
                set t = t + 1
                set t2 = t2 + 1
                    call MoveLocation(D_Loc, x, y)
                    set missle                  = CreateUnit(owner, Dummy_Unit, x, y, 0)
                    set t.Object                = KbTarget.create(null, missle, 0, 0, 0, true)
                    set t.Start                 = vector.create(x, y, GetLocationZ(D_Loc))
                    set t.Owner                 = owner
                    set t.Model                 = AddSpecialEffectTarget(SFX, t.Object.Dragged, attachPoint)
                    set t.ArcCurve              = 0
                    set t.ignoreArmor           = false
                    call t.allowHeight(missle)
                    set missle                  = null
                return t
            endmethod
           
            public method Initiate takes nothing returns nothing
                local vector v = vector.create(Object.x, Object.y, 0)
                set Object.Distance = DistanceBetweenVectors(v, Reach)
                set Object.ignoreArmor = ignoreArmor
                call KnockbackUnit(Object)
                call v.destroy()
            endmethod
           
            private static method DistanceBetweenVectors takes vector a, vector b returns real
                local real dx = b.x - a.x
                local real dy = b.y - a.y
                return SquareRoot(dx * dx + dy * dy)
            endmethod
           
            private static method AngleBetweenVectors takes vector a, vector b returns real
                return bj_RADTODEG * Atan2(b.y - a.y, b.x - a.x)
            endmethod
           
            private static method ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
                local real A = (2*(y0+y1)-4*h)/(d*d)
                local real B = (y1-y0-A*d*d)/d
                return A*x*x + B*x + y0
            endmethod
           
            private static method ParabolaZ takes real h, real d, real x returns real
                return (4 * h / d) * (d - x) * (x / d)
            endmethod
           
            private method TerrainAndArcCalculation takes nothing returns nothing
                local vector v = vector.create(Object.x, Object.y, 0)
                local real h = ArcCurve
                local real d = DistanceBetweenVectors(Start, Reach)
                local real x = DistanceBetweenVectors(Start, v)
                local real z = ParabolaZ(h, d, x)
               
                local real nx = v.x + Object.Velocity * Cos(Object.Angle)
                local real ny = v.y + Object.Velocity * Sin(Object.Angle)
                local real dz = 0
               
                set dz = GetCoordinateZ(v.x, v.y)
                set z = z + dz
                set dz = dz - GetCoordinateZ(nx, ny)
               
                if (dz*dz >= 1024) then // square delta, square height threshold
                    // missile has/is going to hit a cliff
                    call destroy()
                else
                    // do some proper height modifying instead of this probably incorrect method
                    call SetUnitFlyHeight(Object.Dragged, z - GetCoordinateZ(nx, ny) , 0)
                    // continue as normal
                endif
               
                call v.destroy()
            endmethod
           
            private static method GetCoordinateZ takes real x, real y returns real
                // finds x/y location Z using a re-used dummy.
                call MoveLocation(D_Loc, x, y)
                return GetLocationZ(D_Loc)
            endmethod
           
            private static method allowHeight takes unit u returns nothing
                call UnitAddAbility(u, flight_ability)
                call UnitRemoveAbility(u, flight_ability)
            endmethod
           
            public method destroy takes nothing returns nothing
                call SetUnitExploded(Object.Dragged, true)
                set Target = null
                set Owner = null
                call Object.destroy()
                call Start.destroy()
                call Reach.destroy()
                call DestroyEffect(Model)
               
                set t2 = t2 - 1
            endmethod
           
            public method TimeToDistance takes real time returns real
                return time * (Object.Velocity / TimerInterval)
            endmethod
           
            public method SetDestinationTime takes real time returns nothing
                local real a = TimeToDistance(time)
                call SetDestination(a)
            endmethod
           
            public method SetDestinationXY takes real x, real y returns nothing
                set Reach = vector.create(x, y, GetCoordinateZ(x, y))
                set Object.Angle = AngleBetweenVectors(Start, Reach) * bj_DEGTORAD
            endmethod
           
            public method SetDestination takes real distance returns nothing
                local real an = GetUnitFacing(Object.Dragged) * bj_DEGTORAD
                local real x = Object.x + distance * Cos (an)
                local real y = Object.y + distance * Sin (an)
                set Reach = vector.create(x, y, GetCoordinateZ(x, y))
                set Object.Angle = an
            endmethod
           
            public method Homing takes unit target returns nothing
                set .Target = target
                set Reach = vector.create(GetUnitX(Target), GetUnitY(Target), GetCoordinateZ(GetUnitX(Target), GetUnitY(Target)))
            endmethod
           
            private method onLoop takes nothing returns nothing
                local vector v = 0
                //Arc and Terrain methods here
                call TerrainAndArcCalculation()
               
                //Homing methods here
                if not (Target == null) then
                    set v = vector.create(Object.x, Object.y, 0)
                    set Reach.x = GetUnitX(Target)
                    set Reach.y = GetUnitY(Target)
                    set Reach.z = GetCoordinateZ(GetUnitX(Target), GetUnitY(Target))
                    set Object.Angle = AngleBetweenVectors(v, Reach) * bj_DEGTORAD
                    call v.destroy()
                endif
               
                //Function Interfaces here
               
                //Ending missle when it reaches its distance
                if not Object.behingDragged then
                    call destroy()
                endif
            endmethod
        endstruct
       
        private function loopHandler takes nothing returns nothing
            local integer i = 0
            local integer end = s__Missle_t
           
            if end > 0 then
                loop
                set i = i + 1
                    if s__Missle_Object[i].behingDragged == true then
                        call BJDebugMsg(R2S(s__Missle_ArcCurve[i]))
                    endif
                    call s__Missle_onLoop(i)
                exitwhen i == end
                endloop
            endif
        endfunction
       
        private function onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), s__Missle_TimerInterval, true, function loopHandler)
        endfunction
       
    endlibrary
     


    thanks in advance.

    edit: the BJDEBUGMSG showed me 500 all the time, so the value doesnt reset to 0.
     
  13. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Alright, first you should update your loopHandler and integrate it in your struct.
    Something like this:
    Code (vJASS):

    struct Missile
    ...
    ...
        private static method loopHandler takes nothing returns nothing
            ...
        endmethod
       
        static method onInit takes nothing returns nothing
            call TimerStart(...)
        endmethod
    endstruct


    Then, as I'm not quite sure how your stack works, you should update it to something like this:
    Code (vJASS):

    struct Missile
        static integer    counter = 0
        static Missile array missiles

        integer    index

        static method create takes .... returns Missile
            ... some code ..

            set missiles[counter] = this    
            set index = counter
            set counter = counter + 1
           
            return this
        endmethod

        ...
        method destroy takes nothing returns nothing
            set counter = counter - 1
            set missiles[counter].index = index // update the last missile's index to the new one
            set missiles[index] = missiles[counter] // write last missile to current index
        endmethod
     


    Try doing that and post your results!
     
  14. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    i didnt quite get the index part :O
    Code (vJASS):

    set index = counter
    set missiles[index] = missiles[counter
     
     
  15. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Alright

    In the first example when we do this:
    Code (vJASS):

           //
            set missiles[counter] = this    // assign the missile array index @ counter to this Missile instance.
                                            // I.e if we have 3 missiles flying, then we've assigned indexes 0, 1 and 2.
                                            // Counter is now 3. So now we add the 4th element (0,1,2,3=4) to this Missile instance.

            set index = counter             // Set our missile instance's index to 3, since that's its position in the array.

            set counter = counter + 1       // And increment counter by 1
     


    Next when we destroy the missile instance we want our stack of missiles to update itself.

    Code (vJASS):

            //
            set counter = counter - 1 // we are removing one instance, reduce the counter by 1
            set missiles[counter].index = index // grab the last added missile and set its position in the array to the one we are removing
            set missiles[index] = missiles[counter] // do the real switch here
     


    Think of it like this:
    [0][1][2] are running missile indexes in our array.
    counter = 4.

    Now we add another missile, our array looks like this now:
    [0][1][2][3]
    counter = 5.

    Let's say missile no. 2 ([1] reaches its destination and is removed.
    With no stack updating our stack would look like this:
    [0][1-inactive][2][3]
    counter = 5.

    So every iteration, we are wasting one spot because our stack never lowers.

    If we had above stack updating our stack would look like this when the 2nd element is removed:
    [0][3][2]
    counter = 4.

    Since the [1] takes the last added missile ([3]) and sets it in [1]'s array position.
     
  16. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    how about this:
    when creating missle, loop thru all missles, and check if
    Object.behingDragged == false, if thats correct,
    just replace it with the new missle, instead of the odd way you did :O
     
  17. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    That should work too.
    But you must use an array with a counter in either case, so it's not much of a difference.

    And it's more efficient to do it the 'odd' way ;)

    You could actually add that into your loopHandler, so it checks if a missile is flagged for removal (behindDragged=false), and do the necessary updating.
    That should be way more efficient than what you posted, since you would do a very large loop every time you're creating a missile.
     
  18. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Okay.. indexing or not, the arc still isnt fixed :O
    It allows indexing for like 1 second since the moment the code starts xD
    if you use spell twice at same time, it works, if you use it a second later even, it will not do arc.
    any idea? :/
    and im starting to think of using Stack, or something.. for indexing/making looping faster/easier.
     
  19. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    The reason your arc isn't working is probably due to the indexing ;)
    Fix that, and it'll get a lot easier to find whatever can be causing that arc bug (if it isn't indexing)
     
  20. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Okay i made some modifications to the code, but anyways, i think ill learn from this tutorial about indexing, its what you said, just in a more learn-able way :p

    http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/vjass-indexer-tutorial-structs-114223/

    I'll do that to my code, then tell you.

    Edit: Great!
    i've finished the new code o_O, which took me quite a bit,
    i remade the entire code with the indexing part,
    and now arc works flawlessly, and so does homing, ill do terrain check soon :p and now ill add bounce + deflect..
    Thanks for the help, but is there a better way to check terrain collision? since i cant really find a good way ;p
     
    Last edited: Apr 13, 2011