ID:1348860
 
Resolved
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.
Applies to:DM Language
Status: Resolved (500.1205)

This issue has been resolved.
I'm looking for suggestions as to how to implement client-side animation of various Appearance-related values, in a manner more robust than that supported by flick(). The flick() proc could conceivably still be used for this, but the goal is to be able to specify animation of various values, possibly as a series of steps.

The reason I'm asking is I'm already considering adding several visual enhancements to Appearances for BYOND 500 or a near version, and animation would be extremely useful in conjunction with those vars, as it would already be for some things like pixel offsets. So fire up your thinking caps and have at it. Just remember KISS if possible. The simpler and more versatile the scheme, the better.

This feature is sort of the afterthought to tie those other features together. They don't depend on this, nor vice-versa, but it'd be nice to be able to roll them all out together.
In addition to all of those, perhaps a repeat number, and/or duration time?

Also, while not exactly related to the topic of animations (but still a visual effect), I'd really like it if when setting mouse_over_pointer to an icon_state, that icon_state would come from the client mouse_pointer_icon file, and not the object's icon. It just makes more sense to me to store all custom pointers in one file.

[Edit]: Well, that'll teach me to reference a previous post without quoting it...lol My first sentence makes much more sense if that previous post had not been (presumably) retracted by its author. The post in question had a nice list of extra parameters to flick() (like pixel offsets, an icon/icon_state combo, a start_frame, speed, etc.)
Is this strictly confined to existing appearance values, such as icon_state, direction, and frame delay?

Because there's rotation, alpha, color blending (the client should be able to do real time color blending via server instruction or as a pre-compiled rsc appearance script that the server can tell the client to fire up), real-time scale (opengl style) just to name a few!
Allowing the ability to flick() /image and /icon types would be a godsend.

Perhaps flick() could also be extended to allow for an infinite amount of arguments to be passed, or perhaps take in a list argument as well? This could be useful for queuing animation states, so if I want to make the player first "jump" and then "punch", I can do flick( list("jump", "punch"), src) without having to worry about timing.
In response to FIREking
FIREking wrote:
Is this strictly confined to existing appearance values, such as icon_state, direction, and frame delay?

Because there's rotation, alpha, color blending (the client should be able to do real time color blending via server instruction or as a pre-compiled rsc appearance script that the server can tell the client to fire up), real-time scale (opengl style) just to name a few!

This is also all very good. Perhaps almost any form of icon manipulation could be funneled through flick() (or it's successor)? Preferably also more than one at a time, for combo effects (like using a temporary scale-up, along with a rotation to get a nice Nintendo/Gameboy platformer style death animation)
In response to Doohl
Ah, great idea with the sequence without the need to conduct timing!
As for client-side animations, I think an all-inclusive event/triggering system would be the best way to proceed.

Feature bloat #1: Sound hooks

The ability to add sound hooks directly into the icon editor. This would allow the client to sync sounds to animations themselves without the server having to instruct the client to send the sound. Possibly some mechanism for determining output range would be great.

Feature bloat #2: Code hooks

A nice little feature would be to have code hooks that occur at certain points in an animation (obviously based upon appearance on the server). Basically, you can type a proc name that will be called when an animation reaches this frame.

Redesign of dmi format:

It would be very, very nice to redesign the DMI format to capitalize on the nature of tile-sheet animations.

For instance, rather than each distinct frame of an icon being a 2D raster, it would be a reference to a unique 2D raster. One of the things that this allows, is further compression of the DMI format by virtue of identical frames being detatched from the actual raster data, and faster construction of animations via code using an internal referencing system.

Animations themselves could simply be constructed of a list of ids, a delay value, and an optional hooked sound/procname.


Feature bloat #3: Play from a specified time offset

It would be nice to be able to play a specific animation to/from specific offsets without constructing an entirely new animation for each case.

In addition, it would be nice to be able to reverse an animation, or even play a repeating animation from a certain point, backward, to a specific point, repeating a set number of times.


Feature Bloat #4: Scaling, rotation, and per-object alpha

I'm quite aware that this would take some overhaul of the rendering engine to do, but being able to scale, rotate, and set alpha per-object would be pretty damn useful.

Imagine being able to use rotation to create lines in DM. The dragonball games would benefit immensely. Space games would need to have only one icon. The possibilities of this kind of a thing are pretty much serious bang-for-your-buck territory.


Feature Bloat #5: Shaders

While I'm more than aware that an OpenGL rewrite to allow for proper shaders would be painful at best, the client having mode-based rendering would be very nice. Rendering modes could include:

Add/Subtract/Overlay/And/Or/Multiply/Divide

This way, any object beneath the object's layer with the said rendering mode would be modulated by the specified operation with the tiles beneath it.
To add to ter13's suggestion, it would be nice to loop between a range of frames in a single icon_state animation. For example, if you have a talking animation for a character, you have to play the transition from standing still to talking stance, then loop a talking animation, then finally transition back to standing. This could all be packed into a single icon_state if you were able to loop the middle part until the talking is done, and then the animation would naturally continue 'til the end.
In response to FIREking
FIREking wrote:
To add to ter13's suggestion, it would be nice to loop between a range of frames in a single icon_state animation. For example, if you have a talking animation for a character, you have to play the transition from standing still to talking stance, then loop a talking animation, then finally transition back to standing. This could all be packed into a single icon_state if you were able to loop the middle part until the talking is done, and then the animation would naturally continue 'til the end.

This could be done cheaply and effectively with the event system that I indicated above, essentially set in-editor flag commands. Flag commands would be jump to frame, reverse play direction, change delay factor, play sound, execute function, etc.

Possibly, however, the ability to specify variable conditions for animation states would be pretty cool, and would work similarly to Unity's Mecanim. Just set up some kind of a system for changing variables, conditions, etc, and for fireking's example, just set the repeat to be contingent upon the condition (boolean) talking == 1. That way, you just tell the client that the icon_state stopped talking, and it will automatically cease repeating once it reaches the repeat point with the condition no longer being true.


I also forgot to mention something that I've been lamenting for a long time. With the big-icon system, it's that much more obvious to me, but I'd like to see the ability to set the cursor to icons larger than 32x32, and get some more precise control of the cursor icon_state by specifying mouse_over_pointer icon states to custom values.


In addition, I know you are working on a native swapmaps library, Lummox, so this might pique your interest:


Submaps:

Submaps are essentially big objects that can contain turfs. Submaps are parent-located which means they render using the coordinate system of their parent location.

Submaps are map objects that act like movables.

Essentially, in order to retain backwards-compatability, we would set up the global locate(x,y,z) procs to use a list of submap objects, whose location is world, rather than an explicit locale. Old z-layers will just refer to the position of the original submap.

Then, in order to locate turfs in individual submaps, we use submap.locate(x,y).

The unique feature this adds to the mapping system, is that we can quickly and easily move large portions of the map around the world, save individual chunks of the map, etc. We can, in newer versions of BYOND, have jagged map sizes (meaning x/y values can vary per z layer), simply by eschewing the z coordinate in favor of keeping a list of submaps.

Of course, I think this would require a new layering system, in which layers are relative to their submap (which wouldn't break existing games anyway, as layers are already parented to the fixed map!)

But yeah, pipedreams, and all that.
In response to FIREking
FIREking wrote:
Is this strictly confined to existing appearance values, such as icon_state, direction, and frame delay?

Because there's rotation, alpha, color blending (the client should be able to do real time color blending via server instruction or as a pre-compiled rsc appearance script that the server can tell the client to fire up), real-time scale (opengl style) just to name a few!

Frame delay I wasn't thinking of so much (it could be built into the animation anyway), but yeah, things like direction, pixel offsets, etc. And yes, rotation/scaling and alpha are the main things I was thinking of. The former looks simpler than the latter, but they're both in my wish list of new Appearance features.
In response to Lummox JR
Lummox JR wrote:
FIREking wrote:
Is this strictly confined to existing appearance values, such as icon_state, direction, and frame delay?

Because there's rotation, alpha, color blending (the client should be able to do real time color blending via server instruction or as a pre-compiled rsc appearance script that the server can tell the client to fire up), real-time scale (opengl style) just to name a few!

Frame delay I wasn't thinking of so much (it could be built into the animation anyway), but yeah, things like direction, pixel offsets, etc. And yes, rotation/scaling and alpha are the main things I was thinking of. The former looks simpler than the latter, but they're both in my wish list of new Appearance features.

Point of origin would be really nice. Being able per-icon, per frame to place the point of origin of the icon state would be pretty useful for handling animations that are a little more bouncy. I find myself doing a lot of math to adjust bounding boxes to the center of icons rather than the bottom-left corner.
All this sounds awesome. I especially like Ter13's ideas about sound hooks for icon states.. thats just amazing. If we could link appearance and events more thoroughly like that, it can only be a good thing =)

Client-side processing would be so great.. As is, delving into amazing graphical effects can hinder you if you aren't very careful. With that, as I'm sure everyone is aware, we could dump off a lot of processing to the player-pcs instead of the server.
To add onto my own flick() suggestions, it would make things easier if there was some way to make flick() act as a sleep() command, so you can determine exactly when to pick up logic after an animation. I wouldn't recommend just changing it to default to that behavior as it would potentially break existing games, and making a new argument for it seems a bit unelegant.

Perhaps you could add a new function like flick_sleep() that does the same? I suck at naming things, though!
@Kitsueki: Client-side animation would open so many doors, but it also sounds really painful to apply on top of the existing system.

@Doohl: A simple solution would be to have flick() return how long the animation will last, so you can just spawn(flick()) or sleep(flick())
In response to Lummox JR
Lummox JR wrote:
Frame delay I wasn't thinking of so much (it could be built into the animation anyway)

But a developer might want to use the same animation, but at different speeds at runtime.

This has sort of veered away from what I was looking for. Basically I want ideas on how to tell the client that a certain atom or Appearance should undergo an animation, which vars will be changed (from the start of the animation), and on what time scale.

For instance in jQuery, you'd animate something by calling $(element).animate({opacity: 0, height: 10}, {duration: 1000}). This is totally different from BYOND's syntax but I thought there might be correlations we could draw, something that might provide a good way of telling the client which vars to alter. For visual purposes, these vars would all be in play:

Change immediately
icon
icon_state
dir

Change gradually, via interpolation
pixel_x/y/z
layer
alpha (proposed)
transform (proposed)

Except for automated pixel movement, and for a nice means of flicking something permanently to a new state, this would largely be useful for the proposed new vars.
It looks like I'm late to the feature creep party!

Lummox JR wrote:
client-side animation
Well, I really didn't see that one coming! What does this even mean? I'm guessing this would be a server-side proc that can somehow magically do client-side processing. If that's literally what this is, then it will completely wipe the floor with the icon procs! Although now I'm wondering if they too will be given client-side powers.

Now that I think about it, why would you want to create a new proc if you could just add this client-side magic to the current icon procs? Is that already planned, because I think it would make sense to implement that first, before jumping over to this new atom-based method. If the icon procs went client-side, then this kind of processing could be extended to things like overlays.

I guess this would make it a whole lot easier and faster to to manipulate atoms themselves, without having to care about the actual icon. It would be a much more dynamic and flexible way of animating things. This would definitely help to fill the massive gap that currently only flick() resides in.

SuperSaiyanGokuX wrote:
But a developer might want to use the same animation, but at different speeds at runtime.
I have to agree with this. It would be cool if you could dynamically slow things down or speed them up, for some interesting special effects.

Loops?
So, this new proc or flick() overhaul would be able to conditionally loop on its own? That's a somewhat unusual behavior that I haven't really encountered before in a regular procedure. Usually, only the loop procs (for(), while(), etc) are the ones that handle any kind of looping in the code, so it feels kind of awkward to have something like this that can loop on its own. While I feel like it would be more intuitive for this to work with the existing loop procs, I guess it just has to work like this to keep most of the processing on the client's side. If there was some kind of client-side object where procs could be defined to execute client-side, then we wouldn't have a problem like this.

Sounds?
As for sound hooks, while they would be useful, I don't think that such a feature alone is flexible enough. There needs to be a more robust system that can handle atomic sounds. The sounds will need to act more like objects, where they have locs that can be set to container atoms. In another thread I came up with the idea of simply adding them to a built-in list, where they are triggered automatically.

Colors?
Why stop with just changing the alpha value? This is client-side we are talking about! This new proc should be able to do everything that icon.MapColors can and more. Instead of merely being able to change the color, there could also be a delay setting that allows you to animate the changing of the color, in such a way that it would gradually "fade" into the next color. This would allow you to very easily add a fade-in, fade-out, flash, or any kind of bizarre color modification to an object's animation, without the need for a ton of extra icons. You could even use this in combination with pixel offsets to produce some really impressive particle effects! I think this would be much more useful than shaders, but I could see them having their uses as well.

Transforms?
It will be very impressive if we can do client-side scaling and rotation in BYOND. I think this is the most valuable feature listed here so far.

If this is going to be implemented, then you might as well go all the way with it, and add full 3D transform rotation, which should actually open the door to some limited 3D worlds. Technically you could use pure 2D scaling and rotation to softcode 3D transforms, but I'm sure that would end up much less efficient than a fully client-side implementation. I think this would be feasible, since all it would really require at that point is adding in the extra math, although there would probably be a lot of it needed. A scale argument would only really need to cover 2D, since 3D doesn't technically exist on a flat plane. The rotation argument could take 2 different param formats. One would just cover simple 2D rotation, and the other would have rotation along all 3 axes. The 2D format wouldn't really affect the overall shape of the image, but the 3D format would be able to warp and skew the image so that it appears somewhat 3D. While this may not be using the full power of the client's hardware, I think this would still work to a certain degree. I just kind of feel like BYOND desperately needs something like this, when I consider the fact that something as weak as CSS3 can handle 3D transforms, which just makes this seem ridiculous. I have to question my sanity when I go about trying to make a game for an engine that has trouble competing with the likes of CSS! I like BYOND, but I just think it should be able to do anything that such a simple language can.

Once BYOND can do fast scaling and rotation, I think people will start to see it differently, and it may have a real chance in the world. I realize that 3D is certainly not the main goal of scaling and rotation here, but I just wanted to bring it up, since no one has so far. Just having 2D scaling and rotation will greatly speed up so many different types of games out there.

Implementation?
Overall, these are a lot of features to consider, so I'm not sure that trying to cram it all into one proc is the right way to go about the implementation. It wouldn't be a very modular way of doing this, but when it comes to built-in procs, I could really care less about the modularity of the arguments, since I can just define and build up my own systems around it all. However, I think the only way you could fit in all of that information is to use a bunch of different param arguments, separating the input by category. For example, you might have loop-params, color-params, scale-params, and rotation-params, to name a few. I think it may be best to split that into a group of procs, much like the icon procs, but if it all has to be funneled through one proc in order to take advantage of client-side abilities, then I will still be glad that it even exists as a feature. I'm just wondering if this is supposed to be some kind of general catch-all proc for all different kinds of dynamic animation of atoms.


Sorry to carry on like this. I'm just throwing ideas around, and trying to make sense of all this.
Perhaps it would make the most sense to store a series of text commands into a list, and then pass that list into the proc

var/list/effects = list()
effects += "colorfade(color1=#FF0000,color2=#FFAABB,delay=1,frames=3,repeat=4,start=0)"
atom.animate(effects)


or if you went some extra miles here Lummox, the effect procs could return some internal format or binary magic (or a datum or object?)...

var/list/effects = list()
effects += colorfade(color1="#FF0000",color2="#FFAABB",delay=1,frames=3,repeat=4,start=0)
atom.animate(effects)
I would avoid using a string like that if possible since the compiler wouldn't catch any syntax errors within an effect.

A really simple starting point would be:
atom/proc/Animate(property, from, to, duration, repeat=1, interpolator=LINEAR)

The property is ideally a compiler constant like PIXEL_X, ALPHA, etc. From and to are the beginning and ending values. Setting repeat to 0 would loop the animation infinitely. The interpolator option could be excluded for the sake of keeping things simple, but it might add some neat possibilities.
You could call Animate() multiple times to simultaneously animate multiple properties, but each property can only have one animation at a time. Animate(property, null) would end a specific animation and Animate() without and arguments would end all animations.

A more powerful Animate() would take one list of values instead of the from and to parameters. For example:
atom.Animate(PIXEL_X, list(0, 32, 0), 30, 0)
This would move the atom left and right forever.

atom.Animate(PIXEL_X, list(0, 96, 96,  0), 30, 0)
atom.Animate(PIXEL_Y, list(0, 0, 128, 0), 30, 0)
This would move the atom in a triangle from (0, 0) to (96, 0) to (96, 128) and back to (0, 0). Each element in the list is essentially a keyframe. The period of time between each 'keyframe' is of equal length, so each movement here takes 1 second.

A proc in this format is still relatively simple and would work well for most purposes. However, more power might be desirable in some circumstances to control when each keyframe occurs. For example, in the case of the triangle animation, the atom would move faster vertically than it would horizontally because it has to move farther in the same amount of time. A solution for this would probably involve Animate() accepting a list of lists, at which point you have lost a lot of simplicity.
I wouldn't want this to be called for each var though, if it's avoidable because that could get annoying. I think if anything it'd make more sense for multiple calls to setup multiple time blocks or steps.
Page: 1 2 3 4