I like the idea of the DMI format getting an update to remove duplicate frames while changing the way animations are handled. Instead of the bloated icons we have now, the new DMI format would just have a sprite sheet full of unique frames. The only dilemma I can see popping up with this is do you either A) Have animations saved as a part of the DMI, or B) Have all animations handled in the game code.

The benefit of A is that you can still package icons along with all their animations while the benefit of B is that it would be much easier to create a bunch of animations at runtime without having to do any icon editing. If I had to pick one or the other I would go with B as it has the most flexibility in the long term. It would be much better to be able to just string together a list of icon_states and their delays then send that information to game clients. If that were the case you could have dynamic animations with the timing of flick() but without the overhead of doing icon operations on a live server.

Maybe there could be a way to cache these animations in the game client for quicker transmission of animation information. If that were possible you could have both pre-packaged animations and dynamic runtime animations. Depending on how the caching is done, DMI's could be packaged with animations which simply cache themselves ahead of time. The first example animation, assuming it has been cached, could be called by simply using Animate("animation_name",mob) without needing to list out list of animation instructions.

Examples:
//Regular animation
Animate("animation_name", "icon_state:1, delay:1; icon_state:2, delay:1", mob)

//Particle effect
Animate("damage_text", "pixel_y:1, delay:1; pixel_y:1, delay:1; pixel_y:1, delay:1", mob)

//Rotation:
Animate("icon_state:idle, turn:35, delay:1; turn:10, delay:2; turn:-45, delay:3", mob)

//Going invisible:
Animate("stealth", "icon_state:stealthing, alpha:10, delay:1; alpha:10, delay:1; alpha:10, delay:1", mob)

//Changing red:
Animate("damaged", "icon_state:hurt, red:1, delay:1; red:10, delay:1; red:10, delay:1", mob)


Though not as advanced as the other suggestions, it's probably simple enough for newbie coders to work with while still being flexible enough for practical use by experienced developers. I don't know a good way to handle screen filters, but something like this should be decent enough for map entities.

What would also be useful is adding "hook" points to do what FIREking was talking about. They could be inserted into the above syntax via something like "hook:hook_name" and would cause subsequent Animate() calls to wait before firing. If the animation currently playing doesn't have the noted hook point then it's simply overwritten by the new animation which begins immediately.

//We're trying to make an NPC bow after they've finished talking.

//Talking animation, note the repeat flag is enabled.
Animate("talking", "icon_state:mouthopen, delay:1; icon_state:mouthclosed, delay:1, hook:MOUTHISCLOSED; repeat:1", mob)

//The player is now done talking to the NPC.

//Jump to new bowing animation on the frame after "mouthclosed" is finished.
Animate("donetalking", "icon_state:halfbow, delay:1; icon_state:deepbow, delay:2; icon_state:halfbow, delay:1", mob, hook="MOUTHISCLOSED")

-

Somewhat related to the idea of having DMI's updated to remove duplicate frames, it would be nice if there was a way to have East/West mirroring handled in the game software rather than having a bunch of mirrored frames in the icon itself.
In response to SuperAntx
Again, to be clear, altering the .dmi format is not the issue under discussion in this thread. Animations of the kind I'm talking about are an atom-level effect, so they wouldn't make sense within an icon file. Altering the .dmi to be more like a sprite sheet so that frames in a multi-frame icon needn't be duplicated is really a separate discussion.

I do like the idea of stringing an entire chain of animated effects into a single call, though I consider that somewhat difficult without a datum. I don't think a string format is workable unless it's a parameter list like the kind we use in a lot of other places, but that wouldn't be friendly to the transform var.

Additionally I do see some value in creating a visual missile-like object that's not merely animating a single obj, but is itself just an animation. If there were a convenient way to string a number of those together all at once, particle effects would be pretty easy. If that could be done without having to send full Appearances for each of them, it'd be terrific.
Here's what I'm going forward with for now:

animate(object, named args, time, loop)

object: The object to be animated, or null to continue animating the object in a previous animate() call.
named args: Vars that will be part of the animation, such as pixel_x=32.
time: The time (in standard 1/10s ticks) for the animation to occur
loop: Number of times to loop, or -1 to loop forever

Calling animate(object) with no other arguments will terminate an existing loop. This is effectively saying time=0, loop=0, and no var changes to animate.

The named args are changed immediately for this object, but the client will display those changes via animation over time.
Lummox JR resolved issue with message:
Atoms can now be easily animated on the client with the new animate() proc. It can be used to create multi-stage animations and even loops. Several vars can be animated smoothly, and several others can be changed at each stage. This is like a super-sized version of flick(), but the var changes involved are permanent once the animation finishes.
Will there be a way to cache animations?

Say I wanted to animate a damage number flying off a mob, it would require changing its pixel offset around 30 times. Would I have to animate that every single time with multiple calls to animate() or could I do it once then do something to say "do this animation the client already has the information for" whenever I wanted to play that animation again?
Animations can't be "cached" as there's no datum to hold them. (It's something that got discussed but nothing ever congealed together. Ultimately I went with a KISS approach.) However you should only need something pretty basic:

obj/effect/damage
maptext_width = 32
maptext_height = 16

New(newloc, mob/M, n)
maptext = "<font color=red><center>[n]"
step_x = M.step_x
step_y = M.step_y
// take 1s to move upward by 1 tile
animate(src, pixel_y=32, time=10)
// fade out
animate(alpha=0, time=10)
spawn(25) del(src)
Atoms can now be easily animated on the client ...

I'm not sure to understand...Is this like the use of image? But with more controls? I mean, is this only seen by the client?
In response to Kidpaddle45
Kidpaddle45 wrote:
Atoms can now be easily animated on the client ...

I'm not sure to understand...Is this like the use of image? But with more controls? I mean, is this only seen by the client?

Where else would it be seen? The server?

Animations are a replacement for flick with a much more flexible and expanded feature set.

They aren't shown to ONE client, they are shown to all clients, as they obey the rules of the parent atom.

I wouldn't be surprised if they don't work on /image objects, given that flick() never did.
Sorry I didn't formulate this correctly.
I meant to ask if this would work on images. Which is what I'd actually love to see. I do like where this is going but animations on images would really be a neat feature!
In the reference for animate():

"Object: The atom or image to animate. "
Can we get different easing functions to use for the tweening in animate()?
In response to Albro1
Albro1 wrote:
In the reference for animate():

"Object: The atom or image to animate. "

Just upgraded this morning.

This is great.
Still very funky acting. There are a lot of cases that seem like they should work one way, but they work another. These could be bugs or misunderstanding the feature. Not sure in some cases!
In response to D4RK3 54B3R
D4RK3 54B3R wrote:
Can we get different easing functions to use for the tweening in animate()?

I considered this in the beginning. I'd be cool with doing that; the message format already has a reserved flag built in for this purpose, so it would be easy enough to add. What kind of easing would we want though and in what ways would we define it? I could see a sinusoidal easing being useful, as would a cubic function, circular curves in and out, and maybe a bounce.

I don't want to go as far as user-defined easing functions, so I'm thinking of just a simple set that could be easily defined. Suggestions welcome.
In response to Lummox JR
You should definitely add the different easing functions, they would make animate() so much better. To be honest, it feels like animate() isn't complete without them.

Once you get easing functions we'll be able to add some pretty flashy looking particle effects to our games. Just imagine hundreds of sparks flying from a fireball impact then bouncing on the ground.
I think in and out and inOut are necessary for the following:
  • quadratic
  • cubic
  • exponential
  • circular
  • sinusoidal
  • bounce
  • back
Two follow-up questions:

1) Given a certain set of easing functions, how would you define them in a BYONDy way to apply to the argument list? That is, easing="cubic" isn't something I want to do at all. A constant I'd be okay with, though I'm not sure how we'd do an in-out version.

2) Sparks flying on the ground would be problematic with the current setup, given that you might want pixel_z to bounce but other pixel offsets to follow a linear pattern. How would you propose this work?
Maybe a few sets of bitflags, like

animate(easing = CUBIC|IN)
animate(easing = SINE|IN|OUT)

It's kind of challenging to come up with a way to set different easing functions for different parameters, like if I wanted something to move linearly in one direction while moving quadratically in another direction.

I don't have a good solution for that.
The only thing that I can think of in that regards is to provide multiple easing parameters that correspond to different things that are being tweened.
For example, maybe there can be an easing_x for the pixel_x parameter, and easing_y and easing_z? And maybe if these aren't set when you call animate(), they default to whatever easing was set to?

That seems kind of clunky to me though. I am unsure if there is a clean way to implement this without a keyframe datum for animate().
Applying easing to a given stage of the animation seems simple enough. Having each stage broken up into different sets of vars with different easing functions however is extremely problematic.
Maybe something like
animate(blahblah, easing, easing_offet, time);
Where easing is applied to all variables, and easing_offset, if set, is applied only to the pixel offsets?

That way, with linear easing on transform() and maybe bounce easing on pixel_z, you can pull off the bouncing particle.
It's kind of a hacky way of going about it though, and it's a pretty poor solution for if you wanted other things to have different easing.

Perhaps multiple calls of animate() shouldn't cause a series of animations in sequence, but a series of animations in parallel. Like say, I could do:

animate(atom, pixel_x = -5, easing = LINEAR, time = -5);
animate(atom, pixel_y = -64, easing = BOUNCE|OUT, time = -5);

So negative time indicates that these parameters all apply to the current animation stage?

I'm not sure.
Page: 1 2 3 4