PixelProjectiles by Shadowdarke
Pixel based directional projectiles
14 fans · Created May 11 2005
Pixel Projectiles provides a simple interface for customizable directional projectiles that can fire at any angle, speed, and duration between updates and guarantees accurate hits.

Hooks are provided to allow you to define:
  • how hits are determined.

  • what happens when the projectile hits an atom.

  • what happens when the projectile reachs max range without a hit

  • Also includes a handy proc for spread shots. Fire an even spread or random shrapnel within the cone of fire with one easy proc call.

    Version 3: (04-04-2006)
  • Fixed a bug that caused high velocity projectiles to occasionally miss. Kudos to DarkCampainger for not only noticing it, but also finding the fix! (DarkCampainger, XxDohxX)
Very efficient.
How could you make so that the projectile's icon state changes according to the direction the projectile (arrow in this case) is flying?
(note that any tabs, spaces and indentations are represented by a ">>", one set of two ">" is == one indentation)

Hi I have a suggestion for a further control over the projectile :

I was fiddling with the handling of Hit and found that using a extra variable for a projectile
passThrough = 2

Now on Hit(atom/A) i had some small code like :
if(A.density == 1)
if(src.passThrough >= 1)
src.passThrough -= 1

what this will do is when it enters a dense object it will deduct from passThrough, if passThrough is 0 then it deletes the projectile..

this allows projectiles to pass through dense objects X times. and a value of 0.5 for passThrough will allow only entry into a dense object, but not exit.

Firstly; Shadowdarke, this is an amazing library. I love it. Truly I do.

Anyway, I have one small suggestion (that I've implemented in to my own game): owner's direction!

FirePixelProjectile(owner, "dir[owner.dir]", /obj/sd_px_projectile/)

proc/FirePixelProjectile(atom/owner, destination, proj_type = \
/* fires a pixel based projectile of type proj_type from owner to
destination. Destination may be a turf or angle of fire. */

if(!owner) return
var/obj/sd_px_projectile/P = new proj_type()
P.owner = owner
P.loc = P.TurfOf(owner)
P.pixel_x =
P.pixel_y =

if(destination=="4") //East
else if(destination=="5") //Northeast
else if(destination=="1") //North
else if(destination=="9") //Northwest
else if(destination=="8") //West
else if(destination=="10") //Southwest
else if(destination=="2") //South
else if(destination=="6") //South east
if(isnum(destination)) // an angle
P.dx = cos(destination) * P.speed
P.dy = sin(destination) * P.speed

else if(istype(destination, /atom))
atom/A = destination
dx = (A.x - owner.x) * 32 + A.pixel_x - owner.pixel_x
dy = (A.y - owner.y) * 32 + A.pixel_y - owner.pixel_y
px_dist = sqrt(dx * dx + dy * dy)
if(px_dist) // unit vector times P.speed
P.dx = P.speed * dx / px_dist
P.dy = P.speed * dy / px_dist
else // owner and target in exact same position
return P

world.log << "Invalid destination: FirePixelProjectile([owner], [destination], \

spawn(P.delay) // so this proc can return normally
//if(P && (alert("[P.x]:[], [P.y]:[]",,"Ok", "Delete")=="Delete"))
// del(P)
if(P) sleep(P.delay)

return P

It's not the most elegant; I'm sure something done with the directional bit flags would be a million times better, but I'm still not comfortable using them yet.

The "dir[owner.dir]" bit is so that the proc recognises it as text.