CategoryDevelopment – Intermediate

Getting started with the Universal Tween Engine

This is a guest post by Alexander Fröhlich. Alexander is a freelance developer and is supporting ANDLABS at its libgdx-based development. 

If you are not familiar with libgdx yet, please check out the first part of this series, the Getting started with libgdx-guide.

 

1 Tweening?

“Tweening” in games is the process of creating intermediate states and thus frames between two or more given states.

Example (Sprite Translation):
The most simple example would be moving a sprite or image from one x1, y1 position to another x2, y2 position on the screen.

Yet, as you might already suspect, this “Universal Tween Engine” is capable of manipulating not only x, y coordinates for sprite objects…. no, this cross-platform-engine written entirely in java language lets you tween every property of any object given that it has its getter/setter methods attached.

In this tutorial I will show you how this comes in handy for game developers when building ingame hints or tutorials for their game.

The following sample code illustrates basic use and setup of the universal tween engine in a libgdx code project.

2 Ingame Tutorial Tweening

First of all, declare your tweenManager instance. The tweenManager lets you keep track and manage all your tweens (i.e. tweening, tween actions and so on)

public class MyGame implements ApplicationListener {

    // Only one manager is needed, like a 
    // libgdx Spritebatch (MyGame.java)

    private static TweenManager tweenManager;

}

Instantiate the manager inside create() of your libgdx lifecycle:

Register an accessor class, which is the key binding between the manager and the object to be tweened. Here this will be the TutorMessage class. (see below).
So after calling registerAccessor every single object of class TutorMessage we create can be tweened by the TweenManager.

@Override
public void create() {
    setTweenManager(new TweenManager());
    Tween.setCombinedAttributesLimit(4);// default is 3, yet
                                        // for rgba color setting          
                                        //we need to raise to 4! 
    Tween.registerAccessor(TutorMessage.class, new 
                             TutorMessageAccessor()); 

}

The TutorMessage’s are the internal game objects for this sample which hold the position, scale and color message attributes.

public class TutorMessage {

    private String message; // string objects can not be tweened
    private float x;
    private float y;
    private Color color;
    private float scale;

}

To tween these message properties and make them accessible by the manager we have to declare how getting and setting every single attribute works.

Getter/Setter
So we define 3 sections (POS_XY, SCALE, COLOR) that process the current float[] values, handled over by the manager during runtime when tweening is active.

Of course same applies for the setters.

public class TutorMessageAccessor implements TweenAccessor<TutorMessage> {

    public static final int POS_XY = 1;
    public static final int SCALE = 2
    public static final int COLOR = 3;

    @Override
    public int getValues(TutorMessage target, int tweenType, 
                           float[] returnValues) {
        switch (tweenType) {
            case POS_XY:
                returnValues[0] = target.getX();
                returnValues[1] = target.getY();
                return 2;

            case SCALE:
                returnValues[0] = target.getScale();
                return 1;

            case COLOR:
                returnValues[0] = target.getColor().r;
                returnValues[1] = target.getColor().g;
                returnValues[2] = target.getColor().b;
                returnValues[3] = target.getColor().a;
                return 4;

            default: 
                assert false; 
                return -1;
        }
    }

    @Override
    public void setValues(TutorMessage target, int tweenType, 
                            float[] newValues) {
        switch (tweenType) {
            case POS_XY: 
                target.setPosition(newValues[0], newValues[1]); 
                break;

            case SCALE: 
                target.setScale(newValues[0]); 
                break;

            case COLOR:
                Color c = target.getColor();
                c.set(newValues[0], newValues[1], newValues[2], 
                        newValues[3]);
                target.setColor(c);
                break;

            default: 
                assert false;
        }
    }
}

Having bind our TutorMessage class to the TweenManager we can now integrate it into the game.
Remember? We want to provide a kind of ingame tutorial system. So every time our user should see an animated on-screen help, we call the now defined method. The tweenHelpingHand method takes the parameter targetX, targetY that indicate the position where the helping hand (sprite) and its bound message (bitmapfont) should move to.

Then we say Tween
  .to (
      – TutorMessage currentTm ( the message to be moved )
      – int TutorMessageAccessor.POS_XY (constant to select which property should be tweened)
      – float 3f (total tweening duration)
  )
  .target (
    – targetX, targetY ( the final screen position of our tweened message )
  )
  .ease (
    – TweenEquations.easeOutCirc ( one possible interpolation pattern – i.e. moving pattern here)
  )
  .start (
    – MyGame.getTweenManager()  ( binds this tween to the manager )
  )

private void tweenHelpingHand(int targetX, int targetY) {

    // kill current tween - or pre-existing
    MyGame.getTweenManager().killTarget(currentTm);

    // move
    Tween.to(currentTm, TutorMessageAccessor.POS_XY, 3f)
         .target(targetX, targetY)
         .ease(TweenEquations.easeOutCirc)
         .start(MyGame.getTweenManager());

    // colorize
    Tween.to(currentTm, TutorMessageAccessor.COLOR, 3f)
         .target(1f, 1f, 1f, 1f)
         .ease(TweenEquations.easeOutCirc)
         .start(MyGame.getTweenManager());

}

Finally we have to call update inside the libgdx render() method to have the started Tween be updated constantly.

MyGame.getTweenManager().update(delta);

Here you go!
Enjoy this very powerful any easy to use tweening library.

Combining Scene2d animations and Tweening is also possible. You just have to write the ActorAccessor binding class and provide access (getter/setter) to its properties.
Like with Scene2d actions, the universal tween engine also allows sequencing of multiple tweens!

 

If you have any questions or suggestions, please leave a comment.

How to add attributes to your custom View

Jack just asked the following questions on the tutorial for animated GIFs I once wrote:

“I want to be able to place the GifMovieView in an existing layout (like any regular control).
Please give me a step-by-step of how to bind xml layout attributes to this custom view.”

A good question. Here’s the answer.

1 Use your own View in an XML

To place your own View in an layout XML file, just use it like a normal view, only that you have to append the whole package name up front. Something like:

< eu.andlabs.tutorial.animatedgifs.views.GifMovieView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/my_id"
/>

In this XML, you can already use the standard Android attributes.

2 Define your custom attributes

If you want to define your own, custom attributes, go to the res/values-folder and create a file called attrs.xml.

You can define your custom attributes here. In the end, it should look like this:

< ?xml version="1.0" encoding="utf-8"?>
< resources>
< declare-styleable name = "eu.andlabs.tutorial.animatedgifs.view.GifMovieView">
< attr name="url" format="string" />
< attr name="fetchAutomatically" format="boolean" />
< /declare-styleable>
< /resources>

You can now address these attributes in your XML layout. To do so, add something like

xmlns:gif="http://schemas.android.com/apk/res-auto"

To your root layout element. Please notice that this only works with ADT 17 and older. Now you can access your attributes in your layout like this:

< eu.andlabs.tutorial.animatedgifs.views.GifMovieView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/my_id"
gif:url="http://mygif.com/mygif.gif"
gif:fetchAutomatically="true" 
/>

3 Handle the attributes in your View

Since the XML is done, it’s time to address the Java part, which means the custom View. You should at least overwrite the constructor that is receiving a Context and an Attributes-object. Like so:

public GifMovieView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(attrs);
}

You can now access your custom attributes in using the AttributeSet:

private void init(final AttributeSet attrs) {
if (attrs != null) {
String packageName = "http://schemas.android.com/apk/res-auto";
mUrl = attrs.getAttributeValue(packageName, "url");
mFetchAutomatically = attrs.getAttributeBooleanValue(packageName, "fetchAutomatically", false);
}
}

Do whatever is needed with it. That’s already it.

 

I hope you enjoyed this post. Please feel free to ask anything you want in the comments.

And remember: Sharing is caring!

The new madvertise SDK: How to migrate

Three days ago, madvertise officially announced the availability of their new SDKs for Android and iOS.

What has changed?

This time, besides minor changes, rich media functionality, or to be more precise, the MRAID v. 1.0-standard, was implemented. For ads this means: They can be completely written in HTML 5 and they can access some extra functionality via JavaScript. With this extra functionality, for MRAID 1.0, ads are able to expand in size up to full screen. However, madvertise takes care that only ads requested in full screen mode will expand themself immediately. For smaller banner formats like MMA, ads will only expand on user interaction.

How to migrate?

First, install git.

Second, learn how to use git. Seriously.

Third: Clone the madvertise repository into your workspace or wherever you want it to be: git clone git://github.com/madvertise/madvertise-android-sdk.git. In case you already cloned the repository once, pull the new changes.

Now switch to the new mad_mraid10- branch: git checkout mad_mraid10

Import the SDK using new -> Android Project -> from existing source. In case you just pulled in step three, just select your madvertise SDK-project and hit F5. In the SDK Project you should now see a new class called MadvertiseMraidView.java. In the projects integrating the madvertise SDK as a source project, you should see some compile errors at the places where you implemented the MadvertiseCallbackListener. Add the unimplemented methods. They are:

public void onAdClicked()
public void onApplicationPause()
public void onApplicationResume()

onAdClicked() is, obviously, called when an ad is clicked by a user. In this method you can track ad clicks or reward your users by removing the ad for a couple of seconds. In case you want to do so I recommend something like
mMadView.setFetchingAdsEnabled(false);
mMadView.setVisibility(View.GONE);

setFetchingAdsEnabled(boolean isEnabled) allows you to stop fetching ads for a given MadvertiseView or to start it again.
onApplicationPause() is called when a rich media ad is expanded and the actual app content is not in the foreground anymore. The easyest construct here is to directly call onPause() from this method. onApplicataionResume() is the corresponding counterpart to onResume().

Lets look into the XML code, first into the attrs.xml. Here, add < attr name="placement_type" format="string" /> and < attr name="mraid" format="boolean" />. Obviously, you can include those values into your layout files as well:
mad:placement_type="interstitial"
mad:mraid="true"

Placement type declares how you plan to place your rich media ads. Interstitial is perfect when loading something and showing an ad in the meantime, for example full screen. Inline is more suitable for most of the other cases. With the mraid-attribute you declare whether you want rich media ads to be delivered to your app or not. In other words: If you want everything to stay the way it was, set mad:mraid="false". The default for this attribute is true, so if you want rich media functionality, you can leave your layout files just the way they were. With one exception: In case you already upgraded to SDK tools in revision 17, you should now replace the ‘xmlns:mad=...‘-namespace with xmlns:mad="http://schemas.android.com/apk/res-auto".

And that’s already it.

Conclusion

madvertise’s eCPMs and fillrates really sucked in the last months. However, the company doesn’t give up and promises higher costs per click for the new rich media ads. I hope they keep their word and that the rich media ads won’t be too annoying. Let me know what you think (and hope) in the comments.

Tutorial: How to play animated GIFs in Android – Part 3

Animated GIFs in Android is a difficult topic. It is an issue that has been discussed heavily and still, it is very difficult for developers to bring GIFs to life. There are three ways to animate GIFs on Android, each of them has its pros and cons. Each part of this series will cover one of these approaches.

Getting started

For this example, we will use an image I found on gifs.net, it’s this one:

I will store it in our project’s asset folder and name it ‘piggy.gif’. We will also use an Activity to set the views we define as content views. If you want to know everything about playing GIFs, please start at part one.

Approach 3: Using a WebView

This is the by far easyest way. As you might know, a WebView is able to do what a browser does. And since the browser of Android devices using Android 2.2 + supports the animation of GIFs (at least on most devices), we can just use that.

So, at first, we extend our own class by a WebView:

public class GifWebView extends WebView

We create a constructor that takes both a context to call the constructor of the mother-class and a path to the file. We use loadUrl() to load that file into our WebView:

   public GifWebView(Context context, String path) {
      super(context);
      loadUrl(path);
   }

Now, let’s go back to our Activity which we created in the first tutorial. Here, we create our view and pass it a context and path to our GIF-file:

   GifWebView view = new GifWebView(this, "file:///android_asset/piggy.gif");
   setContentView(view);

And now, believe it or not, we are done.

Movie, GifDecoder or WebView?

Which way you take depends on your needs. When your app is targeting users mainly using devices with Android 2.2+, the way described above is probably your way to go. If you want to support as many devices as possible and don’t care much about memory footprint, you can also use the GifDecoder-method. When you want to support many users but don’t want to recycle tons of Bitmaps, and are sure the format of your GIFs can be played using the Movie-class, then this approach is for you.

Personally, I prefer the WebView-way. Because WebKit is already implemented native, it’s memory footprint is really low, especially when compared to the GifDecoder. Operations on images like scaling can be performed simply by using HTML and the overall code is really short and pretty.

 

You can checkout the code of the three parts of this series at http://code.google.com/p/animated-gifs-in-android/.

 

Which method do you like best? As always, please feel free to leave your thoughts in the comments.

© 2024 Droid-Blog

Theme by Anders NorenUp ↑