HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

"Boomerang" Spell Math

09-15-2009, 02:50 AM#1
Gringill
(OT: Alright so right off the bat I feel stupid posting here in comparison to everyone else's threads, especially because I joined today and this is my first post. But I have been lurking for about 5 years without making an account, at THW, here, and sear before that went down. So I feel like I know people but I am still the "look at this noob..." of the thread so >.>)

Anyways, I am currently making a spell that I could most easily describe as a boomerang but requires more explanation. Your hero targets a point and effectively moves in a circle starting where he is at, going to where you targeted, and then back to where you casted it from (see fantastic paint image). In addition all enemy units within range get picked up and move along with the hero back to where he casted from. The hero will be hidden this whole time and will be symbolized probably by vex's dummy .mdl with a sfx attached. I have done things similar to this but I cannot for the life of me figure out how I would do the 'formula' for moving the hero. I have the struct, loop, everything setup except for where/how to move the hero. I looked at the boomerang spell that is submitted right now to get somewhat of an idea as to how I would go about this but it moved in an oval and it was kind of hard to understand as just a block of code.

So basically can someone point me to a better example/tutorial of this, or could someone help explain how I would go about doing this. I realize this is a pretty broad topic and requires a bit of effort to explain but I would appreciate any links to articles aswell (I am not sure what to google either otherwise I would have, "find next point in circle path" etc. dooesn't exactly bring in the most relevant topics =p.
09-15-2009, 05:14 AM#2
Vexorian
Hmnn,
x1 = hero x, y1 = hero y .
x2 = target x, y2 = target y .

We need the center for that circle, as you can see it is just the middle point:

cx = (x1+x2)/2
cy = (y1+y2)/2

The radius of the circle is Distance(cx,cy, x1,x2)

Then you just have to make the actual circle, easiest with polar projections.

The first ( and last) polar projection angle would be: Atan2( y1-cy, x1-cx), so you then go and increment this angle until you have a circle. For each of these iterations get:
x = cx+radius*Cos(ang)
y = cy+radius*Sin(ang)

And you shall get a point of the circle...
09-15-2009, 07:53 AM#3
PipeDream
There's a cute algorithm for drawing circles. It's not better than what Vex wrote, in fact it really draws an ellipse.

e = sqrt(2(1- cos(2pi / period)))

x1 = x0 - e*(y0 - cy)
y1 = y0 + e*(x1 - cx) // replacing x1 with x0 here will make a spiral instead of an ellipse

Period is the number of steps you want it to take to go one full CCW circle. x0,y0 is the current position and x1,y1 is the next position.
09-15-2009, 09:19 PM#4
Gringill
Alright Vex that is working pretty well and I understand it ok now =p. But there is one thing, with the rough-draft code I have right now:

Collapse JASS:
library Jolt initializer Init

globals
    private Jolt array JOLT
    private integer total = 0
endglobals

//================================================================================

struct Jolt
unit        c
real        x
real        y
real        x2
real        y2
real        cx
real        cy
real        r
real        m
group       g
static timer Tim = null

static method Loop takes nothing returns nothing
    local Jolt j
    local integer i = 0
    local real CenterX
    local real CenterY
    loop
        exitwhen i >= total
        set j = JOLT[i]
        //
        if Atan2( j.y-j.cy, j.x-j.cx) != bj_DEGTORAD*AngleBetweenPoints(Location(j.cx,j.cy),Location(GetUnitX(j.c),GetUnitY(j.c))) then
            call SetUnitX(j.c, j.cx+j.r*Cos(j.m))
            call SetUnitY(j.c, j.cy+j.r*Sin(j.m))
            set j.m = j.m+.1
            call BJDebugMsg("Atan2"+R2S(Atan2( j.y-j.cy, j.x-j.cx)))
            call BJDebugMsg("Angle"+R2S(bj_DEGTORAD*AngleBetweenPoints(Location(j.cx,j.cy),Location(GetUnitX(j.c),GetUnitY(j.c)))))
        else
            set JOLT[i] = JOLT[total-1]
            set total = total - 1
            call j.destroy()
        endif
        //
        set i = i + 1
    endloop
    
    if total == 0 then
        call PauseTimer(j.Tim)
    endif
    
endmethod

method onDestroy takes nothing returns nothing
    //
endmethod

endstruct

function CreateJolt takes unit C, real X2, real Y2 returns nothing
    local Jolt j
    local real x
    local real y  
        
    set j           = Jolt.create()
    set j.g         = CreateGroup()
    set j.c         = C
    set j.x         = GetUnitX(j.c)
    set j.y         = GetUnitY(j.c)
    set j.x2        = X2
    set j.y2        = Y2
    set j.cx        = (j.x+j.x2)/2   
    set j.cy        = (j.y+j.y2)/2
    set j.m         = Atan2( j.y-j.cy, j.x-j.cx)
    
    //Get Dist btwn pnts
    set x = j.cx - j.x
    set y = j.cy - j.y
    set j.r = SquareRoot(x * x + y * y)
    
    call SetUnitX(j.c, j.cx+j.r*Cos(j.m))
    call SetUnitY(j.c, j.cy+j.r*Sin(j.m))
    
    set JOLT[total] = j
    if total == 0 then
        call TimerStart(Jolt.Tim, .3, true, function Jolt.Loop)
    endif
    set total = total + 1
endfunction

private function Init takes nothing returns nothing
    set Jolt.Tim = CreateTimer()
endfunction
endlibrary

This line
Collapse JASS:
if Atan2( j.y-j.cy, j.x-j.cx) != bj_DEGTORAD*AngleBetweenPoints(Location(j.cx,j.cy),Location(GetUnitX(j.c),GetUnitY(j.c))) then
never fires it's Else, becase the angle is off by like .04 when it gets back around to about where it should stop =/. I think this is happening because I don't fully undestand the (ang) part. Right now every tick I am changing the angle by + .1, is there a number I can put there that would make the angle between the points the same as the Atan2 function that it should be by the time it goes 360 around?

Or should I just check if the angle is within 1 degree. Otherwise it works fine =p, it just keeps going in a circle forever. And I realize I am using a bj I just threw it in there to make testing easier, I will remove it later.

EDIT:
j.c - is the hero (unit)
j.x - the heroes X
j.y - the heroes Y
x2 - the spell targets X
y2 - the spell targets Y
cx - the center x
cy - the center y
r - the radius
m - the angle that is changed every iteration
g - unneeded for this explanation
09-15-2009, 10:10 PM#5
Vexorian
Quote:
never fires it's Else, becase the angle is off by like .04 when it gets back around to about where it should stop =/
That's because reals are just approximations, instead of doing != on the angle itself, have a limited number of iterations. Then given the number of iterations T, you can calculate how much to increase the angle in each iteration ( 2*pi / T)
09-16-2009, 10:04 PM#6
Gringill
EDIT: O man I got pwnt hard, just realized I was inputting my increment as a degree instead of a radian, lol. Works now, thanks for all the help guys.