ID:152796
 
Alright, after talking to Crashed, DAU, and Unknown Person I think that pixel movement might be the best way for my beam system.

powers
var/offensive = 1
var/icon
var/icon_state
heatbeam
ppcost = 1
name = "Heat Beam"
icon = 'HeatBeam.dmi'
icon_state = "base"

mob
verb
Power1()
set hidden = 1
if(src.Power1)
var/powers/s = text2path("/powers/[ckey(src.Power1)]")
var/powers/a = new s
a.activate(src,src.target)

powers
proc
activate(mob/o,mob/m)
if(!src.offensive)
src.Use(o)
return
var
damage=10
var/icon/_icon = src.icon
var/obj/b = icon(_icon,src.icon_state)
step_to(b,m)
if(damage<1)damage=1
if(m in oview(o,world.view))
o<<"You used [name] on [m] for [damage] damage!"
m<<"[o] uses [name] on you for [damage] damage!"
m.hp-=damage
o.deathcheck(m)


Well, as they pointed out, /icon is only graphical therefore it won't move properly. Crashed gave me the suggestion to use Pixel movement and directed me to Theodis' altmove demo. I saw that and found it really cool about the 360 degree movement. So basically I don't really know how I would use trig. to find out what angle the beam would need to be. I'm thinking that I would need to use the distance formula between the player and the target, but I don't know how to do this exactly.

I also I looked at the latest article from Programming Articles which helped me understand pixel movement. If anyone has any suggestions on how to do this, I will be intrested in hearing it.
To get an object to move in a straight path from a source target to a destination one you shouldn't even need to bother with trig just need to work with vectors.

A vector if you don't know is simply a way of representing a direction and a magnitude(most likely speed). Which will be used to determine how much you move the projectile each tick. To make things more robust it's best to build a Vector datum to work with

Vector
/*
New will have two ways to construct a vector.
Directly with 2 numbers or with a source
and destination vector to generate a direction vector
form the soure to the destination */


var
//Vector components
x
y

New(atom/a, atom/b)
if(isnum(a) && isnum(b)) // The first type of contructor for the vector
x = a
y = b
else if(istype(a) && istype(b)) // The second type of constructor for the vector
x = b.x - a.x
y = b.y - a.y

proc
/* Magnitude returns the "length" of the vector */
Magnitude()
return sqrt(x*x+y*y)
/*
The normalize proc maintains the vectors direction but makes it
have a magnitude of 1 which is very useful when you want to scale it.
This is done by dividing each of the components by the total length
of the vector. */

Normalize()
var/mag = Magnitude()
x /= mag
y /= mag
/*
Scale will stretch the magnitude of the vector */

Scale(val)
x *= val
y *= val


Note this is quite a basic implementation for Vector. There is a whole lot more useful stuff you can do with them however I'm trying to keep this simple.

Now for the beam you simply build a Vector from it's start to finish. Normalize it and scale it depending on how fast you want it to move. Then each tick move the beam by the components of the resulting vector

obj/Beam
icon = 'HeatBeam.dmi'
icon_state = "base"

//start is the starting location
//end is the ending location
//speed is how many pixels per tick the beam moves
New(start, end, speed = 10)
//This will be an asyncronous call so spawn all the logic so the
//calling proc doesn't get blocked.
spawn(0)
//Create our direction vector
var/Vector/v = new(start,end)
v.Normalize()
v.Scale(speed)

//Initialize start and move along the vector until the end is reached
//(or the beam has somehow fallen off the map)
loc = start
while(loc && loc != end)
pixel_x += v.x
pixel_y += v.y
//If the pixel offsets have moved past a tile move the beam
//object and update the pixel offsets
while(pixel_x < -16)
loc = get_step(loc,WEST)
pixel_x += 32
while(pixel_x >= 16)
loc = get_step(loc,EAST)
pixel_x -= 32
while(pixel_y < -16)
loc = get_step(loc,SOUTH)
pixel_y += 32
while(pixel_y >= 16)
loc = get_step(loc,NORTH)
pixel_y -= 32
sleep(1) // Wait a tick


For the end location you need to pass a turf or the beam will never reach the end due to the fact that it's loc is a turf.

[Edit: Whoops made a mistake and forgot to make the right changes when I copied the EAST WEST section of the bottom of the code to make the NORTH/SOUTH stuff :P.]
In response to Theodis
I've taken the pixel based vector approach a step further with my PixelProjectiles library. If the vector is large enough to skip over tiles, the library casts a ray between its current position and next location to provide accurate hit detection. The library should be available on BYONDscape soon. :)
In response to Shadowdarke
I was playing around in the demo (by holding the mouse and watching all the balls fly) and at one point I got this error:

Invalid destination: FirePixelProjectile(DeathAwaitsU, , /obj/sd_px_projectile)