• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Solved] Arc Formula Discussion

Status
Not open for further replies.
Level 11
Joined
Sep 12, 2008
Messages
657
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:

JASS:
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 ;/
 
Level 6
Joined
Feb 10, 2008
Messages
300
There's a really easy way to calculate arcs, and that is by using a gravity constant!
An example:

JASS:
    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)
JASS:
    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:
JASS:
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:
JASS:
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 ;)
 
Level 11
Joined
Sep 12, 2008
Messages
657
Actually, look what i did:
Code:
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
 
Level 6
Joined
Feb 10, 2008
Messages
300
Which is ideally the same as what I said at the end :p
(Using your old parabola function)

JASS:
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
 
Level 6
Joined
Feb 10, 2008
Messages
300
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)
 
Level 11
Joined
Sep 12, 2008
Messages
657
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?
JASS:
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:
JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
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:
JASS:
// 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:
JASS:
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.
 
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
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:

JASS:
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:

JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
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:
JASS:
        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
 
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
Alright, first you should update your loopHandler and integrate it in your struct.
Something like this:
JASS:
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:
JASS:
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!
 
Level 6
Joined
Feb 10, 2008
Messages
300
Alright

In the first example when we do this:
JASS:
       //
        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.

JASS:
        //
        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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
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.
 
Level 11
Joined
Sep 12, 2008
Messages
657
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.
 
Level 11
Joined
Sep 12, 2008
Messages
657
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:
Level 6
Joined
Feb 10, 2008
Messages
300
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.
 
Level 11
Joined
Sep 12, 2008
Messages
657
hey dude, changed velocity into a vector, and im in a problem.
look at this:
JASS:
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?
 
Level 6
Joined
Feb 10, 2008
Messages
300
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)
 
Level 11
Joined
Sep 12, 2008
Messages
657
actually..
JASS:
//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
 
Level 6
Joined
Feb 10, 2008
Messages
300
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? ;)
 
Level 11
Joined
Sep 12, 2008
Messages
657
well.. it works, BUT i do use VelocityZ now ^^
JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
That's isn't really how you use velocities.

This is what you should aim at:
JASS:
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.
JASS:
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
 
Level 11
Joined
Sep 12, 2008
Messages
657
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?
 
Level 6
Joined
Feb 10, 2008
Messages
300
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:
JASS:
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
}
 
Level 11
Joined
Sep 12, 2008
Messages
657
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.
JASS:
            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:
JASS:
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:
JASS:
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:
Level 6
Joined
Feb 10, 2008
Messages
300
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:
JASS:
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:
JASS:
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:
JASS:
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
 
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
        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:
Level 6
Joined
Feb 10, 2008
Messages
300
Okay, good choice!

Now:

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

So, you never do stuff like this:
JASS:
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:
JASS:
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)
 
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
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:
JASS:
    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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
Alright, sorry for the big delay!

JASS:
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!
JASS:
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:
JASS:
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
 
Level 11
Joined
Sep 12, 2008
Messages
657
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,
JASS:
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
JASS:
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
 
Level 6
Joined
Feb 10, 2008
Messages
300
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:

JASS:
 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!
JASS:
/*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:
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
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
JASS:
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
JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
Alright, nice update!

This version should work properly with acceleration and arc!
JASS:
    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:
Level 11
Joined
Sep 12, 2008
Messages
657
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:
JASS:
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.
 
Level 6
Joined
Feb 10, 2008
Messages
300
It seems like the problem lies within the z-declaring, so you should rewrite it like this:

JASS:
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 + GetCoordniateZ(position.x, position.y)
        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)

        call SetUnitFlyHeight(.Object, position.z /*not .Position.z*/, 0)

.. etc.

Homing doesn't work because of the unset 'angle variable.
Just add the angle = GetAngleBetweenVectors(.Position, .Reach) before you actually set the facing.
Because of the unset variable the whole script crashes at that point, every time, so try to fix that first.
 
Level 11
Joined
Sep 12, 2008
Messages
657
Okay, now im mad on the indexing, i realised what happends,
it overwrites last missle, thats the idea, but it does not re-create it and re-do variables, so it leaks 5 vectors + 1 RealityObject,
and also it makes the other missle stops, because its behing overwritten,
which is very bad. if you want me to pm you the test map, tell me.
 
Status
Not open for further replies.
Top