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. The reforging of the races is complete. Come see the 14th Techtree Contest Results.
    Dismiss Notice
  4. It's time to choose your horse in the race - the 32nd Modeling Contest Poll is up!
    Dismiss Notice
  5. 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. Tukki

    Tukki

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

    Isn't the terrain collision accurate enough? Or is it malfunctioning?
    I'm asking because it's a pretty efficient way of checking collision.

    I guess you could add some 'radius' member and use that instead of those 32's if you're after accuracy, since that wouldn't affect performance much.
     
  2. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    hey dude, changed velocity into a vector, and im in a problem.
    look at this:
    Code (vJASS):

    if t.Distance > 0 and GetWidgetLife(t.Object.Object) > 0.405 and t.Object.hittedUnit == false then
                    if t.Object.IsUsed then
                        set t.Distance = t.Distance - t.Object.Velocity.x
     


    and i dont want it to be Velocity.x, because Velocity.y can be diffrent :O
    how do i fix that?
     
  3. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Ow, the best way to solve that is by storing the velocity somewhere.

    Otherwise, to calculate the 'real' velocity you'll have to do this:
    real vel = SquareRoot(Velocity.x*Velocity.x + Velocity.y*Velocity.y)

    If I remember correctly. (But that seems like the logical solution)
     
  4. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    actually..
    Code (vJASS):

    //Part of the vector library
    method getLength takes nothing returns real
          return SquareRoot(.x*.x + .y*.y + .z*.z)
    endmethod
     


    but imagine x = 50, y = 50,
    50 * 50 = 2500, 2500 + 2500 + 0 = 5000
    Squareroot(5000) = 70.711.... (Didn't have a calculator so i went to 70 immideatly, and then .7, and started testing XD)
    so 70.711 is above 50, so right now it wont get to the required XY assigned by the player.. how can i fix that? :D
     
  5. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Well, you aren't using z velocities :p

    Okay; velocities are like this:
    xVel = baseVelocity * Cos(alpha) * updateFrequency

    yVel = baseVelocity * Sin(alpha) * updateFrequency


    So, your base velocity becomes:
    vel = SquareRoot(xVel*xVel + yVel*yVel) / updateFrequency


    No lie.

    Let's say that your base velocity is 300, updateFrequency 0.03125 and the angle is 90 (PI/2 in radians).
    xVel = 300 * Cos(bj_PI/2) * 0.03125
    Cos(90) is 0, which means that xVel = 0.
    yVel = 300 * Sin(bj_PI/2) * 0.03125
    Sin(90) is 1, which means that yVel = 300*0.03125 (~9.4)

    vel = SquareRoot(0*0 + 9.4*9.4) / 0.03125
    which is the same as:
    vel = 9.4/0.03125
    vel ~300.

    Works, right? ;)
     
  6. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    well.. it works, BUT i do use VelocityZ now ^^
    Code (vJASS):

    local real velX = .BaseVelocity * Cos(.Angle * bj_DEGTORAD) * RealityMath_TimerInterval
                local real velY = .BaseVelocity * Sin(.Angle * bj_DEGTORAD) * RealityMath_TimerInterval
                set currentIndex = this
                //Updating location of the missle and the vector.
                set Position.x = Position.x + Velocity.x * Cos (Angle * bj_DEGTORAD)
                set Position.y = Position.y + Velocity.y * Sin (Angle * bj_DEGTORAD)
                set Position.z = Position.z + Velocity.z * Sin (Angle * bj_DEGTORAD)
                call SetUnitX(Object, Position.x)
                call SetUnitY(Object, Position.y)
                call SetUnitFlyHeight(Object, Position.z, 0)
                call SetUnitFacing(Object, Angle)
               
                set UsedVelocity = SquareRoot(velX * velX + velY * velY) / RealityMath_TimerInterval
     


    so im kinda stuck, since i want the distance to also work on Z, for example on arrows that fall down.. or rain missles, etc.
     
  7. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    That's isn't really how you use velocities.

    This is what you should aim at:
    Code (vJASS):

    vector acceleration
    vector velocity
    vector position

               ....
                static method engine ..
                     integer a=0
                     thistype this
                     real z

                     loop
                        exitwhen a==instanceCount
                        this = instanceArray[a]

                        velocity.x = velocity.x + acceleration.x
                        velocity.y = velocity.y + acceleration.y
                        velocity.z = velocity.z + acceleration.z

                        position.x = position.x + velocity.x
                        position.y = position.y + velocity.y
                        position.z = position.z + velocity.z

                        SetUnitX(object, position.x)
                        SetUnitY(object, position.y)
                        SetUnitFlyHeight(object, position.z - GetPointZ(position.x, position.y), 0)
                        set z = velocity.z
                        set velocity.z = 0
                        SetUnitFacing(object, ArcCos(velocity.x / velocity.getLength() / timerFrequency)*bj_RADTODEG) // <-- really inefficient
                        set velocity.z = z
                        distanceDone = distanceDone + velocity.getLength() / timerFrequency // <-- also really inefficient

                        ...
     


    This is still freehand, but it should give you an idea how to use them vectors ;)

    This is a really guessed function, don't trust it.
    Code (vJASS):

    method firePos takes real x, real y, real z, real speed returns nothing
       speed = speed * timerFrequency
       velocity.x = speed * Cos(alpha)
       velocity.y = speed * Sin(alpha)
       velocity.z = speed * Cos(Atan2(SquareRoot((x-position.x) * (x-position.x) + (y-position.y) * (y-position.y)), (z-position.z)))
    endmethod
     
     
  8. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    You know.. if you'd use that code in a newgen, it wont compile, and you'll have like 50 syntax errors? XD you forgot allmost all the set's, and call's.
    you just wrote the function..

    Anyways, what is acceleration, the speed?
     
  9. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Hehe, if I provide compilable code, all you've to do is to copy it, right? ;)

    Acceleration is acceleration :p
    It's how much your velocity increases every iteration.

    An example would be:
    Code (vJASS):

    method launch(vector end, real time){
            acceleration.z = GRAVITY * 0.03125 * 0.03125 // acceleration is measured in m/s^2

            velocity.x = (end.x - position.x)/(time*32);
            velocity.y = (end.y - position.y)/(time*32);
            MoveLocation(loc, end.x, end.y);
            velocity.z =  (end.z + GetLocationZ(loc) - position.z)/(time*32) - 0.5*acceleration.z*32*time
    }
     
     
  10. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    I actually dont get what you wrote in launch, why would velocity have a base value? this works perfect for me, and i even used Acceleration.z and it worked aswell.
    Code (vJASS):

                set Velocity.x = Velocity.x + Acceleration.x
                set Velocity.y = Velocity.y + Acceleration.y
                set Velocity.z = Velocity.z + Acceleration.z
               
                set Position.x = Position.x + Velocity.x * Cos(Angle * bj_DEGTORAD)
                set Position.y = Position.y + Velocity.y * Sin(Angle * bj_DEGTORAD)
                set Position.z = Position.z + Velocity.z
               
                call SetUnitX(Object, Position.x)
                call SetUnitY(Object, Position.y)
                call SetUnitFlyHeight(Object, Position.z - GetCoordinateZ(Position.x, Position.y), 0)
                call SetUnitFacing(Object, Angle)
     


    So thanks, and btw, mind helping me understand the physics of bounce? :O

    edit: i remade the code, because i somehow ruined old code, too much mess, so now i remade it, all works, replaced the knockback and missle with:
    * RealityMath
    * RealityObject
    * RealityMissle
    Object handles update, and everything, missle just provides the Object information about the missle, and calls the update methods,
    and handles everything outside of the update limits about missles.

    So now i need this:
    i've made direction instead of angle, and direction is a vector,
    so this is the problem:
    Code (vJASS):

    public method update takes nothing returns nothing
                local real angle = 0
                local vector v
                if DistanceBetweenVectors(Position, Reach) > 0 then
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach)
                        set Direction.x = angle
                        set Direction.y = angle
                        call v.destroy()
                    endif
                    if ConstantSpeed == false then
                        set Velocity.x = Velocity.x + Acceleration.x
                        set Velocity.y = Velocity.y + Acceleration.y
                        set Velocity.z = Velocity.z + Acceleration.z
                    endif
                   
                    set Position.x = Position.x + Velocity.x * Cos(Direction.x * bj_DEGTORAD)
                    set Position.y = Position.y + Velocity.y * Sin(Direction.y * bj_DEGTORAD)
                    set Position.z = Position.z + Velocity.z
                   
                    call MoveUnitToVector(Object, Position)
                endif
            endmethod
     


    i have no clue what to do with Direction.z, since i want it to work ;p
    and heres MoveUnitToVector:
    Code (vJASS):

    function MoveUnitToVector takes unit u, vector v returns nothing
            call SetUnitX(u, v.x)
            call SetUnitY(u, v.y)
            call SetUnitFlyHeight(u, v.z, 0)
        endfunction
     


    thanks in advance.
     
    Last edited: Apr 15, 2011
  11. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Look, the way you are treating your vector velocity is the same way as you treat any variable...
    Velocity is a vector; velocity.x is the velocity on the x-scale, velocity.y is the velocity on the y-scale and velocity.z is on the z-scale.

    They are NOT identical, although x& y share the same base speed and angle.

    Your code can be rewritten like this:
    Code (vJASS):

    set Position.x = Position.x + Velocity.y * Cos(Angle * bj_DEGTORAD) // <-- since you're treating x/y/z as if they were the same value
    set Position.y = Position.x + Velocity.x * Sin(Angle * bj_DEGTORAD) // <-- same as above
     


    Because your
    Velocity.x
    is equal to your
    Velocity.y
    .

    Now, this is how it should be done:
    Code (vJASS):

    set Position.x = Position.x + Velocity.x // Velocity.x != Velocity.y
    set Position.y = Position.y + Velocity.y // Okay they could be if baseSpeed = 0
     


    You ARE using vectors, not scalars.
    Vectors have a length and direction, where scalars only have a length.

    So when you are setting up the movement you assign the velocities accordingly:
    Code (vJASS):

    set Velocity.x = baseVelocity * Cos(alpha) * updateFrequency // this is how much your object moves in the x-scale each iteration
    set Velocity.y = baseVelocity * Sin(alpha) * updateFrequency // this is how much your object moves in the y-scale each iteration
     


    If you skip the part with Cos/Sin (alpha) you're going to end up with baseVelocity*updateFrequency on both x & y, which means that your vector isn't a vector; it's a scalar.

    If you don't understand this, it's not worth starting with bouncing :p
     
  12. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Okay, lets leave bounce, how should the Velocity.x and Velocity.y look in update method?
    cuz im kind of failing that..

    edit: forget what i wrote above,
    im skipping bounce for now, i wanna do velocity well first.
    heres my update code:
    Code (vJASS):

            public method update takes real interval returns nothing
                local real angle = 0
                local vector v = 0
               
                if distance > 0 and isUsed and not Ended then
                    set distance = distance - Velocity.getLength()
                   
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach) * bj_RADTODEG
                        set Direction.x = angle
                        set Direction.y = angle
                        call v.destroy()
                    endif
                   
                    if ConstantSpeed == false then
                        set Velocity.x = Velocity.x + Acceleration.x * Cos(Direction.x * bj_DEGTORAD) * interval
                        set Velocity.y = Velocity.y + Acceleration.y * Sin(Direction.y * bj_DEGTORAD) * interval
                        set Velocity.z = Velocity.z + Acceleration.z * interval
                    endif
                   
                    set Position.x = Position.x + Velocity.x
                    set Position.y = Position.y + Velocity.y
                    set Position.z = Position.z + Velocity.z
                   
                    call MoveUnitToVector(Object, Position)
                elseif distance <= 0 then
                    set Ended = true
                    set isUsed = false
                endif
            endmethod
     


    i've fixed the interval part, it should work now ? xD and btw,
    i understood the idea of interval, its for acceleration per second
    instead of per interval. nice thinking =]
     
    Last edited: Apr 15, 2011
  13. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Okay, good choice!

    Now:

    Vectors are a physical component with a length and a direction.

    So, you never do stuff like this:
    Code (vJASS):

    if ConstantSpeed == false then
                set Velocity.x = Velocity.x + Acceleration.x * Cos(Direction.x * bj_DEGTORAD) * interval
                set Velocity.y = Velocity.y + Acceleration.y * Sin(Direction.y * bj_DEGTORAD) * interval
                set Velocity.z = Velocity.z + Acceleration.z * interval
            endif


    The *Cos/Sin part should always be incorporated into the vector itself.
    I.e
    set Acceleration.x = 3 * Cos(myAngle)
    , where 3 is the acceleration speed, and myAngle is the angle at which that speed is projected.

    I see that you're getting hang of some things, like:
    set distance = distance - Velocity.getLength()

    set angle = vector.getAngle(Position, Reach) * bj_RADTODEG
    you can get rid of that *bj_RADTODEG here, because you aren't going to need degrees in any operations other than facing

    So if you update your code, it'll look something like this:
    Code (vJASS):

    local real speed = Velocity.getLength()

          ...
            set distance = distance - speed
           
            if not (Homing == null) then
                set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                set Reach.x = v.x
                set Reach.y = v.y
                set angle = vector.getAngle(Position, Reach) // no need for the rad->degree convertion
                set Velocity.x = speed * Cos(angle) * interval // here we just update velocity components
                set Velocity.y = speed * Sin(angle) * interval
                set speed = (distance / speed) / interval // reuse 'speed' as time, and translate time into amount of iterations it'll take to complete the trajectory
                set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z)/(speed) - 0.5*Acceleration.z*time // here we are using the fact that in reality, z-acceleration is negative in ballistic-ish trajectories
                call v.destroy()
            endif
           
            // Acceleration components (Acceleration.x/y/z) are 0 if speed is constant, so no need to check that
                set Velocity.x = Velocity.x + Acceleration.x  // Acceleration is a vector, so it got both length and direction: we can remove that *Cos/Sin(..) thingey
                set Velocity.y = Velocity.y + Acceleration.y
                set Velocity.z = Velocity.z + Acceleration.z
            //endif
           
            set Position.x = Position.x + Velocity.x
            set Position.y = Position.y + Velocity.y
            set Position.z = Position.z + Velocity.z
           
            call MoveUnitToVector(Object, Position)
     
     
  14. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    I must understand you.. what do you refer to when you write time? XD
    do you mean UpdateFrequncy? i really dont get it.

    And btw, i tested using your way, like this:
    Code (vJASS):

    public method update takes real interval returns nothing
                local unit n = null
                local destructable t = null
                local real angle = 0
                local real speed = Velocity.getLength()
                local vector v = 0
                set currentIndex = this
               
                if distance > 0 and isUsed and not Ended then
                    set distance = distance - speed
                   
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach)
                        set Velocity.x = speed * Cos(angle) * interval
                        set Velocity.y = speed * Sin(angle) * interval
                        set speed = (distance / speed) / interval
                        set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z) / (speed) - 0.5 * Acceleration.z * interval
                        call v.destroy()
                       
                        call SetUnitFacing(Object, angle)
                       
                        if not (GetWidgetLife(Homing) > 0.405) then
                            set Homing = null
                        endif
                    endif
                   
                    /*
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach) // no need for the rad->degree convertion
                        set Velocity.x = speed * Cos(angle) * interval // here we just update velocity components
                        set Velocity.y = speed * Sin(angle) * interval
                        set speed = (distance / speed) / interval // reuse 'speed' as time, and translate time into amount of iterations it'll take to complete the trajectory
                        set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z)/(speed) - 0.5*Acceleration.z*time // here we are using the fact that in reality, z-acceleration is negative in ballistic-ish trajectories
                        call v.destroy()
                    endif
                    */

                   
                    if ConstantSpeed == false then
                        set Velocity.x = Velocity.x + Acceleration.x
                        set Velocity.y = Velocity.y + Acceleration.y
                        set Velocity.z = Velocity.z + Acceleration.z
                    else
                        set Velocity.x = Acceleration.x
                        set Velocity.y = Acceleration.y
                        set Velocity.z = Acceleration.z
                    endif
                   
                    set Position.x = Position.x + Velocity.x
                    set Position.y = Position.y + Velocity.y
                    set Position.z = Position.z + Velocity.z
                   
                    call SetUnitX(Object, Position.x)
                    call SetUnitY(Object, Position.y)
                    if ArcHeight > 0 then
                        call SetUnitFlyHeight(Object, CalculateArc(), 0)
                    else
                        call SetUnitFlyHeight(Object, Position.z, 0)
                    endif
                   
                    if UnitsImpact then
                        set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
                        if not (n == null) then
                            call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
                            set Ended = true
                            set isUsed = false
                           
                            set n = null
                        endif
                    endif
                   
                    if TreesImpact then
                        set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
                        if not (t == null) then
                            set Ended = true
                            set isUsed = false
                            set t = null
                        endif
                    endif
                   
                   
                elseif distance <= 0 then
                    set Ended = true
                    set isUsed = false
                endif
            endmethod
     


    sorry its a bit long btw,
    but while test, after i did regular missle, it went allright,
    but as homing missle, it messed up everything,
    the indexing went nut'z, all missles stopped,
    and everything stopped, like the system actually ended and just allowed creation of missles, and nothing else.
    any idea? :p

    heres the entire code:
    Code (vJASS):

        struct RealityObject
            public static thistype currentIndex = 0
           
            public unit Object
            public unit Homing
           
            public vector Position
            public vector Acceleration
            public vector Velocity
            public vector Start
            public vector Reach
           
            public effect Model
            public real distance
            public real Damage
            public real ArcHeight
           
            public boolean Ended
            public boolean isUsed
            public boolean UnitsImpact
            public boolean TreesImpact
            public boolean ConstantSpeed
            public boolean IgnoreTerrain
           
            public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
                local thistype this     = allocate()
               
                set .Object             = Object
                set .Homing             = null
                set .ArcHeight          = 0
               
                set .Position           = vector.create(position.x, position.y, position.z)
                set .Acceleration       = vector.create(acceleration.x, acceleration.y, acceleration.z)
                set .Velocity           = vector.create(0, 0, 0)
                set .Start              = vector.create(position.x, position.y, position.z)
                set .Reach              = vector.create(position.x, position.y, position.z)
               
                set .Damage             = 0
                set .distance           = 0
                set .Ended              = false
                set .isUsed             = false
                set .UnitsImpact        = false
                set .TreesImpact        = false
                set .ConstantSpeed      = false
                set .IgnoreTerrain      = false
               
                return this
            endmethod
           
            public method release takes nothing returns nothing
                set Object = null
               
                call Position.destroy()
                call Acceleration.destroy()
                call Velocity.destroy()
                call Start.destroy()
                call Reach.destroy()
               
                if not (Model == null) then
                    call DestroyEffect(Model)
                    set Model = null
                endif
               
                set .distance           = 0
                set .Ended              = false
                set .isUsed             = false
                set .UnitsImpact        = false
                set .TreesImpact        = false
                set .ConstantSpeed      = false
                set .IgnoreTerrain      = false
               
                call this.destroy()
            endmethod
           
            public method initiate takes nothing returns nothing
                set isUsed = true
                set distance = DistanceBetweenVectors(Start, Reach)
            endmethod
           
            public static method ber takes nothing returns boolean
                return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
            endmethod
           
            public static method ber2 takes nothing returns boolean
                return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
            endmethod
           
            private method CalculateArc takes nothing returns real
                local real y0 = GetCoordinateZ(Start.x, Start.y)
                local real y1 = GetCoordinateZ(Reach.x, Reach.y)
                local real h  = ArcHeight
                local real d  = DistanceBetweenVectors(Start, Reach)
                local real x  = DistanceBetweenVectors(Start, Position)
                return ParabolaZ2(y0, y1, h, d, x)
            endmethod
           
            public method update takes real interval returns nothing
                local unit n = null
                local destructable t = null
                local real angle = 0
                local real speed = Velocity.getLength()
                local vector v = 0
                set currentIndex = this
               
                if distance > 0 and isUsed and not Ended then
                    set distance = distance - speed
                   
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach)
                        set Velocity.x = speed * Cos(angle) * interval
                        set Velocity.y = speed * Sin(angle) * interval
                        set speed = (distance / speed) / interval
                        set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z) / (speed) - 0.5 * Acceleration.z * interval
                        call v.destroy()
                       
                        call SetUnitFacing(Object, angle)
                       
                        if not (GetWidgetLife(Homing) > 0.405) then
                            set Homing = null
                        endif
                    endif
                   
                    /*
                    if not (Homing == null) then
                        set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
                        set Reach.x = v.x
                        set Reach.y = v.y
                        set angle = vector.getAngle(Position, Reach) // no need for the rad->degree convertion
                        set Velocity.x = speed * Cos(angle) * interval // here we just update velocity components
                        set Velocity.y = speed * Sin(angle) * interval
                        set speed = (distance / speed) / interval // reuse 'speed' as time, and translate time into amount of iterations it'll take to complete the trajectory
                        set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z)/(speed) - 0.5*Acceleration.z*time // here we are using the fact that in reality, z-acceleration is negative in ballistic-ish trajectories
                        call v.destroy()
                    endif
                    */

                   
                    if ConstantSpeed == false then
                        set Velocity.x = Velocity.x + Acceleration.x
                        set Velocity.y = Velocity.y + Acceleration.y
                        set Velocity.z = Velocity.z + Acceleration.z
                    else
                        set Velocity.x = Acceleration.x
                        set Velocity.y = Acceleration.y
                        set Velocity.z = Acceleration.z
                    endif
                   
                    set Position.x = Position.x + Velocity.x
                    set Position.y = Position.y + Velocity.y
                    set Position.z = Position.z + Velocity.z
                   
                    call SetUnitX(Object, Position.x)
                    call SetUnitY(Object, Position.y)
                    if ArcHeight > 0 then
                        call SetUnitFlyHeight(Object, CalculateArc(), 0)
                    else
                        call SetUnitFlyHeight(Object, Position.z, 0)
                    endif
                   
                    if UnitsImpact then
                        set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
                        if not (n == null) then
                            call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
                            set Ended = true
                            set isUsed = false
                           
                            set n = null
                        endif
                    endif
                   
                    if TreesImpact then
                        set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
                        if not (t == null) then
                            set Ended = true
                            set isUsed = false
                            set t = null
                        endif
                    endif
                   
                   
                elseif distance <= 0 then
                    set Ended = true
                    set isUsed = false
                endif
            endmethod
           
        endstruct
     


    Thanks in advance.
     
  15. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Alright, sorry for the big delay!

    Code (vJASS):

    if ConstantSpeed == false then
                        set Velocity.x = Velocity.x + Acceleration.x
                        set Velocity.y = Velocity.y + Acceleration.y
                        set Velocity.z = Velocity.z + Acceleration.z
                    else
                        set Velocity.x = Acceleration.x
                        set Velocity.y = Acceleration.y
                        set Velocity.z = Acceleration.z
                    endif
     


    This is pretty bad.
    I'll try to explain.

    Velocity is our current speed towards something, right?
    Acceleration is how much our Velocity increases every iteration (timer timeout).

    So Velocity != Acceleration.

    If you aren't going to have an accelerated movement, then just set
    Acceleration./x/y/z = 0
    . Acceleration is 0 in that case.

    If you have an accelerated movement, just set up acceleration as you do with your velocity, with the exception of another *timer timeout, since it's m/s^2 instead of m/s.

    If you want to use Velocity and Acceleration you'll have to move away from your Parabola function.

    Now, since we want to do a parabol-looking movement, we need to have proper Velocity.z and Acceleration.z.
    What is proper in this case?
    Well, we know for one that
    Velocity.z + Acceleration.z * t = 0
    when the projectile is at the highest point in the trajectory, right? (it's the v = v0 + at formula)

    What can we make from that?
    We need to set Velocity.z so that
    Velocity.z + Acceleration.z * t = 0.

    We can do this:
    Velocity.z = - Acceleration.z * t

    t is the half of the time it takes to complete the movement, thus we can write it like this, and let the user input the time for the whole movement:
    Velocity.z = - Acceleration.z * 0.5 * t


    Alright, this looks pretty nice! But we have to update it a little.
    Velocity.z = - Acceleration.z * 0.5 * t/timer timeout

    time/timer timeout = amount of iterations until we've iterated for time seconds
    Now, let's add in that Gravity shit that I was hinting at earlier.
    Acceleration.z = GravityConstant * timer timeout * timer timeout

    Velocity.z = - Acceleration.z * 0.5 * t/timer timeout


    Still following me?
    We just found out a formula for how much our Velocity.z needs to be to complete the movement with a perfect parabola.

    Now there's one catch:
    What if the start.z and end.z isn't the same?
    That's easy, we add z velocity the same way as we did with x/y velocities!
    I.e:
    Velocity.z = (end.z - start.z) / time / timer timeout - Acceleration.z * 0.5 * time / timer timeout


    Z velocity is always projected 'upwards', i.e we don't need any trigonometric functions (Cos/Sin/Tan etc.)

    Now that we have that, let's write a launchToXYTimed-functions!
    Code (vJASS):

    static constant real TIMEOUT = 0.03125 // just declaring our TIMEOUT variable somewhere
    static constant real GRAVITY = -3500.0 // just declaring our GRAVITY variable somewhere

    method launchTimed takes vector target, real time returns nothing
         local real ticks = time / TIMEOUT // how many iterations our movement takes
         set Acceleration.z = GRAVITY * TIMEOUT * TIMEOUT
         set Acceleration.x = 0 // no acceleration in x/y
         set Acceleration.y = 0
         set Velocity.x = (target.x - Position.x) / ticks
         set Velocity.y = (target.y - Position.y) / ticks
         set Velocity.z = (target.z - Position.z) /ticks - Acceleration.z * 0.5 * ticks

         set Reach.x = target.x
         set Reach.y = target.y
         set Reach.z = target.z
    endmethod


    Now, in our loop method:
    Code (vJASS):

    method update takes nothing returns nothing
         
         local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared
         local real angle

         if (dist > 32*32) then // if we are closer than 32 units, we can say that the projectile has reached its destination
              if (.Homing != null) then
                   // I should note that this way of homing handling could make the projectile never hit the target :P
                   // If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
                   set .Reach.x = GetUnitX(.Homing)
                   set .Reach.y = GetUnitY(.Homing)
                   set .Reach.y = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
                   set angle = vector.getAngle(.Position, .Reach)
                   set .Acceleration.x = 32.0 * Cos(angle) * TIMEOUT * TIMEOUT
                   set .Acceleration.y = 32.0 * Sin(angle) * TIMEOUT * TIMEOUT
                   set .Acceleration.z = (.Reach - .Position)/(Pow(.Reach.getLength(), -1)) * TIMEOUT * TIMEOUT // might work, might not x)
              endif

              set .Velocity.x = .Velocity.x + .Acceleration.x
              set .Velocity.y = .Velocity.y + .Acceleration.y
              set .Velocity.z = .Velocity.z + .Acceleration.z

              set .Position.x = .Position.x + .Velocity.x
              set .Position.y = .Position.y + .Velocity.y
              set .Position.z = .Position.z + .Velocity.z

              call SetUnitX(unit, .Position.x)
              call SetUnitY(unit, .Position.y)
              call SetUnitFlyHeight(unit, .Position.z - GetCoordinateZ(.Position.x, .Position.y), 0)
         else
              // reached the destination
              call .destroy()
         endif
         
    endmethod
     


    Phew!
    Hope that it'll help you somehwat :p
     
  16. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    Well, thanks for your time for this ;p
    and btw, about the homing, the acceleration.z makes the target go to much up,
    so he dissapears in the first second.
    another thing is well, all accelerations in homing, i dont get why you do 32 * and then double it by twice the timeout,
    ----- [edit #1 in] ----------------------------------------------------------------------------------------
    Okay, i just read the comment, and well i figured why 32 * double timeout,
    To make constant velocity, okay i got how it works, so dont bother explaining it.
    ----- [edit #1 out] ---------------------------------------------------------------------------------------
    while you can just leave it as it is..
    and this is squared distance,
    Code (vJASS):

    local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared
     

    how does it work? since it made my missles go much smoother.
    and now theres the indexing bug, the missles for some reason mess up sometimes,
    if i send 3 missles, then 1, really fast, the
    first one goes normal,
    second one goes really fast,
    third one goes normal
    fourth one stops, and stays in his spot forever,
    and if i check it, theres only 3 missles running..

    Thank you in advance. [i will try arc soon]. this is my current code, that WORKS.
    if i add anything in sides, it fails to work xD
    Code (vJASS):

    public method launch takes real Time returns nothing
          set isUsed = true
          set .Time = Time
          //call launchTimed(Reach, time)
    endmethod

            public method update takes nothing returns nothing
                local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared
                local unit n = null
                local destructable t = null
                local real angle = 0
                local vector v = 0
                set currentIndex = this
               
                if dist > 32*32 and isUsed and not Ended or GetWidgetLife(Object) < 0.405 then
                    if (Homing != null) then
                        // I should note that this way of homing handling could make the projectile never hit the target :P
                        // If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
                        set .Reach.x = GetUnitX(.Homing)
                        set .Reach.y = GetUnitY(.Homing)
                        set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
                        set angle = AngleBetweenVectors(Position, Reach)
                        //set .Acceleration.z = (.Reach - .Position)/(Pow(.Reach.getLength(), -1)) * TIMEOUT * TIMEOUT // might work, might not x)
                       
                        call SetUnitFacing(Object, angle * bj_RADTODEG)
                       
                        if GetWidgetLife(Homing) < 0.405 then
                            set Homing = null
                        endif
                    endif
                   
                   
                    set Velocity.x = Velocity.x + Acceleration.x
                    set Velocity.y = Velocity.y + Acceleration.y
                    set Velocity.z = Velocity.z + Acceleration.z
                   
                   
                    set Position.x = Position.x + Velocity.x
                    set Position.y = Position.y + Velocity.y
                    set Position.z = Position.z + Velocity.z
                   
                    call SetUnitX(Object, Position.x)
                    call SetUnitY(Object, Position.y)
                    if ArcHeight > 0 then
                        //call SetUnitFlyHeight(Object, CalculateArc(), 0)
                        //You said its actually a wrong way to calculate arc,
                        //
                        set Velocity.z = (Reach.z - Start.z) / Time / TIMEOUT - Acceleration.z * 0.5 * Time / TIMEOUT
                    else
                        call SetUnitFlyHeight(Object, Position.z - GetCoordinateZ(Position.x, Position.y), 0)
                    endif
                   
                    if UnitsImpact then
                        set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
                        if not (n == null) then
                            call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
                            set Ended = true
                            set isUsed = false
                           
                            set n = null
                        endif
                    endif
                   
                    if TreesImpact then
                        set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
                        if not (t == null) then
                            set Ended = true
                            set isUsed = false
                            set t = null
                        endif
                    endif
                   
                   
                elseif dist <= 32*32 then
                    set Ended = true
                    set isUsed = false
                endif
            endmethod

     
     
  17. Tukki

    Tukki

    Joined:
    Feb 10, 2008
    Messages:
    247
    Resources:
    2
    Maps:
    1
    JASS:
    1
    Resources:
    2
    Shit, totally forgot about this.. I've been loaded with projects and compilations from school, so I guess I just forgot this thread in the midst of it all :(

    I'll try to write a post by tomorrow night :)

    The reason to why I'm doing this:
    local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared

    Instead of:
    local real dist = SquareRoot((.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z)) // distance

    Is that SquareRoot calls are really slow (they aren't very efficient).
    (The second line has a SquareRoot call)

    So if we have our distance squared (say dist2) how do we use time and velocity on it?
    The answer is really simple; just square them too!

    So this line:
    if dist > 32*32 and
    is actually:
    dist2 > 322, because if we use SquareRoot on this inequality, we get: dist > 32
    Easy, enough?

    So if I want the time it takes to reach the destination based on the distance left, and our current velocity, we do like this:
     real time =  dist / (velocity * velocity) 

    Because in reality,
    dist
    is the squared distance to the destination point!

    I'll get to the other problems tomorrow (or later today actually.. ) :)

    EDIT:

    Code (vJASS):

     if (Homing != null) then
                        // I should note that this way of homing handling could make the projectile never hit the target :P
                        // If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
                        set .Reach.x = GetUnitX(.Homing)
                        set .Reach.y = GetUnitY(.Homing)
                        set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
                        set angle = AngleBetweenVectors(Position, Reach)
                        set dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared
                        set .Acceleration.z = (.Reach - .Position)/(Pow(SquareRoot(dist), -1)) * TIMEOUT * TIMEOUT // might work, might not x)
                        set .Acceleration.y = Sin(angle) * baseSpeed * TIMEOUT * TIMEOUT // baseSpeed is set in our launch(..) method
                        set .Acceleration.x = Cos(angle) * baseSpeed * TIMEOUT * TIMEOUT // *TIMEOUT*TIMEOUT because acceleration is m/s^2

                        call SetUnitFacing(Object, angle * bj_RADTODEG)
                       
                        if GetWidgetLife(Homing) < 0.405 then
                            set Homing = null
                        endif
                    endif


    If our missile is a linear one (without any arc), we don't have any z velocity or z acceleration.
    (If the missile isn't homing that is)
    This means that
    set .Position.z = .Position.z + .Velocity.z
    equals
    .Position.z
    (if the missile isn't homing), since
    .Velocity.z
    is 0!
    What does this mean? It means that we can skip the whole 'arc' check and calculations, and just do this!
    Code (vJASS):

    /*if ArcHeight > 0 then
                        //call SetUnitFlyHeight(Object, CalculateArc(), 0)
                        //You said its actually a wrong way to calculate arc,
                        // Yeah, but you still need to set the height, right? ;)
                        // And we update our z velocity earlier, so no need to reset it here
                        set Velocity.z = (Reach.z - Start.z) / Time / TIMEOUT - Acceleration.z * 0.5 * Time / TIMEOUT
                    else
                        call SetUnitFlyHeight(Object, Position.z - GetCoordinateZ(Position.x, Position.y), 0)
                    endif*/

    call SetUnitFlyHeight(Object, .Position.z - GetCoordinateZ(.Position.x, .Position.y), 0)


    Also, my guess at the random fast-moving projectiles is that our missile engine is moving the missile as well as your RealityKnockback system.
    Which means that the unit is being moved 2x every second.
     
    Last edited: Apr 30, 2011
  18. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    lol, i forgot to mention, the code isn't using anything that the old version used, i re-wrote the entire code, this is the new code:
    Code (vJASS):

    library RealityMath requires Vector
        globals
            public real TimerInterval = 0.032
            private location Dummy_Loc = Location(0, 0)
        endglobals
       
        function 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)
        endfunction
       
        function AngleBetweenVectors takes vector a, vector b returns real
            return Atan2(b.y - a.y, b.x - a.x)
        endfunction
       
        function 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
        endfunction
           
        function ParabolaZ takes real h, real d, real x returns real
            return (4 * h / d) * (d - x) * (x / d)
        endfunction
       
        function GetCoordinateZ takes real x, real y returns real
            call MoveLocation(Dummy_Loc, x, y)
            return GetLocationZ(Dummy_Loc)
        endfunction
           
        function TimeToDistance takes real time, real speed, real interval returns real
            return time * (speed / interval)
        endfunction
       
        function DistanceToTime takes real distance, real speed, real interval returns real
            return distance / (speed / interval)
        endfunction
    endlibrary
     

    Code (vJASS):

    library RealityObject requires RealityMath, Vector, GetNearest, DestructableLib
       
        //------------------------------------------------------------------------------------------------------------\\
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //------------------------------------------------------------------------------------------------------------\\
        //  
        //  Intro:
        //  ¯¯¯¯¯
        //      * System Created by dardas @ hiveworkshop.com,
        //      * This was created because of a request by Minimage @ hiveworkshop.com.
        //  
        //  Requirements:
        //  ¯¯¯¯¯¯¯¯¯¯¯¯
        //      * RealityMath       - SHOULD be found with this code.
        //      * Vector            - [url]http://www.wc3c.net/showthread.php?t=87027[/url]
        //      * GetNearest        - [url]http://www.wc3c.net/showthread.php?t=108907[/url]
        //      * DestructableLib   - [url]http://www.wc3c.net/showthread.php?t=103927[/url]
        //      *
        //      *
        //      
        //  Credits:
        //  ¯¯¯¯¯¯¯
        //      * Minimage @ hiveworkshop.com > helped testing for bugs
        //      * Tukki @ hiveworkshop.com    > helped me pretty much all the time with coding/physics.
        //      
        //  Known bugs:
        //  ¯¯¯¯¯¯¯¯¯¯
        //      *
        //      *
        //      
        //  Known limitations:
        //  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        //      *
        //      *
        //      
        //  Extra Info:
        //  ¯¯¯¯¯¯¯¯¯¯
        //      * Started at 15/04/2011
        //      * Ended at XX/XX/XXXX
        //  
        //------------------------------------------------------------------------------------------------------------\\
       
        struct RealityObject
            static constant real TIMEOUT = 0.032

            public static thistype currentIndex = 0
           
            //Missle itself
            public unit Object
           
            //Missle vectors
            public vector Position
            public vector Acceleration
            public vector Velocity
            public vector Start
            public vector Reach
           
            //Missle side effects related
            public effect Model
            public real Damage
           
            //Arc related
            public real ArcHeight
           
            //Homing related
            public unit Homing
            public real HomingVelocity
           
            //All the booleans..
            public boolean Ended
            public boolean isUsed
            public boolean UnitsImpact
            public boolean TreesImpact
            public boolean ConstantSpeed
            public boolean IgnoreTerrain
           
            public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
                local thistype this     = allocate()
               
                set .Object             = Object
                set .Homing             = null
                set .ArcHeight          = 0
               
                set .Position           = vector.create(position.x, position.y, position.z)
                set .Acceleration       = vector.create(acceleration.x * Cos(angle * bj_DEGTORAD), acceleration.y * Sin(angle * bj_DEGTORAD), acceleration.z)
                set .Velocity           = vector.create(0, 0, 0)
                set .Start              = vector.create(position.x, position.y, position.z)
                set .Reach              = vector.create(position.x, position.y, position.z)
               
                set .Damage             = 0
                set .ArcHeight          = 0
                set .Homing             = null
                set .HomingVelocity     = 0
               
                set .Ended              = false
                set .isUsed             = false
                set .UnitsImpact        = false
                set .TreesImpact        = false
                set .ConstantSpeed      = false
                set .IgnoreTerrain      = false
               
                return this
            endmethod
           
            public method release takes nothing returns nothing
                set Object = null
               
                call Position.destroy()
                call Acceleration.destroy()
                call Velocity.destroy()
                call Start.destroy()
                call Reach.destroy()
               
                if not (Model == null) then
                    call DestroyEffect(Model)
                    set Model = null
                endif
               
                set .Damage             = 0
                set .ArcHeight          = 0
                set .Homing             = null
                set .HomingVelocity     = 0
               
                set .Ended              = false
                set .isUsed             = false
                set .UnitsImpact        = false
                set .TreesImpact        = false
                set .ConstantSpeed      = false
                set .IgnoreTerrain      = false
               
                call this.destroy()
            endmethod
           
            public method launch takes nothing returns nothing
                set isUsed = true
            endmethod
           
            public method homing takes unit target, real ConstantVelocity returns nothing
                set .Homing = target
                set .HomingVelocity = ConstantVelocity
                set .Acceleration.x = 0
                set .Acceleration.y = 0
                set .Acceleration.z = 0
            endmethod
           
            public static method ber takes nothing returns boolean
                return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
            endmethod
           
            public static method ber2 takes nothing returns boolean
                return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
            endmethod
           
            private method CalculateArc takes nothing returns real
                local real y0 = GetCoordinateZ(Start.x, Start.y)
                local real y1 = GetCoordinateZ(Reach.x, Reach.y)
                local real h  = ArcHeight
                local real d  = DistanceBetweenVectors(Start, Reach)
                local real x  = DistanceBetweenVectors(Start, Position)
                return ParabolaZ2(y0, y1, h, d, x)
            endmethod
           
            public method update takes nothing returns nothing
                local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) // distance squared
                local unit n = null
                local destructable t = null
                local real angle = 0
                local real Time = 0
                local vector v = 0
                set currentIndex = this
               
                if dist > 32*32 and isUsed and not Ended or GetWidgetLife(Object) < 0.405 then
                    set Time = DistanceToTime(DistanceBetweenVectors(Start, Reach), Velocity * Velocity, TIMEOUT)
                    if (Homing != null) then
                        // I should note that this way of homing handling could make the projectile never hit the target :P
                        // If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
                        //function DistanceToTime takes real distance, real speed, real interval returns real
                        set .Reach.x = GetUnitX(.Homing)
                        set .Reach.y = GetUnitY(.Homing)
                        set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
                        set angle = AngleBetweenVectors(.Position, .Reach)
                        set .Velocity.x = .HomingVelocity * Cos(angle)
                        set .Velocity.y = .HomingVelocity * Sin(angle)
                        set .Acceleration.z = (.Reach - .Position)/(Pow(.Reach.getLength(), -1)) * TIMEOUT * TIMEOUT // might work, might not x)
                       
                        call SetUnitFacing(Object, angle * bj_RADTODEG)
                       
                        if GetWidgetLife(Homing) < 0.405 then
                            set Homing = null
                        endif
                    endif
                   
                   
                    set Velocity.x = Velocity.x + Acceleration.x
                    set Velocity.y = Velocity.y + Acceleration.y
                    set Velocity.z = Velocity.z + Acceleration.z
                   
                    set Position.x = Position.x + Velocity.x
                    set Position.y = Position.y + Velocity.y
                    set Position.z = Position.z + Velocity.z
                   
                    call SetUnitX(Object, Position.x)
                    call SetUnitY(Object, Position.y)
                    call SetUnitFlyHeight(Object, Position.z, 0)
                    if ArcHeight > 0 then
                        //call SetUnitFlyHeight(Object, CalculateArc(), 0)
                        //You said its actually a wrong way to calculate arc,
                        //
                        //set Position.z = (Reach.z - Start.z) / Time / TIMEOUT - ArcHeight * 0.5 * Time / TIMEOUT
                        set Position.z = CalculateArc()
                    else
                        set Position.z = Position.z - GetCoordinateZ(Position.x, Position.y)
                    endif
                   
                    if UnitsImpact then
                        set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
                        if not (n == null) then
                            call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
                            set Ended = true
                            set isUsed = false
                           
                            set n = null
                        endif
                    endif
                   
                    if TreesImpact then
                        set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
                        if not (t == null) then
                            set Ended = true
                            set isUsed = false
                            set t = null
                        endif
                    endif
                   
                   
                elseif dist <= 32*32 then
                    set Ended = true
                    set isUsed = false
                endif
            endmethod
           
        endstruct
    endlibrary
     

    Code (vJASS):

    library RealityMissle requires RealityMath, RealityObject
        //------------------------------------------------------------------------------------------------------------\\
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //  
        //------------------------------------------------------------------------------------------------------------\\
        //  
        //  Intro:
        //  ¯¯¯¯¯
        //      * System Created by dardas @ hiveworkshop.com,
        //      * This was created because of a request by Minimage @ hiveworkshop.com.
        //  
        //  Requirements:
        //  ¯¯¯¯¯¯¯¯¯¯¯¯
        //      * RealityMath       - SHOULD be found with this code.
        //      * RealityObject     - SHOULD be found with this code.
        //      
        //  Credits:
        //  ¯¯¯¯¯¯¯
        //      * Minimage @ hiveworkshop.com > helped testing for bugs
        //      * Tukki @ hiveworkshop.com    > helped me pretty much all the time with coding/physics.
        //      
        //  Known bugs:
        //  ¯¯¯¯¯¯¯¯¯¯
        //      *
        //      *
        //      
        //  Known limitations:
        //  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        //      *
        //      *
        //      
        //  Extra Info:
        //  ¯¯¯¯¯¯¯¯¯¯
        //      * Started at 15/04/2011
        //      * Ended at XX/XX/XXXX
        //  
        //------------------------------------------------------------------------------------------------------------\\
       
        struct Missle
            //
            public static integer array Index
            public static integer InstanceCount = 0
            public static integer Dummy_Unit = 'e000'
            public static integer Flight_Ability = 'Amrf'
            public static timer TimerObject = CreateTimer()
            //
            public RealityObject Object

            public static method create takes player Owner, real x, real y, real height, real angle, real acceleration returns thistype
                local thistype this = InstanceCount
                local unit missle = CreateUnit(Owner, Dummy_Unit, x, y, angle)
               
                local vector pos = vector.create(x, y, height)
                local vector acc = vector.create(acceleration, acceleration, 0)
               
                set .Object = RealityObject.create(missle, pos, angle, acc)
                call UnitAddAbility(.Object.Object, Flight_Ability)
                call UnitRemoveAbility(.Object.Object, Flight_Ability)
               
                call pos.destroy()
                call acc.destroy()
                set missle = null
               
                if InstanceCount == 0 then
                    call TimerStart(TimerObject, RealityObject.TIMEOUT, true, function Missle.Loop)
                endif
               
                set Index[InstanceCount] = this
                set InstanceCount = InstanceCount + 1
                call BJDebugMsg(I2S(InstanceCount))
                return this
            endmethod
           
            public static method Loop takes nothing returns nothing
                local thistype t = 0
                local integer i = 0
               
                loop
                exitwhen i >= InstanceCount
                set t = t.Index[i]
               
                call t.Object.update()
                if t.Object.Ended then
                    //release returns i - 1, so just setting i to release gives i = i - 1.
                    //you must set i = i - 1, so it will loop again or it will skip 1 missle in this current update.
                    set i = t.end(i)
                endif
               
                set i = i + 1
                endloop
               
            endmethod
           
            public method end takes integer i returns integer
                //Releasing the missle object
                call RemoveUnit(Object.Object)
                call Object.release()
               
                //Destroying the struct
                call destroy()
               
                // Recycling the indexer system
                set InstanceCount = InstanceCount - 1
                set Index[i] = Index[InstanceCount]
               
                return i - 1
            endmethod
           
        endstruct
    endlibrary
     


    anyways, the odd part is that its the indexing problem.
    [edit]
    anyways, wrong choice of words, what i meant that the odd part of twice movement is because of the indexing delay.
    [/edit]
    not twice movement per interval, the problem is
    that indexing doesnt work instantly, since it only bugs it if i shoot 5 missles with shift + 5 clicks on left button (so that flag appears 5 times), then my hero shoots it 5 teams instantly, so basicly indexing increases then puts wrong values..
    then when 1 missle starts, it overwrites another missle, then the missle that got overwrited stops moving, about quick missles, i donno why ;/

    about arc, it works this way, so if you got a better way, tell me xD
    you're way last post basicly would just put the missle in constant height, and if it goes thru a terrain mountain, it will keep same height, and not go up with the mountain. i would love hearing another way to check arc, using velocity/acceleration.

    Thanks in advance.
     
  19. Tukki

    Tukki

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

    This version should work properly with acceleration and arc!
    Code (vJASS):
        struct RealityObject
            static constant real TIMEOUT = 0.03125 // 32 fps (1/0.03125 = 32)
            static constant real GRAVITY = -3000.0 // 3000 units of gravity

            public static thistype currentIndex = 0
           
            //Missle itself
            public unit Object
           
            //Missle vectors
            public vector Position
            public vector Acceleration
            public vector Velocity
            public vector Start
            public vector Reach
           
            //Missle side effects related
            public effect Model
            public real Damage
           
            //Homing related
            public unit Homing
            public real HomingVelocity
           
            //All the booleans..
            public boolean Ended
            public boolean isUsed
            public boolean UnitsImpact
            public boolean TreesImpact
            public boolean ConstantSpeed
            public boolean IgnoreTerrain
           
            public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
                local thistype this     = allocate()
               
                set .Object             = Object
                set .Homing             = null
               
                set .Position           = vector.create(position.x, position.y, position.z)
                set .Acceleration       = vector.create(acceleration.x * Cos(angle * bj_DEGTORAD), acceleration.y * Sin(angle * bj_DEGTORAD), acceleration.z)
                set .Velocity           = vector.create(0, 0, 0)
                set .Start              = vector.create(position.x, position.y, position.z)
                set .Reach              = vector.create(position.x, position.y, position.z)
               
                set .Damage             = 0
                set .Homing             = null
                set .HomingVelocity     = 0
               
                set .Ended              = false
                set .isUsed             = false
                set .UnitsImpact        = false
                set .TreesImpact        = false
                set .ConstantSpeed      = false
                set .IgnoreTerrain      = false
               
                return this
            endmethod
           
            public method release takes nothing returns nothing
                set .Object = null
               
                call .Position.destroy()
                call .Acceleration.destroy()
                call .Velocity.destroy()
                call .Start.destroy()
                call .Reach.destroy()
               
                if (.Model != null) then
                    call DestroyEffect(.Model)
                endif
               
                call this.destroy()
            endmethod
           
            public method launchArc takes vector target, real baseVelocity returns nothing
                local integer dist = GetDistanceBetweenVectors(.Position, target)
                local integer tickCount = R2I((dist / baseVelocity) / RealityObject.TIMEOUT)
                local real angle = GetAngleBetweenVectors(.Position, target)
               
                set .Acceleration.x = 0
                set .Acceleration.y = 0
                set .Acceleration.z = RealityObject.GRAVITY * RealityObject.TIMEOUT * RealityObject.TIMEOUT
                                     // acceleration because the missile's trajectory is curved
               
                set .Velocity.x = (target.x - .Position.x) / tickCount
                set .Velocity.y = (target.y - .Position.y) / tickCount      
                set .Velocity.z = (target.z - .Position.z) / tickCount - .Acceleration.z * 0.5 * tickCount
               
                set .Reach.x = target.x
                set .Reach.y = target.y
                set .Reach.z = target.z
           
                set .isUsed = true
            endmethod
           
            public method launch takes vector target, real baseVelocity returns nothing
                local integer dist = GetDistanceBetweenVectors(.Position, target)
                local integer tickCount = R2I((dist / baseVelocity) / RealityObject.TIMEOUT)
               
                set .Acceleration.x = 0
                set .Acceleration.y = 0
                set .Acceleration.z = 0 // no acceleration because the missile's trajectory is straight
               
                set .Velocity.x = (target.x - .Position.x) / tickCount
                set .Velocity.y = (target.y - .Position.y) / tickCount
                set .Velocity.z = (target.z - .Position.z) / tickCount
               
                set .Reach.x = target.x
                set .Reach.y = target.y
                set .Reach.z = target.z
               
                set .isUsed = true
            endmethod
           
            public method homing takes unit target, real ConstantVelocity returns nothing
                set .Homing = target
                set .HomingVelocity = ConstantVelocity
                set .Acceleration.x = 0
                set .Acceleration.y = 0
                set .Acceleration.z = 0
            endmethod
           
            public static method ber takes nothing returns boolean
                return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
            endmethod
           
            public static method ber2 takes nothing returns boolean
                return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
            endmethod
           
            public method update takes nothing returns nothing
                local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) // distance squared
                local unit n = null
                local destructable t = null
                local real angle = 0
                local integer ticks
                local vector v = 0
                set currentIndex = this
               
                if dist > 32*32 and .isUsed and not .Ended or GetWidgetLife(.Object) < 0.405 then
                    if (.Homing != null) then
                        set .Reach.x = GetUnitX(.Homing)
                        set .Reach.y = GetUnitY(.Homing)
                        set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)

                        set dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y)  // 2d-distance squared
                        set ticks = R2I((dist / (.HomingVelocity * .HomingVelocity)) / RealityObject.TIMEOUT )
                       
                        // only changes acceleration because if we changed velocity this way, the missile wouldn't be able to hit the target
                        // this makes the missile 'dodgeable', though. Since the missile will speed up if the target is in front of it, while it will break when
                        // it is behind. Making it possible to run around in circles to 'confuse' the missile.
                        set .Acceleration.z = ((.Reach.z - .Position.z)/ticks) * TIMEOUT * TIMEOUT
                        set .Acceleration.y = ((.Reach.y - .Position.y)/ticks) * TIMEOUT * TIMEOUT
                        set .Acceleration.x = ((.Reach.x - .Position.x)/ticks) * TIMEOUT * TIMEOUT
                       
                        call SetUnitFacing(Object, angle * bj_RADTODEG)
                       
                        if GetWidgetLife(.Homing) < 0.405 then
                            set .Homing = null
                        endif
                    endif
                   
                    set .Velocity.x = .Velocity.x + .Acceleration.x
                    set .Velocity.y = .Velocity.y + .Acceleration.y
                    set .Velocity.z = .Velocity.z + .Acceleration.z
                   
                    set .Position.x = .Position.x + .Velocity.x
                    set .Position.y = .Position.y + .Velocity.y
                    set .Position.z = .Position.z + .Velocity.z
                   
                    call SetUnitX(.Object, .Position.x)
                    call SetUnitY(.Object, .Position.y)
                   
                    // If .IgnoreTerrain flag is set, the missile can go through terrain, if not, the missile flies at .Position.z height above ground
                    if (.IgnoreTerrain) then
                        call SetUnitFlyHeight(.Object, .Position.z - GetCoordinateZ(.Position.x, .Position.y), 0)
                    else
                        call SetUnitFlyHeight(.Object, .Position.z, 0)
                    endif
                   
                    if .UnitsImpact then
                        set n = GetNearestUnit(.Position.x, .Position.y, 75, Condition(function RealityObject.ber))
                        if not (n == null) then
                            call UnitDamageTarget(.Object, n, .Damage, false, false, null, null, null)
                            set .Ended = true
                            set .isUsed = false
                           
                            set n = null
                        endif
                    endif
                   
                    if .TreesImpact then
                        set t = GetNearestDestructable(.Position.x, .Position.y, 75, Condition(function RealityObject.ber2))
                        if not (t == null) then
                            set .Ended = true
                            set .isUsed = false
                            set t = null
                        endif
                    endif
                elseif dist <= 32*32 then
                    set .Ended = true
                    set .isUsed = false
                endif
            endmethod
        endstruct


    I've added 2 methods:
    public method launch takes vector target, real baseSpeed returns nothing

    public method launchArc takes vector target, real baseSpeed returns nothing

    They set up velocity and acceleration accordingly.

    I also updated:
    public method update takes nothing returns nothing
    : improved efficiency, updated syntax, fixed arithmetics and added .IgnoreTerrain flag
    public method release takes nothing returns nothing
    : removed unnecessary variable nulling

    I also added the variable:
    static constant real GRAVITY = -3000.0
    : needed for proper z acceleration

    I removed the variable:
    public real ArcHeight
    : isn't needed anymore

    The indexing seems to work properly, I'll do some testing on it later on.
    Until then!
     
    Last edited: May 3, 2011
  20. dardas

    dardas

    Joined:
    Sep 12, 2008
    Messages:
    649
    Resources:
    0
    Resources:
    0
    The indexing seems to work better, since i'm a bit more carefull now, and increased cooldown, lastly i gotta check mui,

    PARABOLA ARC
    it doesnt work, the gravity part is perfect, but it just goes insanely up of bounds, and Reach.z Position.z never meet, so basicly, you can never end arced missle, so its just stuck in database, eventually will go too much up and crush,
    if its possible.

    Homing
    Homing is quite annoying me,
    it works great, but it goes thru 1 direction, the direction it started in xD
    lets say you shoot towards 90 degrees from you're hero,
    and then its suposed to follow you're enemy, it doesnt,
    it keeps a constant 90 degrees,
    and changes distance because of the reach.x - position.x, and y/z.
    i loved you're calculation for accelerationZ on homing,
    making it go up aswell, so the reach.z and position.z will meet ^^
    I've been trying some stuff, working thing was this:
    Code (vJASS):

    set .Acceleration.x = .HomingVelocity * Cos(angle) * TIMEOUT
    set .Acceleration.y = .HomingVelocity * Sin(angle) * TIMEOUT
    set .Acceleration.z = .HomingVelocity * TIMEOUT * TIMEOUT
     

    But i really dont wanna use it, since it will keep a constant acceleration,
    and it will make the velocity go insane and very impossible to follow enemy,
    so it will do circles around the enemy trying to follow it moving, and it will just have impact on anything around, quite easy to avoid, if i do it on velocity instead, looks quite ugly.

    BTW, i'm,sry my text is so unarranged, im a bad writer...
    also, dont write me a pm about this, i'm looking at it constantly whenever my inet is open, since i switch tabs and refresh alot.

    Thank you for you're help so far.