# [Solved] Arc Formula Discussion

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

1. ### Tukki

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

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

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

2. ### dardas

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

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

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

3. ### Tukki

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

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

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

4. ### dardas

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

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

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

5. ### Tukki

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

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

`yVel = baseVelocity * Sin(alpha) * updateFrequency`

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

No lie.

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

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

Works, right?

6. ### dardas

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

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

set UsedVelocity = SquareRoot(velX * velX + velY * velY) / RealityMath_TimerInterval

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

7. ### Tukki

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

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

vector acceleration
vector velocity
vector position

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

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

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

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

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

...

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

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

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

8. ### dardas

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

Anyways, what is acceleration, the speed?

9. ### Tukki

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

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

An example would be:
Code (vJASS):

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

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

10. ### dardas

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

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

set Position.x = Position.x + Velocity.x * Cos(Angle * bj_DEGTORAD)
set Position.y = Position.y + Velocity.y * Sin(Angle * bj_DEGTORAD)
set Position.z = Position.z + Velocity.z

call SetUnitX(Object, Position.x)
call SetUnitY(Object, Position.y)
call SetUnitFlyHeight(Object, Position.z - GetCoordinateZ(Position.x, Position.y), 0)
call SetUnitFacing(Object, Angle)

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

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

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

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

set Position.x = Position.x + Velocity.x * Cos(Direction.x * bj_DEGTORAD)
set Position.y = Position.y + Velocity.y * Sin(Direction.y * bj_DEGTORAD)
set Position.z = Position.z + Velocity.z

call MoveUnitToVector(Object, Position)
endif
endmethod

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

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

Last edited: Apr 15, 2011
11. ### Tukki

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

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

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

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

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

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

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

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

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

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

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

If you don't understand this, it's not worth starting with bouncing

12. ### dardas

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

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

public method update takes real interval returns nothing
local real angle = 0
local vector v = 0

if distance > 0 and isUsed and not Ended then
set distance = distance - Velocity.getLength()

if not (Homing == null) then
set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
set Reach.x = v.x
set Reach.y = v.y
set angle = vector.getAngle(Position, Reach) * bj_RADTODEG
set Direction.x = angle
set Direction.y = angle
call v.destroy()
endif

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

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

call MoveUnitToVector(Object, Position)
elseif distance <= 0 then
set Ended = true
set isUsed = false
endif
endmethod

i've fixed the interval part, it should work now ? xD and btw,
i understood the idea of interval, its for acceleration per second
instead of per interval. nice thinking =]

Last edited: Apr 15, 2011
13. ### Tukki

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

Now:

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

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

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

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

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

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

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

local real speed = Velocity.getLength()

...
set distance = distance - speed

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

// Acceleration components (Acceleration.x/y/z) are 0 if speed is constant, so no need to check that
set Velocity.x = Velocity.x + Acceleration.x  // Acceleration is a vector, so it got both length and direction: we can remove that *Cos/Sin(..) thingey
set Velocity.y = Velocity.y + Acceleration.y
set Velocity.z = Velocity.z + Acceleration.z
//endif

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

call MoveUnitToVector(Object, Position)

14. ### dardas

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

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

public method update takes real interval returns nothing
local unit n = null
local destructable t = null
local real angle = 0
local real speed = Velocity.getLength()
local vector v = 0
set currentIndex = this

if distance > 0 and isUsed and not Ended then
set distance = distance - speed

if not (Homing == null) then
set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
set Reach.x = v.x
set Reach.y = v.y
set angle = vector.getAngle(Position, Reach)
set Velocity.x = speed * Cos(angle) * interval
set Velocity.y = speed * Sin(angle) * interval
set speed = (distance / speed) / interval
set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z) / (speed) - 0.5 * Acceleration.z * interval
call v.destroy()

call SetUnitFacing(Object, angle)

if not (GetWidgetLife(Homing) > 0.405) then
set Homing = null
endif
endif

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

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

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

call SetUnitX(Object, Position.x)
call SetUnitY(Object, Position.y)
if ArcHeight > 0 then
call SetUnitFlyHeight(Object, CalculateArc(), 0)
else
call SetUnitFlyHeight(Object, Position.z, 0)
endif

if UnitsImpact then
set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
if not (n == null) then
call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
set Ended = true
set isUsed = false

set n = null
endif
endif

if TreesImpact then
set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
if not (t == null) then
set Ended = true
set isUsed = false
set t = null
endif
endif

elseif distance <= 0 then
set Ended = true
set isUsed = false
endif
endmethod

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

heres the entire code:
Code (vJASS):

struct RealityObject
public static thistype currentIndex = 0

public unit Object
public unit Homing

public vector Position
public vector Acceleration
public vector Velocity
public vector Start
public vector Reach

public effect Model
public real distance
public real Damage
public real ArcHeight

public boolean Ended
public boolean isUsed
public boolean UnitsImpact
public boolean TreesImpact
public boolean ConstantSpeed
public boolean IgnoreTerrain

public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
local thistype this     = allocate()

set .Object             = Object
set .Homing             = null
set .ArcHeight          = 0

set .Position           = vector.create(position.x, position.y, position.z)
set .Acceleration       = vector.create(acceleration.x, acceleration.y, acceleration.z)
set .Velocity           = vector.create(0, 0, 0)
set .Start              = vector.create(position.x, position.y, position.z)
set .Reach              = vector.create(position.x, position.y, position.z)

set .Damage             = 0
set .distance           = 0
set .Ended              = false
set .isUsed             = false
set .UnitsImpact        = false
set .TreesImpact        = false
set .ConstantSpeed      = false
set .IgnoreTerrain      = false

return this
endmethod

public method release takes nothing returns nothing
set Object = null

call Position.destroy()
call Acceleration.destroy()
call Velocity.destroy()
call Start.destroy()
call Reach.destroy()

if not (Model == null) then
call DestroyEffect(Model)
set Model = null
endif

set .distance           = 0
set .Ended              = false
set .isUsed             = false
set .UnitsImpact        = false
set .TreesImpact        = false
set .ConstantSpeed      = false
set .IgnoreTerrain      = false

call this.destroy()
endmethod

public method initiate takes nothing returns nothing
set isUsed = true
set distance = DistanceBetweenVectors(Start, Reach)
endmethod

public static method ber takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
endmethod

public static method ber2 takes nothing returns boolean
return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
endmethod

private method CalculateArc takes nothing returns real
local real y0 = GetCoordinateZ(Start.x, Start.y)
local real y1 = GetCoordinateZ(Reach.x, Reach.y)
local real h  = ArcHeight
local real d  = DistanceBetweenVectors(Start, Reach)
local real x  = DistanceBetweenVectors(Start, Position)
return ParabolaZ2(y0, y1, h, d, x)
endmethod

public method update takes real interval returns nothing
local unit n = null
local destructable t = null
local real angle = 0
local real speed = Velocity.getLength()
local vector v = 0
set currentIndex = this

if distance > 0 and isUsed and not Ended then
set distance = distance - speed

if not (Homing == null) then
set v = vector.create(GetUnitX(Homing), GetUnitY(Homing), GetUnitFlyHeight(Homing) + GetCoordinateZ(GetUnitX(Homing), GetUnitY(Homing)))
set Reach.x = v.x
set Reach.y = v.y
set angle = vector.getAngle(Position, Reach)
set Velocity.x = speed * Cos(angle) * interval
set Velocity.y = speed * Sin(angle) * interval
set speed = (distance / speed) / interval
set Velocity.z = (v.z + GetCoordinateZ(v.x, v.y) - Position.z) / (speed) - 0.5 * Acceleration.z * interval
call v.destroy()

call SetUnitFacing(Object, angle)

if not (GetWidgetLife(Homing) > 0.405) then
set Homing = null
endif
endif

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

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

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

call SetUnitX(Object, Position.x)
call SetUnitY(Object, Position.y)
if ArcHeight > 0 then
call SetUnitFlyHeight(Object, CalculateArc(), 0)
else
call SetUnitFlyHeight(Object, Position.z, 0)
endif

if UnitsImpact then
set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
if not (n == null) then
call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
set Ended = true
set isUsed = false

set n = null
endif
endif

if TreesImpact then
set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
if not (t == null) then
set Ended = true
set isUsed = false
set t = null
endif
endif

elseif distance <= 0 then
set Ended = true
set isUsed = false
endif
endmethod

endstruct

15. ### Tukki

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

Code (vJASS):

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

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

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

So Velocity != Acceleration.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

method update takes nothing returns nothing

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

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

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

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

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

endmethod

Phew!

16. ### dardas

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

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

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

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

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

public method update takes nothing returns nothing
local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) + (.Reach.z - .Position.z) * (.Reach.z - .Position.z) // distance squared
local unit n = null
local destructable t = null
local real angle = 0
local vector v = 0
set currentIndex = this

if dist > 32*32 and isUsed and not Ended or GetWidgetLife(Object) < 0.405 then
if (Homing != null) then
// I should note that this way of homing handling could make the projectile never hit the target :P
// If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
set .Reach.x = GetUnitX(.Homing)
set .Reach.y = GetUnitY(.Homing)
set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
set angle = AngleBetweenVectors(Position, Reach)
//set .Acceleration.z = (.Reach - .Position)/(Pow(.Reach.getLength(), -1)) * TIMEOUT * TIMEOUT // might work, might not x)

call SetUnitFacing(Object, angle * bj_RADTODEG)

if GetWidgetLife(Homing) < 0.405 then
set Homing = null
endif
endif

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

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

call SetUnitX(Object, Position.x)
call SetUnitY(Object, Position.y)
if ArcHeight > 0 then
//call SetUnitFlyHeight(Object, CalculateArc(), 0)
//You said its actually a wrong way to calculate arc,
//
set Velocity.z = (Reach.z - Start.z) / Time / TIMEOUT - Acceleration.z * 0.5 * Time / TIMEOUT
else
call SetUnitFlyHeight(Object, Position.z - GetCoordinateZ(Position.x, Position.y), 0)
endif

if UnitsImpact then
set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
if not (n == null) then
call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
set Ended = true
set isUsed = false

set n = null
endif
endif

if TreesImpact then
set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
if not (t == null) then
set Ended = true
set isUsed = false
set t = null
endif
endif

elseif dist <= 32*32 then
set Ended = true
set isUsed = false
endif
endmethod

17. ### Tukki

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

I'll try to write a post by tomorrow night

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

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

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

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

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

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

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

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

EDIT:

Code (vJASS):

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

call SetUnitFacing(Object, angle * bj_RADTODEG)

if GetWidgetLife(Homing) < 0.405 then
set Homing = null
endif
endif

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

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

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

Also, my guess at the random fast-moving projectiles is that our missile engine is moving the missile as well as your RealityKnockback system.
Which means that the unit is being moved 2x every second.

Last edited: Apr 30, 2011
18. ### dardas

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

library RealityMath requires Vector
globals
public real TimerInterval = 0.032
private location Dummy_Loc = Location(0, 0)
endglobals

function DistanceBetweenVectors takes vector a, vector b returns real
local real dx = b.x - a.x
local real dy = b.y - a.y
return SquareRoot(dx * dx + dy * dy)
endfunction

function AngleBetweenVectors takes vector a, vector b returns real
return Atan2(b.y - a.y, b.x - a.x)
endfunction

function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction

function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction

function GetCoordinateZ takes real x, real y returns real
call MoveLocation(Dummy_Loc, x, y)
return GetLocationZ(Dummy_Loc)
endfunction

function TimeToDistance takes real time, real speed, real interval returns real
return time * (speed / interval)
endfunction

function DistanceToTime takes real distance, real speed, real interval returns real
return distance / (speed / interval)
endfunction
endlibrary

Code (vJASS):

library RealityObject requires RealityMath, Vector, GetNearest, DestructableLib

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

struct RealityObject
static constant real TIMEOUT = 0.032

public static thistype currentIndex = 0

//Missle itself
public unit Object

//Missle vectors
public vector Position
public vector Acceleration
public vector Velocity
public vector Start
public vector Reach

//Missle side effects related
public effect Model
public real Damage

//Arc related
public real ArcHeight

//Homing related
public unit Homing
public real HomingVelocity

//All the booleans..
public boolean Ended
public boolean isUsed
public boolean UnitsImpact
public boolean TreesImpact
public boolean ConstantSpeed
public boolean IgnoreTerrain

public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
local thistype this     = allocate()

set .Object             = Object
set .Homing             = null
set .ArcHeight          = 0

set .Position           = vector.create(position.x, position.y, position.z)
set .Acceleration       = vector.create(acceleration.x * Cos(angle * bj_DEGTORAD), acceleration.y * Sin(angle * bj_DEGTORAD), acceleration.z)
set .Velocity           = vector.create(0, 0, 0)
set .Start              = vector.create(position.x, position.y, position.z)
set .Reach              = vector.create(position.x, position.y, position.z)

set .Damage             = 0
set .ArcHeight          = 0
set .Homing             = null
set .HomingVelocity     = 0

set .Ended              = false
set .isUsed             = false
set .UnitsImpact        = false
set .TreesImpact        = false
set .ConstantSpeed      = false
set .IgnoreTerrain      = false

return this
endmethod

public method release takes nothing returns nothing
set Object = null

call Position.destroy()
call Acceleration.destroy()
call Velocity.destroy()
call Start.destroy()
call Reach.destroy()

if not (Model == null) then
call DestroyEffect(Model)
set Model = null
endif

set .Damage             = 0
set .ArcHeight          = 0
set .Homing             = null
set .HomingVelocity     = 0

set .Ended              = false
set .isUsed             = false
set .UnitsImpact        = false
set .TreesImpact        = false
set .ConstantSpeed      = false
set .IgnoreTerrain      = false

call this.destroy()
endmethod

public method launch takes nothing returns nothing
set isUsed = true
endmethod

public method homing takes unit target, real ConstantVelocity returns nothing
set .Homing = target
set .HomingVelocity = ConstantVelocity
set .Acceleration.x = 0
set .Acceleration.y = 0
set .Acceleration.z = 0
endmethod

public static method ber takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
endmethod

public static method ber2 takes nothing returns boolean
return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
endmethod

private method CalculateArc takes nothing returns real
local real y0 = GetCoordinateZ(Start.x, Start.y)
local real y1 = GetCoordinateZ(Reach.x, Reach.y)
local real h  = ArcHeight
local real d  = DistanceBetweenVectors(Start, Reach)
local real x  = DistanceBetweenVectors(Start, Position)
return ParabolaZ2(y0, y1, h, d, x)
endmethod

public method update takes nothing returns nothing
local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) // distance squared
local unit n = null
local destructable t = null
local real angle = 0
local real Time = 0
local vector v = 0
set currentIndex = this

if dist > 32*32 and isUsed and not Ended or GetWidgetLife(Object) < 0.405 then
set Time = DistanceToTime(DistanceBetweenVectors(Start, Reach), Velocity * Velocity, TIMEOUT)
if (Homing != null) then
// I should note that this way of homing handling could make the projectile never hit the target :P
// If you want the missile to have a constant velocity towards the target: use Velocity instead of .Acceleration, store .Velocity.getLength() somewhere and use that instead of 32.0 ;)
//function DistanceToTime takes real distance, real speed, real interval returns real
set .Reach.x = GetUnitX(.Homing)
set .Reach.y = GetUnitY(.Homing)
set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)
set angle = AngleBetweenVectors(.Position, .Reach)
set .Velocity.x = .HomingVelocity * Cos(angle)
set .Velocity.y = .HomingVelocity * Sin(angle)
set .Acceleration.z = (.Reach - .Position)/(Pow(.Reach.getLength(), -1)) * TIMEOUT * TIMEOUT // might work, might not x)

call SetUnitFacing(Object, angle * bj_RADTODEG)

if GetWidgetLife(Homing) < 0.405 then
set Homing = null
endif
endif

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

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

call SetUnitX(Object, Position.x)
call SetUnitY(Object, Position.y)
call SetUnitFlyHeight(Object, Position.z, 0)
if ArcHeight > 0 then
//call SetUnitFlyHeight(Object, CalculateArc(), 0)
//You said its actually a wrong way to calculate arc,
//
//set Position.z = (Reach.z - Start.z) / Time / TIMEOUT - ArcHeight * 0.5 * Time / TIMEOUT
set Position.z = CalculateArc()
else
set Position.z = Position.z - GetCoordinateZ(Position.x, Position.y)
endif

if UnitsImpact then
set n = GetNearestUnit(Position.x, Position.y, 75, Condition(function RealityObject.ber))
if not (n == null) then
call UnitDamageTarget(Object, n, Damage, false, false, null, null, null)
set Ended = true
set isUsed = false

set n = null
endif
endif

if TreesImpact then
set t = GetNearestDestructable(Position.x, Position.y, 75, Condition(function RealityObject.ber2))
if not (t == null) then
set Ended = true
set isUsed = false
set t = null
endif
endif

elseif dist <= 32*32 then
set Ended = true
set isUsed = false
endif
endmethod

endstruct
endlibrary

Code (vJASS):

library RealityMissle requires RealityMath, RealityObject
//------------------------------------------------------------------------------------------------------------\\
//
//
//
//
//
//
//
//
//
//
//
//------------------------------------------------------------------------------------------------------------\\
//
//  Intro:
//  Â¯Â¯Â¯Â¯Â¯
//      * System Created by dardas @ hiveworkshop.com,
//      * This was created because of a request by Minimage @ hiveworkshop.com.
//
//  Requirements:
//  Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯
//      * RealityMath       - SHOULD be found with this code.
//      * RealityObject     - SHOULD be found with this code.
//
//  Credits:
//  Â¯Â¯Â¯Â¯Â¯Â¯Â¯
//      * Minimage @ hiveworkshop.com > helped testing for bugs
//      * Tukki @ hiveworkshop.com    > helped me pretty much all the time with coding/physics.
//
//  Known bugs:
//  Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯
//      *
//      *
//
//  Known limitations:
//  Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯
//      *
//      *
//
//  Extra Info:
//  Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯Â¯
//      * Started at 15/04/2011
//      * Ended at XX/XX/XXXX
//
//------------------------------------------------------------------------------------------------------------\\

struct Missle
//
public static integer array Index
public static integer InstanceCount = 0
public static integer Dummy_Unit = 'e000'
public static integer Flight_Ability = 'Amrf'
public static timer TimerObject = CreateTimer()
//
public RealityObject Object

public static method create takes player Owner, real x, real y, real height, real angle, real acceleration returns thistype
local thistype this = InstanceCount
local unit missle = CreateUnit(Owner, Dummy_Unit, x, y, angle)

local vector pos = vector.create(x, y, height)
local vector acc = vector.create(acceleration, acceleration, 0)

set .Object = RealityObject.create(missle, pos, angle, acc)
call 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.

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.

19. ### Tukki

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

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

public static thistype currentIndex = 0

//Missle itself
public unit Object

//Missle vectors
public vector Position
public vector Acceleration
public vector Velocity
public vector Start
public vector Reach

//Missle side effects related
public effect Model
public real Damage

//Homing related
public unit Homing
public real HomingVelocity

//All the booleans..
public boolean Ended
public boolean isUsed
public boolean UnitsImpact
public boolean TreesImpact
public boolean ConstantSpeed
public boolean IgnoreTerrain

public static method create takes unit Object, vector position, real angle, vector acceleration returns thistype
local thistype this     = allocate()

set .Object             = Object
set .Homing             = null

set .Position           = vector.create(position.x, position.y, position.z)
set .Acceleration       = vector.create(acceleration.x * Cos(angle * bj_DEGTORAD), acceleration.y * Sin(angle * bj_DEGTORAD), acceleration.z)
set .Velocity           = vector.create(0, 0, 0)
set .Start              = vector.create(position.x, position.y, position.z)
set .Reach              = vector.create(position.x, position.y, position.z)

set .Damage             = 0
set .Homing             = null
set .HomingVelocity     = 0

set .Ended              = false
set .isUsed             = false
set .UnitsImpact        = false
set .TreesImpact        = false
set .ConstantSpeed      = false
set .IgnoreTerrain      = false

return this
endmethod

public method release takes nothing returns nothing
set .Object = null

call .Position.destroy()
call .Acceleration.destroy()
call .Velocity.destroy()
call .Start.destroy()
call .Reach.destroy()

if (.Model != null) then
call DestroyEffect(.Model)
endif

call this.destroy()
endmethod

public method launchArc takes vector target, real baseVelocity returns nothing
local integer dist = GetDistanceBetweenVectors(.Position, target)
local integer tickCount = R2I((dist / baseVelocity) / RealityObject.TIMEOUT)
local real angle = GetAngleBetweenVectors(.Position, target)

set .Acceleration.x = 0
set .Acceleration.y = 0
set .Acceleration.z = RealityObject.GRAVITY * RealityObject.TIMEOUT * RealityObject.TIMEOUT
// acceleration because the missile's trajectory is curved

set .Velocity.x = (target.x - .Position.x) / tickCount
set .Velocity.y = (target.y - .Position.y) / tickCount
set .Velocity.z = (target.z - .Position.z) / tickCount - .Acceleration.z * 0.5 * tickCount

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

set .isUsed = true
endmethod

public method launch takes vector target, real baseVelocity returns nothing
local integer dist = GetDistanceBetweenVectors(.Position, target)
local integer tickCount = R2I((dist / baseVelocity) / RealityObject.TIMEOUT)

set .Acceleration.x = 0
set .Acceleration.y = 0
set .Acceleration.z = 0 // no acceleration because the missile's trajectory is straight

set .Velocity.x = (target.x - .Position.x) / tickCount
set .Velocity.y = (target.y - .Position.y) / tickCount
set .Velocity.z = (target.z - .Position.z) / tickCount

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

set .isUsed = true
endmethod

public method homing takes unit target, real ConstantVelocity returns nothing
set .Homing = target
set .HomingVelocity = ConstantVelocity
set .Acceleration.x = 0
set .Acceleration.y = 0
set .Acceleration.z = 0
endmethod

public static method ber takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitOwnedByPlayer(GetFilterUnit(), GetOwningPlayer(currentIndex.Object))
endmethod

public static method ber2 takes nothing returns boolean
return IsDestructableTree(GetFilterDestructable()) and not IsDestructableDead(GetFilterDestructable())
endmethod

public method update takes nothing returns nothing
local real dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y) // distance squared
local unit n = null
local destructable t = null
local real angle = 0
local integer ticks
local vector v = 0
set currentIndex = this

if dist > 32*32 and .isUsed and not .Ended or GetWidgetLife(.Object) < 0.405 then
if (.Homing != null) then
set .Reach.x = GetUnitX(.Homing)
set .Reach.y = GetUnitY(.Homing)
set .Reach.z = GetCoordinateZ(.Reach.x, .Reach.y) + GetUnitFlyHeight(.Homing)

set dist = (.Reach.x - .Position.x) * (.Reach.x - .Position.x) + (.Reach.y - .Position.y) * (.Reach.y - .Position.y)  // 2d-distance squared
set ticks = R2I((dist / (.HomingVelocity * .HomingVelocity)) / RealityObject.TIMEOUT )

// only changes acceleration because if we changed velocity this way, the missile wouldn't be able to hit the target
// this makes the missile 'dodgeable', though. Since the missile will speed up if the target is in front of it, while it will break when
// it is behind. Making it possible to run around in circles to 'confuse' the missile.
set .Acceleration.z = ((.Reach.z - .Position.z)/ticks) * TIMEOUT * TIMEOUT
set .Acceleration.y = ((.Reach.y - .Position.y)/ticks) * TIMEOUT * TIMEOUT
set .Acceleration.x = ((.Reach.x - .Position.x)/ticks) * TIMEOUT * TIMEOUT

call SetUnitFacing(Object, angle * bj_RADTODEG)

if GetWidgetLife(.Homing) < 0.405 then
set .Homing = null
endif
endif

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

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

call SetUnitX(.Object, .Position.x)
call SetUnitY(.Object, .Position.y)

// If .IgnoreTerrain flag is set, the missile can go through terrain, if not, the missile flies at .Position.z height above ground
if (.IgnoreTerrain) then
call SetUnitFlyHeight(.Object, .Position.z - GetCoordinateZ(.Position.x, .Position.y), 0)
else
call SetUnitFlyHeight(.Object, .Position.z, 0)
endif

if .UnitsImpact then
set n = GetNearestUnit(.Position.x, .Position.y, 75, Condition(function RealityObject.ber))
if not (n == null) then
call UnitDamageTarget(.Object, n, .Damage, false, false, null, null, null)
set .Ended = true
set .isUsed = false

set n = null
endif
endif

if .TreesImpact then
set t = GetNearestDestructable(.Position.x, .Position.y, 75, Condition(function RealityObject.ber2))
if not (t == null) then
set .Ended = true
set .isUsed = false
set t = null
endif
endif
elseif dist <= 32*32 then
set .Ended = true
set .isUsed = false
endif
endmethod
endstruct

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

`public method launchArc takes vector target, real baseSpeed returns nothing`

They set up velocity and acceleration accordingly.

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

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

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

The indexing seems to work properly, I'll do some testing on it later on.
Until then!

Last edited: May 3, 2011
20. ### dardas

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

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

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

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

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

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

Thank you for you're help so far.