ID:1813265
 
Applies to:DM Language
Status: Open

Issue hasn't been assigned a status value.
Right now, pure-visual particle effects have overhead that they really don't need to be adding to the engine.

There are currently two ways to take advantage of animated particle effects:

1) movable atoms

2) images

Unfortunately, both have some slight problems with additional overhead that could otherwise be avoided.

/image objects would be perfect for animated particle effects if you didn't have to explicitly show them to people. Explicitly showing them to people requires that the developer either simply show all of these image objects to every user in the world, or manually iterate through each player that would feasibly be in view of the particle effects and add the images to their viewing list.

Instead of doing this, it would be much preferable if there were some kind of a flag for image objects that made them always visible to all players without inducing the same overhead as adding them to the images list of all players. In other words, they would act similarly to normal atoms, but wouldn't have a bounding box, wouldn't trigger Move()/Cross()/Uncross() behavior, etc.

Unfortunately, spawning several dozen physical atoms within a very small space can bog the engine down with a large number of calls to the movement-related functions, making physical atoms not very ideal for particle effects.
This sounds a lot closer to missile(). Kind of a similar concept anyway.
Similar, but allowing us to control the positioning and transformation via animate() as opposed to it just being a linear animation like missile() provides.
This sounds cool. I wants it.
Just some flag for /image.
I actually this can be used for other things as well, sounds very useful.
I also have encountered the need to use this, so thumbs up.
I sixth this :D
+
One thing that occurs to me about this concept: I don't see how it'd be a problem to simply use objs but not call Move() for them. Ultimately anything that might be developed to handle this would be so indistinguishable from real atoms, there's almost no point. missile() is just a fire-and-forget effect, but anything you can animate() would have more permanence by definition.
Well the problem is that you can't set the location as you can for images, since when you set the location for image objects to be the mob for example, it keeps following it around aka acting as an overlay, where as an object would merely try to enter the contents of said mob. No?
One thing that occurs to me about this concept: I don't see how it'd be a problem to simply use objs but not call Move() for them. Ultimately anything that might be developed to handle this would be so indistinguishable from real atoms, there's almost no point. missile() is just a fire-and-forget effect, but anything you can animate() would have more permanence by definition.

In addition to being able to use images as mutable overlays, there's also the issue that even a small number of particles will cause all sorts of problems when something tries to Cross() them. Regardless of whether you have Cross()/Uncross() defined, they still slow down movement-related procs for other objects.

It seems nonsensical to me to use atoms as particles unless they do what movable atoms are supposed to do: be physical.

Unfortunately, BYOND really lacks a means of providing visible-to-all purely visual objects, and the images having to be in the client's images list to be rendered adds an extra level of overhead for view sending that would be unnecessary for a visible-to-all image.
Also, one of the other major problems with particle effects and animate() is that objects' apparent rendering positions are not calculated based upon transform. This makes things like particle effects render incorrectly, or suddenly appear when you move and the particle's origin is now within your view.

It's a really troubling problem, and really causes developers quite a few headaches when it comes to making a game that isn't clunky. What we wind up having to do is basically avoid using animate() for what it was intended for and manually make certain that objects are rendered in the correct positions by manually changing the location of the object rather than relying on animate() to get objects to the right viewers (which it doesn't).
I'm not familiar enough with the subject to offer much commentary, but I definitely support working out a way to get this in. It could be pretty useful for a lot of things.
In response to Ter13
Ter13 wrote:
Also, one of the other major problems with particle effects and animate() is that objects' apparent rendering positions are not calculated based upon transform. This makes things like particle effects render incorrectly, or suddenly appear when you move and the particle's origin is now within your view.

It's a really troubling problem, and really causes developers quite a few headaches when it comes to making a game that isn't clunky. What we wind up having to do is basically avoid using animate() for what it was intended for and manually make certain that objects are rendered in the correct positions by manually changing the location of the object rather than relying on animate() to get objects to the right viewers (which it doesn't).

Wouldn't it be good to just have animate() work as expected? I don't really understand it much but I'd definitely want to rely on animate() to render properly and show to the right viewers.

The only thing I noticed is that I can't use animate for effects that occur over an entire z level, it definitely would pop to existence in certain places and not show entirely in others. I don't know how hard it'd be to change that though.
If there are issues with animate() not working intuitively, please post a separate bug report with a demo.
@Rotem: Basically, the way that BYOND currently handles view sending, is tiles/objects are obtained by checking for tiles within range of the client. Tiles are marked "interesting" if they are larger than the tile size of the world.

In order to make everything function reliably (and efficiently), Lummox/Tom would basically have to go in and implement a quadtree structure for tracking viewport rendering.

When an object is changed visually (bounds, loc, pixel offsets, or transform), its visual_bounds would need to be calculated:

(This is an incredibly non-optimal solution. It could be cleaned up quite a lot)

var/w = icon.width/2
var/h = icon.height/2
var/ox = bound_x + step_x + pixel_x
var/oy = bound_y + step_y + pixel_y + pixel_z
//create initial bounding box, then transform vertices
var/p1 = point(-w,-h) * transform
var/p2 = point(w,-h) * transform
var/p3 = point(w,h) * transform
var/p4 = point(-w,h) * transform
//regenerate the bounding box based on the min/max bound values of the vertices
var/x1 = min(p1.x,p2.x,p3.x,p4.x) + ox
var/x2 = max(p1.x,p2.x,p3.x,p4.z) + ox
var/y1 = min(p1.y,p2.y,p3.y,p4.y) + oy
var/y2 = max(p1.y,p2.y,p3.y,p4.y) + oy
//reset the point values
p4.x = p1.x = x1
p2.y = p1.y = y1
p3.x = p2.x = x2
p4.y = p3.y = y2


After you've calculated the bounding box for the object, crawl downwards through the quadtree until you find the last node in the chain that fully contains the object's visual bounding box.

var/node = quadtree.topnode
var/childnode;
while(node)
//negative x axis
if(p4.x<quadtree.childwidth)
//negative y axis
if(p4.y<quadtree.childheight)
childnode = quadtree.child1
else //positive y axis
childnode = quadtree.child4
else //positive x axis
//negative y axis
if(p4.y<quadtree.childheight)
childnode = quadtree.child2
else //positive y axis
childnode = quadtree.child3
//test if this object's bounding box fits fully inside the quadrant
if(childnode.fitsinside(p1,p2,p3,p4))
//if this is the last node in the quadtree (leaf)
if(childnode.end)
//this element belongs only to the leaf
src.SetContainer(node)
node = null
else
//otherwise, continue further down the subdivisions
node = childnode
else
src.SetContainer(node)
node = null


Of course, you'd want to set a minimum granularity such that the end of the chain isn't a single tile, but rather, probably a group of either 32x32 or 64x64 tiles.

When constructing a view list for the client, you'd need to normalize the viewport edges of the client against the quadtree's minimum granularity, and grab all the nodes that are within the client's viewport's range. Then, you basically subscribe the client to the node's list of watchers. When a client starts watching the node, the node will send a message containing all of the objects within that node. When an update happens to a node, it's stored in a list of updates that have happened during that frame, and at the end of the frame, visual updates are sent to the clients watching the node. If a node doesn't have watchers, it simply doesn't track updates.

This method would decrease network overhead by quite a bit and make the client-server interaction much smoother and easier to work with.

Unfortunately, I don't think Tom and Lummox are much interested in doing this, as forcing it into an existing implementation can be incredibly problematic.
bamp for muh particles
I guess the problem with big icons not being correctly displayed to people was fixed some updates ago. Nevertheless, this sounds like a good feature for images.

In the worst case we would have to create an object and add images to it's overlays (I guess (?)).