Jump to content

Generic Java Importer

Recommended Posts

Hey guys,

I worked a little bit further on the library and made some changes in the inverse kinematics handling. If you want to apply inverse kinematics on a player you just need an instance of SpriterIKResolver class, which is an abstract class, means you need a specific algorithm to solve the constraints. Anyway, there is a SpriterCCDResolver class, which does the job for you.

To apply inverse kinematics create a SpriterIKObject instance and map it to a bone or a sprite with

yourResolver.mapIKObject(ikObject, boneOrSprite);

and in your update logic method just call


to resolve the whole stuff.

Before calling resolve(yourPlayer), you need to deactivate all effectors, otherwise the resolver will have no effect on the animation:

yourResolver.deactivateEffectors(yourPlayer, true);

If you do not want the resolver to apply IK for some reason, just call:

yourResolver.activateEffectors(yourPlayer);//Activates all effectors which where mapped before
yourResolver.activateAlll(yourPlayer);//To activate all bones, no matter if they were mapped or not

Play with it around.

The drawing works also a little bit different now. Your specific drawer needs now to implement drawLine, drawRectangle and setDrawColor. This enables the ability for the AbstractDrawer class to debugDraw an animation for every backend in the same way.

The FileLoader class gets now notified if all textures have been loaded. You can just reimplement the method finishLoading if necessary (to generate an atlas or whatever).

Character mapping is not implemented yet, but you can bypass this issue by creating a new loader for each character map and pass the loader to your player. I need an example file to implement the feature. I would really appreciate if someone could upload one, since I do not have Spriter Pro.

Furthermore I created a little demonstration video, to show you some features of the library:

The runnable demo can be downloaded via a link in the video description.

-Trixt0r ;)

Share this post

Link to post
Share on other sites

Hi trixtor,

I want to ask if it works on Android.

I trying to implement your solution, in desktop I have no problem with showing animation.

But on android I have Class Not Found expection on SpriteLoader and SpriteDrawer classes.

Share this post

Link to post
Share on other sites

Hi Michalko,

Hmmm... I would say this error has nothing to with the library. This is an android issue, I guess.

Try to create a new android project which uses the library. Sometimes the android sdk does sometimes weird things.

Last time I tested it on android, it worked for me. I will try it again for myself.

- Trixt0r

Share this post

Link to post
Share on other sites

Hi Trixtor, thank you for your quick answer.

I found error. I have set compiler to 1.7 in Spriter, and 1.6 in android project ... :roll:

But now I had nullpointer expection in android, on SpriterPlayer init.

On desktop it work, but only if i have a monster folder in desktop projekt folder. I didnt take resources from asset, but they are linked.

On android there is

09-16 10:59:20.205: E/AndroidRuntime(26435): FATAL EXCEPTION: GLThread 25281

09-16 10:59:20.205: E/AndroidRuntime(26435): java.lang.NullPointerException

09-16 10:59:20.205: E/AndroidRuntime(26435): at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java:103)

I use your loader and drawer, and i just showing animation in middle of screen.

I created new project via Libgdx setup ui.

My loading code is:

public GameScreen(MainGame game)
this.game = game;
this.batch = new SpriteBatch();
this.shapeRenderer = new ShapeRenderer();

this.loader = new SpriterLoader(true);

this.drawer = new SpriterDrawer(this.batch);
this.drawer.renderer = this.shapeRenderer;

try {
spriter = Spriter.getSpriter(Gdx.files.internal("monster/basic.scml").file(), loader);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
camera = new OrthographicCamera();

this.player = new SpriterPlayer(spriter, 0, loader);

Share this post

Link to post
Share on other sites

Hmm... could you please post the whole stack trace? This could give me more information about the problem.

I am not at home right now and can not test it on my android device.

I bet there is again an issue in loading files on android. Could you please try:

spriter = Spriter.getSpriter(Gdx.files.internal("monster/basic.scml").file().getAbsolutePath(), loader);
Spriter.getSpriter(Gdx.files.internal("monster/basic.scml").file().getAbsoluteFile(), loader);

If this does not work, try to load the scml file like this:

FileHandleSCMLReader.getSpriter(Gdx.files.internal("monster/basic.scml"), loader);

I just wrote an extra scml reader for LibGDX specific file handles and didn't test it on android.

Or just let the code as it is and just change in the SpriterLoader class the following line

FileHandle f = Gdx.files.absolute(path);


FileHandle f = Gdx.files.internal(path);

Let me know if it worked.

Share this post

Link to post
Share on other sites


I did the change in SpriterLoader before, but it didnt work too for me (absolute to internal).

i tried your other tips, but nothing work.

this si my full stack trace:

09-16 13:51:36.447: E/AndroidRuntime(2469): FATAL EXCEPTION: GLThread 26298
09-16 13:51:36.447: E/AndroidRuntime(2469): java.lang.NullPointerException
09-16 13:51:36.447: E/AndroidRuntime(2469): at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java:103)
09-16 13:51:36.447: E/AndroidRuntime(2469): at com.LittleRoach.games.spritertest.GameScreen.(GameScreen.java:61)
09-16 13:51:36.447: E/AndroidRuntime(2469): at com.LittleRoach.games.spritertest.MainGame.create(MainGame.java:18)
09-16 13:51:36.447: E/AndroidRuntime(2469): at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:322)
09-16 13:51:36.447: E/AndroidRuntime(2469): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1455)
09-16 13:51:36.447: E/AndroidRuntime(2469): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)

When I change to getAbsoluteFile() a get different :

09-16 13:59:33.455: E/AndroidRuntime(4598): FATAL EXCEPTION: GLThread 26571
09-16 13:59:33.455: E/AndroidRuntime(4598): java.lang.NullPointerException
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.brashmonkey.spriter.Spriter.loadResources(Spriter.java:80)
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.brashmonkey.spriter.Spriter.(Spriter.java:69)
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.brashmonkey.spriter.Spriter.getSpriter(Spriter.java:47)
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.LittleRoach.games.spritertest.GameScreen.(GameScreen.java:46)
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.LittleRoach.games.spritertest.MainGame.create(MainGame.java:18)
09-16 13:59:33.455: E/AndroidRuntime(4598): at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:322)
09-16 13:59:33.455: E/AndroidRuntime(4598): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1455)
09-16 13:59:33.455: E/AndroidRuntime(4598): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)


FileHandleSCMLReader.getSpriter(Gdx.files.internal("monster/basic.scml"), loader);

doesnt work for me, cant find FileHandleSCMLReader class.

I dont know, if i did som mistake or something.

Thank you for your answers, and i hope we can solve this.

Share this post

Link to post
Share on other sites

Sorry i found that class, in demo, i dont look there before ...

But it also throw nullpointerexpection..

09-16 14:21:37.517: E/AndroidRuntime(8677): FATAL EXCEPTION: GLThread 27096
09-16 14:21:37.517: E/AndroidRuntime(8677): java.lang.NullPointerException
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.brashmonkey.spriter.objects.SpriterObject.setRef(SpriterObject.java:50)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.brashmonkey.spriter.player.SpriterAbstractPlayer.generateData(SpriterAbstractPlayer.java:107)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java:80)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java:103)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.LittleRoach.games.spritertest.GameScreen.(GameScreen.java:62)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.LittleRoach.games.spritertest.MainGame.create(MainGame.java:18)
09-16 14:21:37.517: E/AndroidRuntime(8677): at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:322)
09-16 14:21:37.517: E/AndroidRuntime(8677): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1455)
09-16 14:21:37.517: E/AndroidRuntime(8677): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)

But it work good for every case in desktop.

Share this post

Link to post
Share on other sites

Hmmm... keep the "internal" version of accessing the files and keep loading with the FileHandleSCMLReader and change the SpriterLoader.load method like this:

//Gdx.app.postRunnable(new Runnable(){ //Post the creation of a OpenGL Texture to the LibGDX rendering thread.
//This is necessary if you are loading the scml file asynchrouously with more than one thread.
//public void run() {
files.put(ref, createSprite(new Texture(pix)));

Just comment the Runnable stuff out and keep files.put and pix.dispose.

I hope this helps, cause I do not have any clue why it crashes on android :D

Oh and change the finishedLoading method:

//Gdx.app.postRunnable(new Runnable(){//Has to be called in the rendering thread since OpenGL textures have to be created
//public void run() {


if you are using the texture atlas generation.

Share this post

Link to post
Share on other sites

hi trixtor im having a problem with this line in SpriterLoader.java with the current libgdx nightlies, it seems can't create a texture that is not a power of 2



files.put(ref, createSprite(new Texture(pix)));



here's the stack trace,

Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: Texture width and height must be powers of two: 137x152

at com.badlogic.gdx.graphics.GLTexture.uploadImageData(GLTexture.java:241)

at com.badlogic.gdx.graphics.Texture.load(Texture.java:145)

at com.badlogic.gdx.graphics.Texture.(Texture.java:133)

at com.badlogic.gdx.graphics.Texture.(Texture.java:116)

at com.pogs.runpogsrun.util.SpriterLoader$1.run(SpriterLoader.java:70)

at com.badlogic.gdx.backends.lwjgl.LwjglApplication.executeRunnables(LwjglApplication.java:238)

at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:193)

at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)

Share this post

Link to post
Share on other sites

sorry for the next post. i found out the source of the error. i must set the LwjglApplicationConfiguration.useGL20 when using trixtors SpriterLoader.java, the 'useGL20' is set to false in default

when creating a project on Aurelien Ribon 's GDX-SETUP-UI.

LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "run-pogs-run";
cfg.useGL20 = true; // enable 'useGL20' to make textures that not a power of 2
cfg.width = 480;
cfg.height = 320;

new LwjglApplication(new RunPogsRunGame(), cfg);

Share this post

Link to post
Share on other sites

hello trixtor, i finish my test sample using your awesome Library for Spriter/java , it works well on my android device and Desktop as well. and now i've tried it on iOS using RoboVM for libGDX which gives me some null pointer exception error. here's the stackTrace.

Exception in thread "main" java.lang.NullPointerException

at com.brashmonkey.spriter.objects.SpriterObject.setRef(SpriterObject.java)

at com.brashmonkey.spriter.player.SpriterAbstractPlayer.generateData(SpriterAbstractPlayer.java)

at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java)

at com.brashmonkey.spriter.player.SpriterPlayer.(SpriterPlayer.java)

at com.pogs.runpogsrun.RunPogsRunGame.create(RunPogsRunGame.java)

at com.badlogic.gdx.backends.iosrobovm.IOSGraphics.draw(IOSGraphics.java)

at com.badlogic.gdx.backends.iosrobovm.IOSGraphics$1.draw(IOSGraphics.java)

at org.robovm.cocoatouch.uikit.UIView$Callbacks.draw(UIView.java)

at org.robovm.cocoatouch.uikit.UIApplication.UIApplicationMain(Native Method)

at org.robovm.cocoatouch.uikit.UIApplication.main(UIApplication.java)

at com.pogs.runpogsrun.RobovmLauncher.main(RobovmLauncher.java)

Share this post

Link to post
Share on other sites

Hi arnelpogs,

I'm very sorry for the problems which are occuring on iOS, but I can not test my code on such a device since I have no apple products.

Thank you for the message. I do not have any clue how RoboVM compiles the Java code and I saw that there are several limitations if you are using RoboVM to get Java code working on iOS. Anyway, could you please tell me what your approaches were to fix the issue? Can you post some code?

Seems like there is something wrong when loading the Sprites and posting Runnables to the LibGDX rendering thread. Try to comment the postRunnable thingy out and load everything on the rendering thread, like I described here. That is the only thing I can think of, when looking on the stack trace. Are you already using FileHandleSCMLReader?

Maybe I should mention one thing:

The loader class for the LibGDX example is capable for loading the sprites asynchronously to the LibGDX main thread and I only tested this on desktop/laptop. So if you do not need to load your spriter resources in another thread, please remove the


stuff in the loader. Especially if you want to use the library on mobile devices with just one thread/porcessor or in the browser.

If you initialize a SpriterPlayer object you have to make sure that every reference (i.e sprite) has been loaded, otherwise you will get such a NullpointerException because the generateData method relies on the fact that every reference is already mapped to a specific texture object. Perhaps I should add something like a LoaderListener which gets notified if the loader has loaded all necessary sprites.

I the meantime you could just iterate through the files map and check if the mapped object is null or not and if no null value occured create the player. Or just wait some time/steps before creating a player (e.g. 60 steps or 1 second).

Sorry for no update for the last 2 months. I am currently working on my bachelor thesis about deferred rendering and have not that much time to update the library. But I am definitely going to implement more stuff, especially the free-form stuff which has been added in the B6 version and of course the character mapping and the qudratic, cubic and bezier tweening. Don't worry about that. My private projects rely on such features. ;)

- Trixt0r

Share this post

Link to post
Share on other sites

hello trixtor, just having some experiment and i already know the problem regarding on loading spriter on iOS. and i finally make it work now.

in your SpriterLoader.java the abstract 'load' method parameter 'path' seems having a value different in android and desktop.

when running in desktop and android the value of the 'path' is the image internal path



dir/body.png ...

... etc)

while when running into iOS the value of the 'path' became the image absolute path.


/Users/arnelespiritu/Library/Application Support/iPhone Simulator/7.0/Applications/77C753E6-2712-4650-94D3-6BB805364B12/RunPogsRunGame.app/scml//head.png

/Users/arnelespiritu/Library/Application Support/iPhone Simulator/7.0/Applications/77C753E6-2712-4650-94D3-6BB805364B12/RunPogsRunGame.app/scml//face.png

so i modify your SpriterLoader.java load method a bit.

public void load(final Reference ref, String path) {
FileHandle f = null;
switch(Gdx.app.getType()) {
case Android:
case Desktop:
f = Gdx.files.internal(path);
case iOS:
f = Gdx.files.absolute(path);
if(f==null) return;//other platform. yet not tested

if(!f.exists()) {
System.out.println("image not exist");
if(packer == null && this.pack)
packer = new PixmapPacker(2048, 2048, Pixmap.Format.RGBA8888, 2, true);
final Pixmap pix = new Pixmap(f);

if(packer != null)
packer.pack(ref.fileName, pix);

//files.put(ref,null);//Put first the reference into the map, in the next frame, the null value will be replaced with the actual texture.

//Gdx.app.postRunnable(new Runnable(){ //Post the creation of a OpenGL Texture to the LibGDX rendering thread.
//This is necessary if you are loading the scml file asynchrouously with more than one thread.
// @Override
// public void run() {
files.put(ref, createSprite(new Texture(pix)));
// }

i hav'nt test on webGL yet also on applet. anyway thanks trixtor this api is so cool.keep it up, im looking forward on your work thanks.

Share this post

Link to post
Share on other sites

Thanks for finding this out, arnelpogs!

I pushed some changes in the libGDX loader.

The loader now should not have any problems with different OpenGL ES versions. So you are also able to use version 1.0 if you like. And of course I added the iOS thingy to it. In addition, instead of being silent, the loader throws a gdx runtime exception if the file is not found to see what is actually going on.

Edit: I also copied the examples for LWJGL and Slick2D from Discobeard.

- Trixt0r

Share this post

Link to post
Share on other sites

Hi Trixt0r!

loader.findReferencesByFolderName("foldername") first returns the references from the folder, then a null and after that all other references (not in the folder that I choose). I don't know if it's a bug or a feature :)

Thanks again for your work!

Share this post

Link to post
Share on other sites

Thanks for the bug report, HipGnose!

This is of course a bug. Seems like I was fully retarded when writing this method.

It will be fixed with the next commit.

Discobeard, I have to thank you! Without your basecode I would not have started working on a Spriter API.

It would be cool, if you could update the LWJGL and Slick2D examples with every major update, since I am very busy with the LibGDX stuff.

Threaded resource loading support would be cool.

- Trixt0r

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...