Well I guess the design of this depends on how complicated you want to allow the animations to be.

You could do something similar to jQuery's animate(). Or maybe a proc like my first suggestion but instead of having the property argument, make from and to associative lists (which I guess would be pretty similar to jQuery except you provide explicit starting values). The downside is that you lose the ability to add a more steps to the animation, unless you allow the proc to be called multiple times and queue the animations. In that case, you lose the ability to loop a multi-step animation.

Personally I still kind of like the way my second and third examples work. Mainly because I can't think of another method that would allow all of the same features without overcomplicating the code. It is simple and easily readable yet reasonably powerful. It doesn't introduce any new syntax or require specially formatted strings. Most of all, it doesn't require multidimensional lists, which could get ugly. Additionally, it doesn't call for any new datums. I actually think adding a /animation type might be a good alternative, but in the past you guys have seemed reluctant to add built-in datums for things like this.

One call per var could potentially get repetitive, but it looks like there will not be many vars that can be animated, and of those, I would expect that in most cases only a couple are being animated at once. So hopefully, that wouldn't be an issue. And animating many vars at the same time will probably require more code no matter which way the proc works.
In response to Nickr5
Nickr5 wrote:
Well I guess the design of this depends on how complicated you want to allow the animations to be.

Indeed, this is the big question. Do we want animations to be in stages? What if one property has a long animation and another needs to be in two short stages?

Also it occurred to me that matrix interpolation might work better in layers, but that might be a little too advanced to consider. I was thinking along the lines of wanting to move outward from a center while rotating, for a kind of spiral effect. Probably pointless to bother with.

My current best idea is to do something very flick-like, and have the all be animate(src, result, time), where the result is an Appearance. This would effectively change src's Appearance but tell the client to transition to that over time from its current state. Multiple calls could represent stages. The beauty of this is that it can handle a lot of var changes at once, and it's really straightforward. The downside is it requires the user to make a temporary copy of the object to set all those vars first, unless it's provided with a parameter list in place of an Appearance.

I don't think your examples that call it per-property are necessarily the best choice, inasmuch as 1) they'd be subject to timing issues, and 2) it's extra network overhead. I do like the way you built in stages, though.

You could do something similar to jQuery's animate(). Or maybe something similar to my first suggestion but instead of having the property argument, make from and to associative lists (which I guess would be pretty similar to jQuery except you provide explicit starting values).

That's relatively close to my animate() idea, with a parameter list. (The main issue I see with a parameter list is that with atom.transform being a list, converting to and from a parameter format is kind of ugly.)

Personally I still kind of like the way my second and third examples work. Mainly because I can't think of another method that would allow all of the same features without overcomplicating the code. It is simple and easily readable yet reasonably powerful. It doesn't introduce any new syntax or require specially formatted strings. Most of all, it doesn't require multidimensional lists, which could get ugly. Additionally, it doesn't require any new datums. I actually think adding a /animation type might be a good way to do this, but in the past you guys have seemed reluctant to add built-in datums for things like this.

Yeah, something similar to a datum would seem to make more sense, but I'm definitely reluctant to build one in.

One call per var could potentially get repetitive, but it looks like there will not be many vars that can be animated, and of those, I would expect that in most cases, only a couple are being animated at once. So hopefully, that wouldn't be an issue. And animating many vars at the same time will probably require more code no matter which way the proc works.

Yeah, you make a good point there. I'd just rather avoid multiple proc calls, which would mean multiple messages, for animations that need to happen concurrently.

Then again, maybe animate(src, ..., time) would work with an argument list, where you could say something like:

animate(O, alpha=0, transform=list(2,0,0,0,2,0), 10)


The 10 is a time argument, which could be named too or left unnamed; the first argument is of course the object to be animated. Its vars are changed immediately as a result of the call, but first the clients are told to animate from the current appearance to that.

The transform argument may look a little awkward there because I haven't settled on a helper function format yet (see id:1353302), but that says to scale by 2.

Mind you this doesn't address a case where you might want an atom to spin around 10 times. The transform matrix would be identical to the identity matrix, which means you'd want to do something with stages. Stages could be handled by multiple calls. Maybe that'd be ugly, but I think it'd be okay.
In response to Lummox JR
Lummox JR wrote:
I don't think your examples that call it per-property are necessarily the best choice, inasmuch as 1) they'd be subject to timing issues, and 2) it's extra network overhead. I do like the way you built in stages, though.
I'd just rather avoid multiple proc calls, which would mean multiple messages, for animations that need to happen concurrently.

I was assuming you would buffer the calls to Animate() so that they all get sent over the network together. I think that would fix all of the problems you mention here: there would be no additional overhead and you could guarantee that calls that are made in the same tick occur simultaneously.

For example:
animate(a, PIXEL_X, ...)
animate(a, PIXEL_Y, ...)
sleep(1) // at this point *both* of the previous calls should be sent to the client
animate(b, ALPHA, ...)
animate(b, TRANSFORM, ...)
Because of network delays, the programmer can't make assumptions about when a or b will begin to animate. Nor even that the two animations will occur exactly one tenth of a second apart from each other. But you *can* promise that a.pixel_x is animated at the same time as a.pixel_y, b.alpha is animated at the same time as b.transform, and that b's animation starts sometime after a's animation.

Anyway, I don't really mean to keep pushing the one call per property thing. It seemed a little weird to me too and it looks like you have some good ideas. I just want what I was suggesting to be clear!

Stages could be handled by multiple calls. Maybe that'd be ugly, but I think it'd be okay.
Yeah, I think this would work. Multiple calls for stages wouldn't bother me any more than multiple calls for different properties. If animating multiple vars concurrently is more common than having multi-stage animations (not sure if this is a safe assumption, but it seems reasonable), then your way has the advantage of requiring fewer calls. However, the one big problem I have with it is that if I understand you correctly, you don't provide any good way to loop multiple stages of an animation indefinitely.

That's relatively close to my animate() idea, with a parameter list. (The main issue I see with a parameter list is that with atom.transform being a list, converting to and from a parameter format is kind of ugly.)
Once you figure out the helper function I think either way would probably be fine.

Yeah, something similar to a datum would seem to make more sense, but I'm definitely reluctant to build one in.
Just out of curiosity, why? This reluctance to add built in types seems like it has been a recurring thing to me. Yet I would say most object oriented languages have plenty of classes in their standard library.
I'm also confused about the reclutance of creating a datum.
icons, and sounds exist as soft-coded datums that interact with hooks from the core, don't they?

What can't the same be done for this? Expanding the Appearence data to a datum?
For the record, I think it would make a lot of sense to use a /datum for any new type that involves considerable configuration. This may very well be a good candidate if there is a lot of desired functionality; certainly using member variables is a lot more intelligent than passing lots of arguments.

The downside is the implementation and the fact that there may be expectations about passing this new type into existing procs. One of the nice things about DM is that some of the procs can accept many different types (eg, an atom or an icon or an image) and do what you'd expect, but it's not wholly consistent and introducing a new type can add to that.

All told, though, I very much approve of this idea, because flick() has long been a workhorse for client-side effects despite its very limited configuration.


On the subject of a custom datum, it occurred to me that while we can't really use Appearance directly (it's read-only, because it's a shared structure like a string, so new ones are created on the fly), we could do something like /icon where it has an internal Appearance object as a member of the datum, and changing its properties could make the appropriate changes internally. In which case it'd be possible to do this:

var/A = new/appearance(myobj)
A.transform = matrix_rotate(90) // still haven't decided on matrix helper syntax
animate(myobj, A, time=0)


However my arglist animate() syntax proposed above (where you could just name the values you want to change) would be equally effective. That said, one side benefit of this datum is that it'd be an easy way to modify overlays. It could also be used as a way of changing several properties of an atom at once. So just throwing that out there.

The only thing I don't like about my animate(object, named args, time) syntax is that, as Nickr5 pointed out, indefinite loops would be difficult. I can think of a few ways around this:

Method 1:
animate(object, appearance1, time1, appearance2, time2, ...) // negative time could indicate a loop

Method 2a:
animate(object, appearance, time) // negative time could indicate the start of a loop

Method 2b:
animate(object, named arguments, time) // negative time could indicate the start of a loop

Stopping a loop is obviously also important, but time=0 would suffice for that.

With an infinite loop, it seems like if no time is specified to return to the original appearance, then the time from the original animate() call should be used to return to it. That way you'd only need animate(object, transform=list(1.25,0,0,0,1.25,0), time=-5) for a pulsating heart, for instance.
Honestly, if there were a way we could precache animations themselves, it would be really nice to set them up, send them off to the client, and call them via index/name.

Is transform in that example handling scaling and rotation?
Yes, it would do scaling and rotation.
In response to Lummox JR
Lummox JR wrote:
Yes, it would do scaling and rotation.

...You are my hero...

Money will be thrown your way soon, sir.

Tom wrote:
I think it would make a lot of sense to use a /datum for any new type that involves considerable configuration.

Not to open old wounds (Thanks, F_A/OFD >_<), but will this ethos eventually address the issues with winset/get? I fully support any effort that encapsulates more of BYOND's behavior in datums.

LummoxJr wrote:
On the subject of a custom datum, it occurred to me that while we can't really use Appearance directly (it's read-only, because it's a shared structure like a string, so new ones are created on the fly)

This is one of the many, many things about BYOND that I constantly pine for the ability to do. I understand that there are major concerns about changing data that may be read while edits are occurring, it occurs to me that locking and unlocking appearances for editing would only be difficult because of the existing implementation, and is of itself not terribly difficult.

Perhaps it's time to consider addressing this limitation. I for one, would much appreciate a means of manipulating all appearances of one type on the fly, which would make for some very elegant day/night systems due to the added feature of being able to manipulate the referenced appearance rather than looping through thousands of turfs at a time.

I would much prefer to have a single object that encapsulates animations, and is devoid of icon-specific behavior.

Meaning, an animation created for a player icon could be created for a variation of an enemy icon, rather than having to be applied to each, simply by handling animations as a reserved list of objects cached on the client side.

I really am not sure I'd be too happy about using anything that had to be sent to the client each time you use the animation. It's better than nothing, but it's inelegant at best.

Out of curiosity, though, is there any way we can get the scaling and rotation to bubble up to the atom level? I'm concerned about using up a unique appearance per scaled and rotated object, and having an animation be tied to the scale and rotation defined within that particular chain of animation. Adding the atom's scale/rotation and treating the animation-level transform as a delta would be much more elegant.
In response to Ter13
Ter13 wrote:
Lummox JR wrote:
On the subject of a custom datum, it occurred to me that while we can't really use Appearance directly (it's read-only, because it's a shared structure like a string, so new ones are created on the fly)

This is one of the many, many things about BYOND that I constantly pine for the ability to do. I understand that there are major concerns about changing data that may be read while edits are occurring, it occurs to me that locking and unlocking appearances for editing would only be difficult because of the existing implementation, and is of itself not terribly difficult.

Perhaps it's time to consider addressing this limitation. I for one, would much appreciate a means of manipulating all appearances of one type on the fly, which would make for some very elegant day/night systems due to the added feature of being able to manipulate the referenced appearance rather than looping through thousands of turfs at a time.

This isn't exactly what I meant. I was referring more to a simple way of copying the appearance from an atom, and making changes to a datum that get reflected in the creation of a new appearance. The appearance could then be assigned at will.

Changing an appearance that already exists would be a bit of a headache. I understand the impetus behind the idea; I just don't think it's practical.

I would much prefer to have a single object that encapsulates animations, and is devoid of icon-specific behavior.

Meaning, an animation created for a player icon could be created for a variation of an enemy icon, rather than having to be applied to each, simply by handling animations as a reserved list of objects cached on the client side.

I really am not sure I'd be too happy about using anything that had to be sent to the client each time you use the animation. It's better than nothing, but it's inelegant at best.

Except for objects undergoing some kind of permanent looped animation, where I agree that'd be an issue and it's something I'll have to consider, I don't see the problem of sending to the client each time. Flicks already do this. I think animations will be used more for transitional effects than permanent ones, so sending to the client just makes sense.

If you have any ideas on how we'd handle permanent looped animations, though, I'd definitely love to hear them. Right now my only loop-based ideas are built around flick-like events that are seen only by currently logged-in clients.

Out of curiosity, though, is there any way we can get the scaling and rotation to bubble up to the atom level? I'm concerned about using up a unique appearance per scaled and rotated object, and having an animation be tied to the scale and rotation defined within that particular chain of animation. Adding the atom's scale/rotation and treating the animation-level transform as a delta would be much more elegant.

I can see a case to be made for both, but I think all things considered it's unnecessary to plan for delta. Here's why: Whatever helper functions I setup for matrices (please do weigh in on that thread), they will include built-in easy multiplication. My original, but not wonderful, concept would be something like matrix(transform, 45, MATRIX_ROTATE), which would multiply transform by a 45° rotation matrix, yet you could omit that argument and just create a raw rotation matrix if you liked. So the delta will be built right into whatever routines we have.
This might come off as rude, but I sincerely don't mean any of this as an insult, but more as a plea for some perspective. And I might be totally wrong about how I'm interpreting your solution here, so if I am, I do apologize.

The reason I can't answer your direct questions, Lummox, is that I feel like you are neglecting that BYOND isn't a game engine. It's a fully self-contained IDE.

I can't help but feel that your view of the engine as a programmer is getting in the way of you seeing the problem with the suggested approaches from the perspective of the non-programmers who will be working within the IDE.

Putting this much of the animation controls' new features solely in the realm of the programmer's domain within a project unjustifiably leverages too much of the graphical concerns on someone who should only genuinely be concerned with numeric data (I.E. top-level, per-object rotation, scale, and alpha properties).

I'm having difficulty being overly excited about this unless the portions of it that specifically involve artistic talent, and the portions that specifically involve programming talent are segmented to the proper portions of the project.

I'm not sure if it's a fair observation, but too often does it seem like our recent updates to the engine are neglecting that the project itself is a fully self-contained IDE, and each toolset is important to a different portion of every team. Mixing and matching specialties leads to disorganization and counter-intuitive approaches to what should be otherwise an obvious, and simple solution.

That said, I really appreciate all the agony and work you guys are putting into the project, but if we really do want to grow as a community, we need to ensure our product not only fills a niche of its own, but also emulates the features of other projects that work, and work well.

Again, I can't edit the wording of this enough times to fully express my concerns without feeling like I'm coming off at an level of criticism that I genuinely don't intend to put across. Please don't take any of this as derogatory, I really do mean the best with this post.

Were it my call, I'd much rather have time and energy spent rewriting limiting portions of the engine that don't allow us to do certain things we'd like to, than to use the existing, problematic portions to build the less-optimal approach into the project.
In response to Ter13
I'm not really sure I understand what you're getting at. If the point is to say there should be more work done on the map editor instead of a visual feature, that's something best left to another thread. All I'm doing here is soliciting advice on how people would want a planned feature to work and how they'd want to interact with it.
I'm really not sure I understand what you're getting at. if the point is to say there should be more work done on the map editor instead of a visual feature.

My argument is that if we're building in new features for an animation handling system, these features really should be integrated with the existing visual toolset, and not exclusively accessible via writing chains of functions to build animations.
In response to Ter13
Ter13 wrote:
My argument is that if we're building in new features for an animation handling system, these features really should be integrated with the existing visual toolset, and not exclusively accessible via writing chains of functions to build animations.

That's only relevant to "permanent" animations, which is actually something I'd still like to work out how to handle. So far I'd been looking at a flick-like format, but I do see a case to be made that some objects might always be in motion. That said however, such things would be really difficult to display in the map editor, which doesn't display animated icons at all.
I'm not talking about the map editor at all. I'm talking about a visual implementation for working with animations, or building this behavior into the DMI format itself. A pure show-once-build-once code solution for new animation features, like scale, rotation, etc, is inelegant at best.
In response to Ter13
Ter13 wrote:
I'm not talking about the map editor at all. I'm talking about a visual implementation for working with animations, or building this behavior into the DMI format itself. A pure show-once-build-once code solution for new animation features, like scale, rotation, etc, is inelegant at best.

It makes no sense in the .dmi format, inasmuch as this is an Appearance feature. Also, the icon var itself could be part of the animation.

Because animation can impact multiple vars, I don't see how this would be handled visually in a meaningful way. It's not like we're dealing strictly with the new transform var (currently under development).
Perhaps it's best that I just wait until you have more to show that will explain your approach, because reading through this thread has clearly given me a very different understanding of what we're looking at. My apologies.
In response to Ter13
I had the feeling we were on different pages too. Let me try to explain what I'm getting at a little better:

I want users to have a way to smoothly animate between different states, in much the same way jQuery does this. This would be done on the client side, so the actual change of state would be instantaneous.

Like jQuery, I want the animation to be flexible in that it could change pretty much any var related to an atom's appearance. For the most part, this would mean changes to icon and icon_state (those would be instantaneous since there's no in-between), but it would also mean the pixel offsets could change, as could the new transform var, the proposed alpha var, etc.

There are two ways animation might be seen: First, it might be a flick-like event that's sent to all players who might see the object. Second, it might be a permanent loop that's seen by anyone once the object comes into view. I haven't worked out how I want to handle the latter, though I have an idea.
In response to Ter13
Ter13 wrote:
Perhaps it's best that I just wait until you have more to show that will explain your approach, because reading through this thread has clearly given me a very different understanding of what we're looking at. My apologies.

It's my understanding that we're looking for a function (or suite of functions) to handle on-the-fly appearance changes at run-time. Not anything permanently built into the icon files themselves, just ways to more easily incorporate flick()-like temporary (or not-so-temporary) appearance changes, through a system that generates the transition animation for the developer. (I.E. new rotation angle is going to be 45 degrees; don't just switch the icon to a 45 degree state, but animate the transition between the current angle and the desired angle)

From Lummox's angle of the implementation, he's trying to come up with the internal system that will be used to handle all of this (preferably in one universal system/proc that can accept every kind of appearance change, potentially also a series of changes and/or a list of simultaneous changes)

From the developer's side, Lummox has mentioned several times that he'd like to also add some more user-friendly "interface" sorts of procedures (so that developers won't need to use the potentially ultra-complex internal proc with its potentially dozens of arguments if they'd rather not) Perhaps such as "animate_rotation()" or "animate_scale()" or whatnot that would accept the necessary arguments for those appearance changes, then simply pass them on internally to the actual universal control proc.

So yes, this discussion is far more technical than we'd like these systems to be presented to the developer for end-use, but there is also a second layer of the discussion on how to make this system user-friendly after the internals are hammered out.

...or so I've gathered... Maybe I'm wrong?
As far as the helper procs, that's more a question of how to handle the transform matrices. I doubt animation itself will need any helper procs, but matrices definitely will because it's not like Joe Developer should be expected to have an intimate grasp of them.

With the animation, this is about what I was thinking for the process:

animate(object, named vars, time, loop=0)

If loop > 0, it represents the start of a loop. Animations will queue up (and be considered part of an existing loop) with subsequent calls. (Open question: At what point is the animation no longer considered stacking? When the calling proc ends or sleeps? Or should there be a null for the object when it's going to stack, referring to the last object referenced?)

I think it makes sense for any animations started this way to store info with the object itself until the animation is completed or stopped. That way, if the object comes into view for a client who didn't see it before, the client can be given enough info to animate it. This would allow for permanent animations, like a spinning star or something.

I'd like for this to allow for gradual "swing" easing like that in jQuery, as well as linear animation, but I'm wondering if that isn't overkill.
Page: 1 2 3 4