ID:768159
 
I noticed there was a lack of any sort of formal missle or projectile type logic in DM. I have coded a very basic and crude example of how you could make a missle that can actually be dodged and will actually hit targets.

obj/flicker
layer = MOB_LAYER + 1
animate_movement = SYNC_STEPS
mob
var/atom/flicker/flick = new
Move()
..()
flick.loc = src.loc
Cross(atom/a)
return a.crossed(src)
atom
proc/crossed(atom/a)
return 1

obj/missile
icon = 'explosion.dmi'
New(loc, dir)
src.loc = loc
walk(src,dir,11/7,7)
spawn(30)
del(src)

crossed(mob/a)
world << "[src] has hit [a]!"
//could do damage here
flick(src, a.flick)
spawn del src
return 1


Let me know what you think of this type of design!

Note: I have purposely avoided Crossed() here. If you've ever played around with those procs, you'll realize they don't fire quite how you'd expect at first glance.
Cross and Crossed are equivalent to Enter and Entered. Crossed isn't called unless Cross returns a true value, like Enter and Entered. They are called once one object's bounding box intersects another's and won't be called again until the object separates. They also require pixel movement to work.

Another thing: atoms are positioned at the first argument given to new() before New() is called. You don't need to set it again, or call ..(), because initial positioning happens before New is even called.

You should also either explain why you're using 11/7 and 7, or make it customizable.

P.S. Missile
I tried this and it does nothing...

mob
Crossed(atom/a)
world << a
Cross(atom/a)
return 1


11/7 for lag and 7 for glide_size = smooth movement. Try it. It could easily be made customizable, its just a code snippet.

I understand how Cross and Crossed work. Even without pixel movement though, they still function, just not 100% (see above example).

Enter and Exit for moveable atoms only work when they're entering or exiting each other's contents. So an object walking across turfs traveling past a mob walking on turfs, neither atom's enter or exit procedures are going to be related to each other, only related to the turfs they're on.

Thanks for the reminder about ..() but, if I were to put New(dir) it would think dir is loc, right?
You can pass arguments to ..()

obj
missile
New(dir, loc)
..(loc)
src.dir = dir

If you had just called ..() it'd pass the same arguments to it that were passed to that proc (dir, loc), but since you want to pass the loc as the first parameter, you have to specify that.

The Action RPG Framework has an implementation of projectiles which is what I typically use. You pass the mob that's creating the projectile to its constructor and it can extract the loc and dir information from that. This also gives the projectile a way to remember who fired it, since many games will want to know who fired it when the projectile hits something.
In response to Forum_account
Forum_account wrote:
You can pass arguments to ..()

> obj
> missile
> New(dir, loc)
> ..(loc)
> src.dir = dir
>

If you had just called ..() it'd pass the same arguments to it that were passed to that proc (dir, loc), but since you want to pass the loc as the first parameter, you have to specify that.

The Action RPG Framework has an implementation of projectiles which is what I typically use. You pass the mob that's creating the projectile to its constructor and it can extract the loc and dir information from that. This also gives the projectile a way to remember who fired it, since many games will want to know who fired it when the projectile hits something.

How are you determining when a projectile collides with something else? I am trying Enter, Entered, Cross and Crossed over here and still getting some cases where I can walk right through a missle.
I make them dense and use their bump/Bump event.
Ah!
Now I wish I had posted this in developer help lol...

But here's what I've upgraded to:

obj
flick
layer = MOB_LAYER + 1
animate_movement = SYNC_STEPS

mob
var/obj/flick/flicker = new
Move()
..()
flicker.loc = src.loc

obj/missile
icon = 'explosion.dmi'
density = 1

New(loc, dir)
walk(src,dir,11/7,7)
spawn(30)
del(src)

Bump(atom/a)
if(ismob(a))
src.density = 0
Move(a.loc)
world << "[src] has hit [a]!"
//damage
flick(src,a.flicker)
spawn(1) del src
if(isturf(a))
spawn(1) del src
Why the isturf part at the end? just curious.
So the missle will die when it hits a wall.
In response to FIREking
FIREking wrote:
So the missle will die when it hits a wall.

Have you tested that already? It seems like it would die as soon as it entered any turf.

Also a small suggestion. Rather than doing del src, try src.loc=null .
Yeah this works. Bump doesn't get called on non dense things. Setting loc to null won't actually remove the missile from server memory. But I see what you're saying about two del() events being queued up..

New code would be

obj/missile
icon = 'explosion.dmi'
density = 1
New(loc, dir)
walk(src,dir,11/7,7)
spawn(30)
del(src) //always dies

Bump(mob/a)
if(ismob(a))
src.density = 0
Move(a.loc)
world << "[src] has hit [a]!"
flick(src,a.flicker)
world << a.underlays.len
spawn(1) loc = null//gonna die anyways
if(isturf(a))
spawn(1) loc = null//gonna die anyways
I totally misunderstood. For some reason my brain didn't process the fact that you were using dense turfs as your walls. -_- *