finer grained animation control for tripleplay?

247 views
Skip to first unread message

Jeramie Risinger

unread,
Dec 19, 2012, 1:07:30 PM12/19/12
to pl...@googlegroups.com
I'm looking for a way to more exactly and programatically control the animations for a given sprite.  The examples on all of the three rings stuff has been super helpful in figuring out how to start, run, and repeat an animation, but my google fu fails me when I look for proper ways to stop an animation, start another one, stop that, start another one.

Should I simply have an image layer for each animation that I wish to display, add them all to the same group layer for positioning, and when I wish to show one, set that particular image layer to be visible and hide the rest?  Should I be creating and destroying image layers each time I finish with a flipbook animation?  Should I be extending/implementing my own Frames class instead of using SimpleFrames?  Should I not be using repeat if I plan to stop and start it all the time?

Here are some snippets, let me know if I'm being unintelligible.  It happens.  Also, thanks in advance for any help!  :)

@Override
protected Group createIface() {
animGlayer
= graphics().createGroupLayer();
layer
.addAt(animGlayer, 100, 50);
fullSheetHeight
= 320;
fullSheetWidth
= 1600;
oneImageWidth
= fullSheetWidth / 10;
oneImageHeight
= fullSheetHeight / 2;

animLayer
= graphics().createImageLayer();
layer
.add(animLayer);
Image image = assets().getImage("images/myAlienSprites.png");

  image
.addCallback(new Callback<Image>() {
   
public void onSuccess(Image image) {
   
Region swimAlien = image.subImage(0, 0, fullSheetWidth, oneImageHeight);
   
SimpleFrames frames = new SimpleFrames(swimAlien, oneImageWidth, oneImageHeight);
    swimLeftFlipbook
= new Flipbook(frames, 100);

   anim
.repeat(animLayer).flipbook(animLayer, swimLeftFlipbook);
   anim
.add(animGlayer, animLayer);//(layer, animLayer);
   animLayer
.setOrigin(oneImageWidth / 2, 0);
 
}

 
@Override

 
public void onFailure(Throwable cause) {

   
PlayN.log().warn("dood"+cause.getMessage());
}


});

animLayer
.addListener(new Pointer.Adapter() {
            public void onPointerStart(Pointer.Event event) {
                    //anim.flipbook(animLayer, swimLeftFlipbook).then()....? new runnable?  destroy the layer?  hide it?
                    //proper code to halt the animation.
            }
});

return null;
}







Michael Bayne

unread,
Dec 19, 2012, 2:26:52 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 10:07 AM, Jeramie Risinger <jeramie....@gmail.com> wrote:
Here are some snippets, let me know if I'm being unintelligible.  It happens.  Also, thanks in advance for any help!  :)

I think you are using the animation stuff in a way that is not going to work out very well.

The TriplePlay animation code is not meant to form the basis of an animated game entity system. If you have game objects (like aliens) that are going to have different modes and will display different animations in relation to those modes (or other events), you want a totally different animation control system than the one provided by TPAnim. TPAnim is for one-shot animations, like floating a number up over an enemy that was damaged and fading it out, or for adding animated bits to a user interface, like a gleam on a button.

Game entities with states and associated animations should be handled by a system more like FlashBang: https://github.com/threerings/flashbang-playn Unfortunately FlashBang is totally undocumented and is a bit overbearing in that it makes you structure your app around it.

You can still use TPAnim's Flipbook, and you could even use Animation.Flip, but you'd call init() and apply() yourself based on an update call happening on your game entity. Then it would pick the appropriate Flipbook to use based on its state.

Maybe if I ever have free time again, I'll make a TPEntity system for displaying graphical game entities that have states and animations and do proper lifecycle management and much of what FlashBang does, but in the same a la carte way that all of TP's services are structured.

With all that out of the way, you *can* do what you want. You can do anything with TPAnim, it just won't be pretty. For example:

class Alien {
  // this controls the position and orientation and whatever
  public final GroupLayer layer = PlayN.graphics().createGroupLayer();

  public void setAnimation (Animator anim, Flipbook book) {
    stopAnimation(); // stop any existing animation
    layer.add(_blayer = PlayN.graphics().createImageLayer());
    _current = anim.repeat(layer).flipbook(_blayer, book).handle();
  }

  public void stopAnimation () {
    if (_current != null) {
      _current.cancel();
      _current = null;
    }
    if (_blayer != null) {
      _blayer.destroy();
      _blayer = null;
    }
  }

  protected ImageLayer _blayer;
  protected Animation.Handle _current;
}


golee...@gmail.com

unread,
Dec 19, 2012, 2:38:20 PM12/19/12
to pl...@googlegroups.com
It's possible to fetch a handle on the animation, using handle(), which can be used to cancel the animation.

To cancel a animation which is being repeated you will have to fetch the handle on the repeat function before you start queuing up the animations on it.

At least this is the way that we are doing it.

Hope that it makes sense.

Michael Bayne

unread,
Dec 19, 2012, 2:45:45 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 11:38 AM, <golee...@gmail.com> wrote:
To cancel a animation which is being repeated you will have to fetch the handle on the repeat function before you start queuing up the animations on it.

That's not necessary. The animation system (as of 1.5.1 or so) tracks the "originating" animation and returns that as the handle so that cancelation works properly. So this does what you want (returns a handle on the repeating animation):

    _current = anim.repeat(layer).then().flipbook(_blayer, book).handle();

Jeramie Risinger

unread,
Dec 19, 2012, 3:15:22 PM12/19/12
to pl...@googlegroups.com
That makes sense.  I was getting the feeling of what they were meant for each time I tried to make them do more of, as you described it, Game Entities with associated animations.  Thanks for the heads up and quick reply.  If it's not much of a performance hit to dust and recreate layers like that, I could see making use of them in the interim.  

If I come up with something different that does this good stuff and seems share-worthy, I'll let you know and you can see if it's worth grabbing.

Thanks again.  It really helps to know, one way or another, whether I'm making the right assumptions when using some of this code.  :)

golee...@gmail.com

unread,
Dec 19, 2012, 3:48:54 PM12/19/12
to pl...@googlegroups.com
Hmm ok. I couldn't get it working a couple of weeks ago when using repeat, it worked when canceling a single shot animation but using repeat I had to do:

Animation a = _anim.repeat(layer);
Handle h = a.handle();
a. ... queue up other animations;
h.cancel();

Probably errors in the code, writing from memory.

Will try it again using latest tp.

la...@bulbsort.com

unread,
Dec 19, 2012, 4:33:46 PM12/19/12
to pl...@googlegroups.com
I have tried it now using latest Tripleplay and PlayN (sorry for different account). Still won't work using repeat in that way that you describe.

THIS CODE WORKS:
Animation.Repeat cr = _anim.add(new Animation.Repeat(jumpLayer));
final Handle h = cr.handle();
cr.then().tweenX(jumpLayer).to(300).in(1960).then().tweenX(jumpLayer).to(100).in(1960);

_timer.after(5000, new Runnable() {
   @Override
   public void run() {
      h
.cancel();
   }
});


THIS CODE DOES NOT WORK:
final Handle h = _anim.repeat(jumpLayer).tweenX(jumpLayer).to(300).in(1960).then().tweenX(
   jumpLayer
).to(100).in(1960).handle();

_timer.after(5000, new Runnable() {
   @Override
   public void run() {
      h
.cancel();
   }
});


Michael Bayne

unread,
Dec 19, 2012, 4:58:44 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 1:33 PM, <la...@bulbsort.com> wrote:
THIS CODE DOES NOT WORK:
final Handle h = _anim.repeat(jumpLayer).tweenX(jumpLayer).to(300).in(1960).then().tweenX(
   jumpLayer
).to(100).in(1960).handle();

_timer.after(5000, new Runnable() {
   @Override
   public void run() {
      h
.cancel();
   }
});


Oops. I guess when I fixed the canceling of chains of animations, I missed the repeat animation, which does some special stuff. It's fixed now:


The whole point of passing a layer to repeat() is that you cancel the repeating by removing/destroying the layer. But I suppose there are cases where people want to use TPAnim for entity/character animation purposes and it's useful to be able to repeat an animation on a layer and then cancel it and repeat a new animation.

I should perhaps add a repeat() that takes no layer, since you can just cancel it manually, but I suppose it's nice to also have the fallback lifecycle management in place that if your primary layer goes away, so should the animation that's being processed on it.

I am not thrilled with this design, but as I said before, TPAnim is not designed for character/entity animation systems (which provide much more robust lifecycle management as well as much better transitions than just "stop the animation on whatever frame it happens to be processing and start this new one"). It's meant for one-shot animations that you fire and forget. I only added repeat() so that I could animate throbbers which let you know that some processing is taking place by repeating a short animation, and then go away when the processing is done.

Anyway, it works now, and code should work properly. So that's good. :)

-- m...@samskivert.com

la...@bulbsort.com

unread,
Dec 19, 2012, 6:08:21 PM12/19/12
to pl...@googlegroups.com
Works like a charm, awesome!

We use the tp animation system to animate a lot of in game stuff in the game which we currently are developing, and we haven't encountered any giant obstacles yet. Patrolling monsters, player animation, etc. Flipbook+tween(Value) seems nice for a lot of stuff. We haven't started to think about nice looking transitions yet, and when we do maybe we need to find some other way to do our animations.

What do you use at OOO? Flashbang? Or maybe something more secret and closed source :)

We have also been looking a little on Flump, and it looks very interesting. But it looks like one have to buy some Flash animation tool to create useable animation data.

Michael Bayne

unread,
Dec 19, 2012, 6:21:53 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 3:08 PM, <la...@bulbsort.com> wrote:
Works like a charm, awesome!

Great! 
 
We use the tp animation system to animate a lot of in game stuff in the game which we currently are developing, and we haven't encountered any giant obstacles yet. Patrolling monsters, player animation, etc. Flipbook+tween(Value) seems nice for a lot of stuff. We haven't started to think about nice looking transitions yet, and when we do maybe we need to find some other way to do our animations.

I agree that React and the TriplePlay stuff are a good solution to a wide variety of animation and user interface problems. I just have not used the TPAnim stuff for a game that uses animated characters that move around and transition between animations in the standard way, and I suspect that it's not a perfect match. Some day I eventually will and I'll probably create TPEntity or something like that to simplify things and smooth out the rough edges.
 
What do you use at OOO? Flashbang? Or maybe something more secret and closed source :)

I used TPAnim entirely for Spellwood, but Spellwood does not have any sort of entity or character animation system because it's not a game where you control a little guy that moves around and interacts with an environment. We had another game in development (which tragically got canceled) which was using FlashBang and Flump and it very definitely had little guys that move around and interact with an environment and transition between different animation states. We have yet another project in development which is using Flump for animation, but has its own hand-rolled entity system and uses TPAnim mostly just to schedule state changes, but not to actually run the animations.

We have also been looking a little on Flump, and it looks very interesting. But it looks like one have to buy some Flash animation tool to create useable animation data.

Flump is designed for studios (like ours) that are transitioning away from making Flash games, and who have a bunch of artists who are comfortable making animations using the Flash Authoring Tool and who would like to keep doing that, instead of learning some totally new tool which probably totally sucks compared to the (expensive, commercial) Flash Authoring Tool.

Letting your artists use the tools they're comfortable with tends to more than pay for the cost of the tool. We could force all of our artists to use Gimp instead of Photoshop, and within a week or two we will have spent the cost of the Photoshop licenses in lost productivity.


Jeramie Risinger

unread,
Dec 19, 2012, 6:38:46 PM12/19/12
to pl...@googlegroups.com
I pulled down latest & built.  Got the change.  However, if I try what you suggested, either destroying & recreating or simply canceling, i get a null pointer exception in the Animation class.


 // if we have no next animation, return our overflow
 _current
= _current.next();
 
if (_current == null) return remain;

(around line 408).

I found that If I open up the Animator class and add an extra if statement to see if current happened to have been unset after the while loop was entered, assuming 0 frames remaining, I just return 0.


while (remain <= 0) {
   
// if we've been canceled, none remaining
   
if(_current == null) return 0;
   
// if we have no next animation, return our overflow
    _current
= _current.next();
   
if (_current == null) return remain;


 This fixes the exception and I think gets most of what I'm looking for, in that I get to keep my imageLayer around, I can just cancel it at will and replace the flipbook in it with a different one.  For instance, I can do something like this:

alien.setAnimation(anim, rotatingFramesFlipBook).then().action(new Runnable(){
 @Override
 
public void run() {
   alien
.setAnimation(anim, swimLeftFlipbook);
 
}
});


It looks like it's possible to get a null pointer in the while loop, possibly because of the current.apply()?  

Michael Bayne

unread,
Dec 19, 2012, 6:46:32 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 3:38 PM, Jeramie Risinger <jeramie....@gmail.com> wrote:
I pulled down latest & built.  Got the change.  However, if I try what you suggested, either destroying & recreating or simply canceling, i get a null pointer exception in the Animation class.

This is why TPAnim is not designed for this sort of thing. :)

The problem is that you're canceling an animation while that animation is currently executing. Again, that should work, so I'll sort out a fix for it.

Also, this is kind of weird:

alien.setAnimation(anim, rotatingFramesFlipBook).then().action(new Runnable(){
 @Override
 public void run() {
   alien.setAnimation(anim, swimLeftFlipbook);
 }
});

If you want to set one animation, then set another, just do something like:

anim.flipbook(..., rotatingFramesFlipbook).then().flipbook(..., swimLeftFlipbook);

It's a little weird to run an animation and then tack an action onto the end that cancels the current animation (which is just finishing up anyway) and starts a new one.

Anyway. I'll fix the bug.

-- m...@samskivert.com

Jeramie Risinger

unread,
Dec 19, 2012, 6:51:10 PM12/19/12
to pl...@googlegroups.com
Yeah, if there's a better way, I'll go for that.

I'm trying to do something like:
  1.  animateLeft when moving left.
  2.  Cue turn animation right before/during turning around.
  3.  After turn animation is complete, we're moving "right".  so play the rightMotion animation.
The whole time there's one animation constantly running, whether left, right, or rotate.  Lemme know if there's a better way to accomplish it.  :)

Michael Bayne

unread,
Dec 19, 2012, 6:58:45 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 3:51 PM, Jeramie Risinger <jeramie....@gmail.com> wrote:
I'm trying to do something like:
  1.  animateLeft when moving left.
  2.  Cue turn animation right before/during turning around.
  3.  After turn animation is complete, we're moving "right".  so play the rightMotion animation.
The whole time there's one animation constantly running, whether left, right, or rotate.  Lemme know if there's a better way to accomplish it.  :)

Again, we're out in the forest where TPAnim is not well suited to these sorts of things, but you could do something like:

class Alien {
  // this controls the position and orientation and whatever
  public final GroupLayer layer = PlayN.graphics().createGroupLayer();

  public void goLeft () { startAnims(null, goLeftBook); }
  public void turnLeft () { startAnims(turnLeftBook, goLeftBook); }
  public void goRight () { startAnims(null, goRightBook); }
  public void turnRight () { startAnims(turnRightBook, goRightBook); }

  protected void startAnims (Flipbook transition, Flipbook repeated) {
    stopAnimation();
    layer.add(_blayer = PlayN.graphics().createImageLayer());
    if (transition == null) {
      _current = anim.repeat(layer).flipbook(_blayer, repeated);
    } else {
      _current = anim.flipbook(_blayer, transition).then().
        repeat(layer).flipbook(_blayer, repeated);
    }
  }

  protected void stopAnimation () {
    if (_current != null) {
      _current.cancel();
      _current = null;
    }
    if (_blayer != null) {
      _blayer.destroy();
      _blayer = null;
    }
  }

  protected ImageLayer _blayer;
  protected Animation.Handle _current;
}

Where the key difference here is that you are queuing the turn animation and the repeated going animation in the same animation sequence.


Michael Bayne

unread,
Dec 19, 2012, 6:59:26 PM12/19/12
to pl...@googlegroups.com
On Wed, Dec 19, 2012 at 3:58 PM, Michael Bayne <m...@samskivert.com> wrote:
    if (transition == null) {
      _current = anim.repeat(layer).flipbook(_blayer, repeated);
    } else {
      _current = anim.flipbook(_blayer, transition).then().
        repeat(layer).flipbook(_blayer, repeated);
    }

Oops, those should have .handle()after them.

-- m...@samskivert.com

Jeramie Risinger

unread,
Dec 19, 2012, 7:36:49 PM12/19/12
to pl...@googlegroups.com
I'll give 'er a try when I get some time.  Thanks!


--
 
 
 

la...@bulbsort.com

unread,
Dec 20, 2012, 7:40:55 AM12/20/12
to pl...@googlegroups.com

Flump is designed for studios (like ours) that are transitioning away from making Flash games, and who have a bunch of artists who are comfortable making animations using the Flash Authoring Tool and who would like to keep doing that, instead of learning some totally new tool which probably totally sucks compared to the (expensive, commercial) Flash Authoring Tool.

Letting your artists use the tools they're comfortable with tends to more than pay for the cost of the tool. We could force all of our artists to use Gimp instead of Photoshop, and within a week or two we will have spent the cost of the Photoshop licenses in lost productivity.



Yeah I suspected that was why you stayed close to the Flash stuff.

Just out of curiosity. If you were starting up a company with only two guys who are mainly coders and who are trying to fill all the roles in the game making process, and these guys are open to switch to which ever coding language and whatever tools to fulfil their mission. What languages and tools would you use to be able to get into creating the actual games as quick as possible and release them on Android, iOS and HTML5?

As of now we are using PlayN, Inkscape, Gimp, Blender and Garageband. But sometimes I wonder if it wouldn't be better to just go with Unity or something more streamlined. But then we would loose HTML5, open source and get some extra licensing costs.

Sorry for derailing the thread :D

Michael Bayne

unread,
Dec 20, 2012, 12:23:32 PM12/20/12
to pl...@googlegroups.com
On Thu, Dec 20, 2012 at 4:40 AM, <la...@bulbsort.com> wrote:
Just out of curiosity. If you were starting up a company with only two guys who are mainly coders and who are trying to fill all the roles in the game making process, and these guys are open to switch to which ever coding language and whatever tools to fulfil their mission. What languages and tools would you use to be able to get into creating the actual games as quick as possible and release them on Android, iOS and HTML5?

I did a lot of research on this before I adopted PlayN for Three Rings' future cross-platform development. If you want to support mobile and broad web browser penetration, then your choices are substantially limited.

As of now we are using PlayN, Inkscape, Gimp, Blender and Garageband. But sometimes I wonder if it wouldn't be better to just go with Unity or something more streamlined. But then we would loose HTML5, open source and get some extra licensing costs.

Unity is decent if you want to do 3D games, but for 2D games, it's probably more trouble than it's worth. A number of games (most notably Bastion ) have had success with XNA/MonoGame, which allows you to deploy to XBOX, iOS, Android and Chrome (via NaCL). That means C# development, which is a nicer language than Java, but which has a far less robust tools ecosystem.

There are also projects that purport to compile C or C++ into decently performant JavaScript (Emscripten, and I think there's one other). If you like C or C++ this is not a totally crazy approach, but you have to cobble together the platform specific bits for Android and iOS yourself, it's not nearly as turn-key as PlayN or Unity or MonoGame.

Lastly, there's Flash/Air, which in spite of all of the rumors of its death, is actually evolving to survive the massive transition to mobile devices. I know a number of indy game developers who exclusively develop in Flash (notably Colin Northway, of Fantastic Contraptions fame, and his wife Sarah, who has developed half a dozen Flash games and is selling them successfully on iOS and through web Flash portals). The key is to use Stage3D and a toolkit like Starling, though Sarah has also successfully made non-graphically-intensive games using Flash's traditional 2D rendering pipeline.

There are many other choices out there, but these are the ones that seemed most feasible when I was looking around.

We went with PlayN because we had been making games in Java for the previous nine years (and ActionScript, but no one ever really enjoyed ActionScript). we have a team of engineers who are super comfortable in Java and tools used to develop and debug Java. We have also benefited greatly from using Java for both the client and server in our big games (Puzzle Pirates, Bang! Howdy, Spiral Knights), and wanted to be able to leverage that in this crazy HTML + mobile future.

I should also point out that LibGDX is a lot like PlayN (Java-based, supports Android/iOS/HTML5) and is more mature in many ways. They also have native library extensions for things like Box2D (which I'm currently working on adapting/stealing for PlayN :).

-- m...@samskivert.com

la...@bulbsort.com

unread,
Dec 21, 2012, 5:41:38 PM12/21/12
to pl...@googlegroups.com
Thanks for the excellent input!

It feels like even for us, who haven't got that kind of time invested in Java and tools, it will probably be best to continue down the path with PlayN.

But seeing that LibGDX uses Java, is more mature in many ways and will support Android, iOS and HTML. Wouldn't it be better if everyone on PlayN switched to LibGDX instead? Boosting the progress of it. Or why did you guys on OOO choose PlayN over LibGDX?

Michael Bayne

unread,
Dec 21, 2012, 6:09:42 PM12/21/12
to pl...@googlegroups.com
On Fri, Dec 21, 2012 at 2:41 PM, <la...@bulbsort.com> wrote:
But seeing that LibGDX uses Java, is more mature in many ways and will support Android, iOS and HTML. Wouldn't it be better if everyone on PlayN switched to LibGDX instead? Boosting the progress of it. Or why did you guys on OOO choose PlayN over LibGDX?

I feel like I've answered this question five times in different venues, but let's go for a sixth:

When I was looking into cross-platform toolkits that supported both mobile and HTML5, LibGDX supported only Android and didn't look like it would ever support anything else, or was ever intended to support anything else. It used native libraries which seemed like they would be a clear non-starter for an HTML5 port. PlayN on the other hand supported HTML5, Android and Flash when I first saw it. It was far more obviously designed to be cross-platform.

In the end, LibGDX was ported to HTML5 (which may have been Mario's intention all along, but my cursory investigation of LibGDX a year and a half ago didn't reveal any indication of that), and eventually to iOS. So now the two libraries are much closer in terms of functionality and supported platforms.

As for why I don't throw everything out the window today and jump on the LibGDX bandwagon? I've rewritten or written the vast majority of the PlayN code at this point, so I know how it all works, where its limitations are, how it can be improved, how I would go about improving it, etc. Even if LibGDX could do something PlayN couldn't, it would be vastly more efficient for me to make PlayN do it than to learn LibGDX as deeply and switch all of my efforts (and Three Ring's engineers) over to a new train.

-- m...@samskivert.com

la...@bulbsort.com

unread,
Dec 21, 2012, 6:43:28 PM12/21/12
to pl...@googlegroups.com
I fail at searching around before asking stupid questions as usual :D

Thanks for the off topic chat anyways, I feel more assured that we are on the right track with our chosen framework now.

Daniel Gerson

unread,
Aug 17, 2013, 5:40:34 PM8/17/13
to pl...@googlegroups.com, la...@bulbsort.com
Are there any advantages to the *one-shot* design approach of TPAnim as you described in this thread?
Having written a little documentation for others, I kind of feel obliged to add a warning that adopting TPAnim can get them into a bind depending on their expectations.

Seems to me either the one-shot approach yields some advantages, or the current api should be considered a stepping stone to a more configurable finite state machine come scheduler. Doesn't seem like there's a good reason why a more complex solution under the hood of the same api couldn't handle all cases... and lead to only one grand master animator per app. Obviously it only makes sense for someone to do that work when that someone needs it (luckily I don't at the moment), but the idea of handling false-alarm, backtracking etc seems to me like a pretty common use case (never mind arbitrary animation stacking, ragdoll modes etc)

Also, I regard myself a convert to the Chris Pruett highlighted zero allocation game design philosophy, so the ChainBuilders fill me with angst :-)

Always good to know where we're headed.

DMG


Reply all
Reply to author
Forward
0 new messages