PixelProjectiles

by Shadowdarke
Pixel based directional projectiles
ID:91654
 
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
ie
obj/sd_px_projectile/Bullet
passThrough = 2

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

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.

-end-
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 = \
/obj/sd_px_projectile)
/* 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.cx
P.pixel_y = P.cy

if(istext(destination))
destination=copytext(destination,4)
if(destination=="4") //East
destination=0
else if(destination=="5") //Northeast
destination=45
else if(destination=="1") //North
destination=90
else if(destination=="9") //Northwest
destination=135
else if(destination=="8") //West
destination=180
else if(destination=="10") //Southwest
destination=225
else if(destination=="2") //South
destination=270
else if(destination=="6") //South east
destination=315
if(isnum(destination)) // an angle
P.dx = cos(destination) * P.speed
P.dy = sin(destination) * P.speed

else if(istype(destination, /atom))
var
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
P.Hit(A)
return P

else
world.log << "Invalid destination: FirePixelProjectile([owner], [destination], \
[proj_type])"
del(P)
return

if(P)
spawn(P.delay) // so this proc can return normally
while(P)
P.UpdatePosition()
//if(P && (alert("[P.x]:[P.cx], [P.y]:[P.cy]",,"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.

~Ease~