ID:154592
 
After considerable thought, I realised that BYOND simply isn't yet equipped for complex mathematical calculations. Everyone can multiply, divide, or even get a modulus of, a number. But not everyone can get the cosine and return a number in radians, then convert those radians into your average everyday degrees.

That's what problem I faced with s_missile. Al, much to my delight, helped me out with what was then SPL Missile, telling me a variety of mathematical formulae, even offering some code.

The worst part was, the code worked... but only in two directions. Not wanting to bother Al again (hey, he only gets a little snippet of online time every little while anyway...), I've decided to try a few things a little more unique and a lot more exciting.


Essentially, SPL Missile had four procs; spl_missile1(), spl_missile2(), spl_missile3(), and spl_missile4(). Talk about obfuscated... now people had to remember which number did what! Respectively, those functions were to fire an icon, to fire an icon and icon_state, to fire an object of a specified prototype, and to fire an actual mob or obj that exists.

Now, thanks to isicon(), I've merged all of these procs into one convenient source; s_missile(). The usages thereof are as follows:

s_missile(icon,trg,lag=1,homing=0)
s_missile(icon,icon_state,trg,lag=1,homing=0)
s_missile(type,trg,lag=1,homing=0)
s_missile(ref,trg,lag=1,homing=0)


The main problem that balked me, however, was how to get the linear movement in walk_line() to work. Originally, the plan was to determine the tangent from the source to the destination, convert that to degrees, then move the missile in that direction.

But I've found a much more apt solution; I simply use a variation on Guy's principle of rise over run; I constantly add the rise/run to a variable called _process, and then I subtract the rounded value thereof from the variable. The rounded value, then, is compared, and if 0, it moves horizontally, if 1 it moves diagonally, and if 2 it moves diagonally and tells itself to move vertically next turn (and so on for the other numbers above two, with vertical moves divided between before and after the diagonal move). This is continually applied until the missile reaches its destination.


Here's hoping that I can pull it off!
But I've found a much more apt solution; I simply use a variation on Guy's principle of rise over run; I constantly add the rise/run to a variable called _process, and then I subtract the rounded value thereof from the variable. The rounded value, then, is compared, and if 0, it moves horizontally, if 1 it moves diagonally, and if 2 it moves diagonally and tells itself to move vertically next turn (and so on for the other numbers above two, with vertical moves divided between before and after the diagonal move). This is continually applied until the missile reaches its destination.

You don't need to reinvent the wheel: In the 60:s a matematician named Bresenham wrote a line drawing algorithm, and it's perfectly applicable in this case. I found some code in a book, and rewrote it to Byond:

proc
        send_missile(source, target, delay)
                if(!source||!target) return 0
                var
                        x0;y0;x1;y1
                        dx;dy
                        x_inc;y_inc;
                        error; i

                var/turf
                        T; T2

                T=source:loc
                x0=T.x; y0=T.y

                if(!istype(target,/turf))
                        T2=target:loc
                else
                        T2=target
                x1=T2.x; y1=T2.y

                dx=x1-x0; dy=y1-y0

                if(dx>=0)
                        x_inc=1
                else
                        x_inc=-1
                        dx=-dx

                if(dy>=0)
                        y_inc=1
                else
                        y_inc=-1
                        dy=-dy

                // Move the missile based on which delta is greater.
                if(dx>dy)
                        for(i=1,i<=dx,i++)
                                error+=dy
                                if(error>=dx)
                                        error-=dx
                                        y0+=y_inc
                                x0+=x_inc
                                source:Move(locate(x0,y0,source:z))
                                sleep(delay)
                else
                        for(i=1,i<=dy,i++)
                                error+=dx
                                if(error>0)
                                        error-=dy
                                        x0+=x_inc
                                y0+=y_inc
                                source:Move(locate(x0,y0,source:z))
                                sleep(delay)


The only problem occurs when the missile has to travel many steps on one axis, but only one step in the other. I'm sure you can optimize it.

/Andreas
In response to Gazoot
You don't need to reinvent the wheel:

Well, actually, as far as I'm thinking, this routine would be fairly easy to make. Besides, the wheel is easy to invent, too! =)

In the 60:s a matematician named Bresenham wrote a line drawing algorithm, and it's perfectly applicable in this case. I found some code in a book, and rewrote it to Byond:

[a Freudian snip]

The only problem occurs when the missile has to travel many steps on one axis, but only one step in the other. I'm sure you can optimize it.

Interesting! I'll have to look into it when I get home... my method will have to make a variation on that theme, because to follow DM-integral walk_to format, it has to return immediately then process in the background through spawn. And I also want to give it the capability of homing, if the target moves.

On a side note; is that what you use for Golf?
In response to Spuzzum
On 12/14/00 1:45 pm Spuzzum wrote (about missiles):
On a side note; is that what you use for Golf?

No, when I look back, I think I wrote golf without thinking at all. :) I have to rewrite it with better physics, using the (warning: advertising alert) TRIG LIBRARY!
If I'm using the same conditions during the stroke, I might use the line routine. But I'm thinking about wind changes and other real-time events. We'll see!

/Andreas
In response to Gazoot
On 12/15/00 5:36 am Gazoot. wrote:


I have to rewrite it with better physics, using the (warning: advertising alert) TRIG LIBRARY!

Heh. I'm eager to get the Resource InfoCenter up and running so you all can put your nifty creations there without worrying about them getting lost in the manifolds of this forum. Very soon!
In response to Tom H.
Heh. I'm eager to get the Resource InfoCenter up and running so you all can put your nifty creations there without worrying about them getting lost in the manifolds of this forum. Very soon!

Soon as in today soon? =)
In response to Spuzzum
On 12/21/00 1:56 pm Spuzzum wrote:
Heh. I'm eager to get the Resource InfoCenter up and running so you all can put your nifty creations there without worrying about them getting lost in the manifolds of this forum. Very soon!

Soon as in today soon? =)

Hopefully! And Dan has a whole slate of cool stuff that's pretty much ready to go too. Busy busy...