• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] formula for a boomerang

Status
Not open for further replies.

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
No, nobody can, as there is no formula for a "U boomerang".
I however can tell you how to go about making a boomerang. It is barically comprised of 3 parts.

Part 1 can be a pretty much straight line to the target point.
Part 2 is an arc of some form though atleast 180 if not more degrees.
Part 3 is another straight line back to caster which should home in to a degree if the caster is capable of moving.

Each part has its own rules and formula.
 
Level 11
Joined
Apr 6, 2008
Messages
760
ok thx Dsg, but if i want something to Arc like (not Z arc)

attachment.php
 

Attachments

  • Arch.JPG
    Arch.JPG
    2.4 KB · Views: 503
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
Cos or Sin.

Another option is to have two velocities, one pointing side ways and one pointing forward-backward, in relation to the arc (as in, side ways isn't equal to X and front-back isn't equal to Y, it's in relation to the movement). Then the 'Y' velocity acts like gravity.
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
You coult try 2 parabolas, 1 with a negative x2 and one with a positive x2
(Positive is a 'valley' parabola (dont know the word), which could be the first part, and as soon as you think the time has come ( test with it), you can go to the next (negative) parabola which is a 'mountain' one, if you apply these to the x- and y-axis, and then with some Cos/Sin calculation, you might get the desired effect,
Though i got this idea, i might not give you an example due to my minor knowledge of maths,,
But i think you should do it this way:
1) Check what parabola to use.
2) Calculate x- and y- coordinates with it. (which will be straight on y-axis)
3) Get the position of the caster and use it as Location(0,0) to calculate with Cos and Sin the real x- and y-coordinates
(With a normal parabola it will always go 'straight' with y-axis, but you want it to go to the facing of the caster, or the angle between point and caster, so you use Cos/Sin)
4) Move Boomerang to the new point, increase the 'x' value you use for the parabola function(s),,

ExamplePic:

Blue = Negative Parabola Func
Green = Positive Parabola Func
Red = Unused Part of Positive ParabolaFunc
Black = Caster
BOOMERANG.jpg

Hope you get what i mean and hope you can use this for your boomerang spell/system, or whatever you use it for ;)
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
Well, that will take some time,, and i have to do some maths myself before i can show you,, i hope i can do some tonight and show you tomorrow,,
I will continue on my schoolwork now and do it right after i finish that ;)
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
It gave me a headache,, and even confused me for some time ><
But here it is,,
(Beware, it is HUGE!)

JASS:
function Parabola takes real MaxDist, boolean Positive, real x returns real
 if Positive then
  // y = x*x - MaxDist
  return x*x + MaxDist
 else
  return -1*(x*x) - MaxDist
 endif
endfunction
function Differentiate takes real MaxDist, boolean Positive, real Max returns real 
 local real x
 // function = x*x +- MaxDist
 if Positive then
  // function = x*x + MaxDist
  // Differentiated = 2*x // just learned that at school! =D
  // now we have to find the 'x' value that fits our 'Max' value
  // This max value is the 'coefficient' for the formula of the ramp
  // for further explanation (in good english, which is not my native language)
  // google/wikipedia for differentiation of functions and what it does
  set x = Max/2
 else
  // function = -1* (x*x) - MaxDist
  // Differentiated = -1 * 2*x = -2*x
  // read comment above the 'else'
  set x = Max/-2
 endif
 return x
endfunction
// IF YOU CHANGE THE PARABOLA FUNcTION, YOU HAVE TO REDO THE ABOVE FUNCTION! ( DIFFERENTIATE IT AGAIN )
function DifferentiateYCalc takes real MaxDist, boolean Positive, real MaxDiff returns real
 local real a
 local real b
 local real y
 if Positive then
  // function = x*x + MaxDist
  // Dfunc = 2x
  // DFunc = 2* MaxDiff
  set a = 2*MaxDiff
  // y = a*x + b
  set b = Parabola(MaxDist, Positive, x) - a*x 
  // fill in to calculate 'a' and 'b'
  // now fill in OUR x,,
  set y = a * x + b
 else
  set a = -2 *MaxDiff
  set b = Parabola(MaxDist, Positive, x) - a*x
  set y = a*x + b
 endif
 return y
endfunction
struct
 unit boomerang
 real MaxDifferentiatedX
 real x
 real y
 real MaxBoomerangDistance
 real cos
 real sin
 boolean PositiveBool
 boolean NegativeParaFirst
endstruct
function Loop takes nothing returns nothing
 // loop through structs
 if dat.PositiveBool then
  set dat.x = dat.x + 1
  // or - 1, according to the side you want the boomerang to go to
  // decrease or increase this number (the  '1' ) to make the boomerang go faster/slower
  set dat.y = Parabola(dat.MaxBoomerangDistance/2, dat.PositiveBool, dat.x)
  // recalculate coordinates to Warcraft coordinates, use the given 'dat.cos' and 'dat.sin' for it
//  if dat.yx >= DifferentiateYCalc(dat.MaxBoomerangDistance/2, dat.PositiveBool, dat.MaxDifferentiatedX) then 
   // change to other parabola
   set dat.PositiveBool = false
  endif
 else
  set dat.x = dat.x - 1
  // this one has to be the exact opposite of the one under the 'then'
  set dat.y = Parabola(dat.MaxBoomerangDistance/2, dat.PositiveBool, dat.x)
  // recalculated coordinates
  if dat.y <= DifferentiateYCalc(dat.MaxBoomerangDistance/2, dat.PositiveBool, dat.MaxDifferentiatedX) then 
   if dat.NegativeParaFirst = true then
    set dat.PositiveBool = true
    set dat.NegativeParaFirst = false
   else
    // END THE SPELL HERE
   endif
  endif
 
 endif
endfunction
function Create takes nothing returns nothing
 // initialize struct,, I call it 'dat' now,,
 set dat.MaxBoomerangDistance = 500 // Total distance the boomerang will go
 set dat.PositiveBool = false // we start with the 'valley' parabola
 set dat.NegativeParaFirst = true
 set dat.cos = Cos(//angle here
 set dat.sin = Sin(//angle here
 set dat.x = 0
 set dat.y = 0
 set dat.MaxDifferentiatedX = Differentiate(dat.MaxBoomerangDistance/2, dat.PositiveBool, -500) // the -500 means that the.. (next line)
 // .. coefficient of the formula that calculates the RAMP of the parabola, is -500, which means it is a really steep line.. (next line)
 // .. almost vertical, which means we can go to the next parabola safely
 set x = Parabola(dat.MaxBoomerangDistance/2, dat.PositiveBool, Differentiate(dat.MaxBoomerangDistance/2, dat.PositiveBool, 0)
 // This x is the 'x' in the co-ordinate system of the 'top' of the first parabola, the point where the caster is,,
 // if we fill this line in in the Parabola Function, we get our Startin 'y' in the co-ordinate system
 // these values have to be recalculated to become Warcraft Coordinates
 set dat.y = Parabola(dat.MaxBoomerangDistance/2, dat.PositiveBool, dat.x)
 // returns, as stated above, our 'y' coordinate
 
 // Timer Start stuff
endfunction

P.S. i made this without using JNGP, since it is really slow on this computer and this is most math, and not Jass,,
 
Level 14
Joined
Nov 18, 2007
Messages
816
Hmm, i took a polar approach, i think it might look better.
Here goes:
JASS:
library Boomerang uses GroupUtils // maybe you need an initializer and requirements; add them here
    
    // Credits:
    //  - Rising_Dusk for his GroupUtils library
    //  - Vexorian for JassHelper
    //  - PipeDream for Grimoire
    //  - PitzerMike and MindWorX for JassNewGenPack
    //  - SFilip for TESH

    globals
        private constant    real                    TICK                    = 1./32
        private constant    integer                 AID                     = 'A000'
        private constant    integer                 DUMMY_ID                = 'h000'
        private constant    real                    BOOMERANG_SPEED         = 600.
        private             real            array   DAMAGE                  //
        private constant    real                    BOOMERANG_COLLSIZE      = 96.
        private constant    real                    BOOMERANG_SIZE          = 1.25
        private constant    real                    BOOMERANG_HEIGHT        = 64.
        private constant    string                  HIT_FX                  = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
        private constant    string                  HIT_FX_ATTPT            = "chest"
        private constant    attacktype              ATTACK_TYPE             = ATTACK_TYPE_MAGIC
        private constant    damagetype              DAMAGE_TYPE             = DAMAGE_TYPE_MAGIC
    endglobals
    
    private function SetUpDAMAGE takes nothing returns nothing
        set DAMAGE[1]=100.
        set DAMAGE[2]=150.
        set DAMAGE[3]=200.
    endfunction
    
    private function Damage takes integer level returns real
        return DAMAGE[level]
    endfunction
    
    private keyword Data
    
    globals
        private location l
        private Data tmps
    endglobals

    private struct Data
        unit c // caster
        unit dum // boomerang dummy
        integer level
        real d // planned distance
        real a // current angle
        real p // periodic angle change
        real x // x-coord of launch point
        real y // y-coord
        real tx // targeted x-coord
        real ty // targeted y-coord
        real f // base-angle
        group g // group holding already damaged enemies
        
        static boolexpr DamageFilter
        
        private integer i

        private static thistype array Structs
        private static timer T=CreateTimer()
        private static integer Count=0
        
        private static method DamageFilterFunc takes nothing returns boolean
        local unit u=GetFilterUnit()
            if IsUnitType(u, UNIT_TYPE_DEAD)==false and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false and (not IsUnitInGroup(u, tmps.g)) and IsUnitEnemy(u, GetOwningPlayer(tmps.c)) then
                if UnitDamageTarget(tmps.c, u, Damage(tmps.level), false, false, ATTACK_TYPE, DAMAGE_TYPE, null) then
                    call DestroyEffect(AddSpecialEffectTarget(HIT_FX, u, HIT_FX_ATTPT))
                    call GroupAddUnit(tmps.g, u)
                endif
            endif
            set u=null
            return false
        endmethod
        
        method onDestroy takes nothing returns nothing
            set .c=null
            call KillUnit(.dum)
            call ShowUnit(.dum, false)
            set .dum=null
            call ReleaseGroup(.g)
            // clean your struct here
            set thistype.Count=thistype.Count-1
            set thistype.Structs[.i]=thistype.Structs[thistype.Count]
            set thistype.Structs[.i].i=.i
            if thistype.Count==0 then
                call PauseTimer(thistype.T)
            endif
        endmethod

        private static method Callback takes nothing returns nothing
        local integer i=thistype.Count-1
        local thistype s
        local real r
        local real x
        local real y
            loop
                exitwhen i<0
                set s=thistype.Structs[i]
                // make the boomerang home, even if the caster moves
                set s.x=GetUnitX(s.c)
                set s.y=GetUnitY(s.c)
                set s.d=SquareRoot( ((s.tx-s.x)*(s.tx-s.x))+((s.ty-s.y)*(s.ty-s.y)) )
                set s.p=TICK*((bj_PI*BOOMERANG_SPEED)/(4*s.d))
                set s.f=Atan2(s.ty-s.y, s.tx-s.x)-(bj_PI/4)
                // functions for moving the boomerang:
                // r(a)=distance*Sin(2*a) // a is the angle and goes from 90 to 0 // distance from center point
                // x(a)=Cos(a)*r(a) // x and y coordinates in relation to the location it was cast.
                // y(a)=Sin(a)*r(a) // note that i inlined some things to allow casting the boomerang in all directions from any point on the map
                set r=(s.d*Sin(2*s.a))
                set x=s.x+(Cos(s.a+s.f)*r)
                set y=s.y+(Sin(s.a+s.f)*r)
                
                call SetUnitX(s.dum, x)
                call SetUnitY(s.dum, y)
                
                set tmps=s
                call GroupEnumUnitsInRange(ENUM_GROUP, x, y, BOOMERANG_COLLSIZE, Data.DamageFilter)
                set s.a=s.a-s.p
                if s.a<=0 then
                    call s.destroy()
                endif
                // do your things here, dont forget to call s.destroy() somewhen
                set i=i-1
            endloop
        endmethod
    
        static method create takes nothing returns Data
        local thistype s=thistype.allocate()
            set l=GetSpellTargetLoc()
            set s.tx=GetLocationX(l)
            set s.ty=GetLocationY(l)
            call RemoveLocation(l)
            set l=null
            set s.c=GetTriggerUnit()
            set s.x=GetUnitX(s.c)
            set s.y=GetUnitY(s.c)
            set s.dum=CreateUnit(GetOwningPlayer(s.c), DUMMY_ID, s.x, s.y, 0)
            call SetUnitX(s.dum, s.x)
            call SetUnitY(s.dum, s.y)
            call UnitAddAbility(s.dum, 'Amrf')
            call UnitRemoveAbility(s.dum, 'Amrf')
            call SetUnitScale(s.dum, BOOMERANG_SIZE, BOOMERANG_SIZE, BOOMERANG_SIZE)
            call SetUnitFlyHeight(s.dum, BOOMERANG_HEIGHT, 0)
            set s.level=GetUnitAbilityLevel(s.c, AID)
            set s.d=SquareRoot( ((s.tx-s.x)*(s.tx-s.x))+((s.ty-s.y)*(s.ty-s.y)) )
            set s.a=(bj_PI/2)
            set s.p=TICK*((bj_PI*BOOMERANG_SPEED)/(4*s.d))
            set s.f=Atan2(s.ty-s.y, s.tx-s.x)-(bj_PI/4)
            set s.g=NewGroup()
            
            // initialize the struct here
            set thistype.Structs[thistype.Count]=s
            set s.i=thistype.Count
            if thistype.Count==0 then
                call TimerStart(thistype.T, TICK, true, function thistype.Callback)
            endif
            set thistype.Count=thistype.Count+1
            return s
        endmethod
        
        private static method onInit takes nothing returns nothing
        local trigger t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddAction(t, function Data.create)
            
            set Data.DamageFilter=Condition(function Data.DamageFilterFunc)
            
            call SetUpDAMAGE()
        endmethod
    endstruct

endlibrary

Also, i attached a testmap. Im not so sure, you might want to switch the boomerang itself to xe. I think that would be far better. This is merely a quick'n'dirty implementation.
 

Attachments

  • Boomerang_1.0.0.w3x
    22.3 KB · Views: 59
Level 16
Joined
Oct 12, 2008
Messages
1,570
Now i think of it: There is a way easier way! In my calculator, which i use for school, are standard formulas, for parabolas, other stuff, and CIRCLES,,
Here is the one that seems most handy to me
((X-H)2)/ A2 + ((Y-K)2)/B2
CIRKEL FORMULE.jpg

Explanation:
H = The difference on 'x' axis, so if you put H=2, the circle will move 2 coordinates to the right, according to co-ordinate system,,
K = The same as 'H', only for 'y' axis, so if i put K=2, the circle will move 2 coordinates up, according to the co-ordinate system

A = Half of the width of the full circle, If i put 1 here, the width of the circle at the broadest point is 1*2 = 2

B = Same as 'A' only for Height. If you put 5 here, the height on from highest point to lowest point will be 5*2 = 10

Recommended settings:
H = 0
K = <Some value>
A = 1
B = K
(B has to be K to make the circle start/end on position of the caster.)

Hope this helps more ;)

EDIT: Here is a picture with explanations of the variables and pictures of how it would look:
BStap1.jpg
BStap2.jpg
BStap3.jpg
BStap4.jpg
BStap5.jpg
BStap6.jpg
 
Last edited:
Level 16
Joined
Oct 12, 2008
Messages
1,570
Nope,,
Nothing at all,,
But the thing is, this section is to help other people, not to use their ideas for your own spells,
And you even credited Ciebron for the idea, which seems right to me, but i thought it was a little strange, that is all,,
 
Status
Not open for further replies.
Top