Jump to content
Spriter Forums

Generic Java Importer


Discobeard

Recommended Posts

  • 2 weeks later...

Hey there! I was looking at the spriter runtime and it seems all interpolations happen using the playerTweener. So far so good. But is there an easy way to create complex animations? Like the player is standing still, then his legs start moving and then the hands start moving too while he is still walking. Do I have to create all possible hand/legs combinations as separate animations or something like that?

Link to comment
Share on other sites

If I understand you correctly, you want to apply an animation on only some parts of a skeleton, while the rest keeps the current animation? Maybe this example can help you.

It is possible, but you have to keep the structure of bones and objects always the same and the names of the body parts have also to be the same.

- Trixt0r

Link to comment
Share on other sites

What I didn't understand is how would I add a third animation, for instance a 'stand' animation. This animation would interpolate with the 'walk' animation in your example and it would not affect the 'shoot' animation. What came into mind was nesting playerTweeners but it didn't work out. Everything would be simpler I think if there was some way so that each animation only affected the bones specified in the editor without the need for a baseBoneName.

Link to comment
Share on other sites

  • 1 month later...

Hey

I started using Trixt0rs Java Library to control my Spriter animations. I'm trying to control the animation speed by myself. For that I call the Players setTime(myDelta) method with my custom elapsed time. I do that because the animation has to be perfectly in sync with another part of my game. Calling setTime(myDelta) and then update() works fine when I use Player, but when I switch to PlayerTweener it is no more possible to control time manually. Do you have an advice for handling that?

At the moment I set the weight for the interpolation/transition from one animation to the other with the Java Universal Tweening Engine. Is it possible to do that automatically with Trixt0rs Library?

Would be nice to get some help here.

EDIT:

Sorry for bothering you about the setTime() problem I had with the PlayerTweener. I made a mistake by using a wrong value for setTime(). It works perfectly when you set the correct time values to both players in PlayerTweener.

Link to comment
Share on other sites

At the moment I set the weight for the interpolation/transition from one animation to the other with the Java Universal Tweening Engine. Is it possible to do that automatically with Trixt0rs Library?

You could extend the PlayerTweener class, override the setPlayers method and add a PlayerListener to one of the Player objects and also add a default PlayerListener to your extended PlayerTweener. Now the listener for one of the Player objects listens for an animation change and reacts properly to it. The default listener for the extended PlayerTweener overrides the postProcess method, which is just incrementing the weight.

I guess there is need for some more examples and maybe some utility classes...

-Trixt0r

Link to comment
Share on other sites

Thanks a lot Trixt0r, that is a great advice. I think that solves also my problem of removing a listener from a Player right at the moment when the method animationFinished() of the listener is called. I always got an error when update() is called right after I removed the listener. Is that because of the Player still iterating through the Array while I remove the listener from it? But when I handle the events from the listener inside the extended PlayerTweener, I probably won't have that problem.

A little bit more examples or more explanations in the wiki would be good. Maybe also regarding the following questions:

Animation speed/time step

Am I supposed to control the speed of the Player by myself to achieve a constant speed on all devices? I haven't found something related to that in your code, only the dependence of the speed value. When I understand it correctly, on every update you proceed 15 ms in time. Why 15 ms? Wouldn't it be easier to control it by a float from 0 to 1?

Looping animations

I don't really understand from where the looping value in the Animation class comes from. I thought when I disable the "Repeat Playback" button on top of the timeline in Spriter, the animation is played only once, but it is still looping. Do I have to handle that with the animationFinished() method from the listener?

Changing bone parent

I'm not sure if it is a bug, but there is a strange positioning problem on bones that change parent. It's more or less like the situation in this Spriter video

.

When a bone changes the parent bone (or is created) somewhere in the middle of the timeline, the attached image is positioned at (0, 0) and is not moving/rotating. Strange is that it works when you play it directly in player1 or when you set the animation on the same player. But when you play the animation in a second player and set the weight immediately to that player, it doesn't work correctly.

EDIT: I tested it again in a different setup. It happens always when the bone count isn't the same in different animations. You already wrote that in the wiki on git.


//create()
player = new PlayerTweener(reader.getData().getEntity("boy"));
player.getFirstPlayer().setAnimation("walk");
player.setWeight(0);


//touchUp()

//works
player.getFirstPlayer().setAnimation("animationChangingBone");

//doesn't work
player.getSecondPlayer().setAnimation("animationChangingBone");
player.setWeight(1);

Link to comment
Share on other sites

Animation speed/time step
You can actually set the speed value ony your own. A value of 15 does not mean 15 ms progress in time. It simply means 15 frames further in your animation. This means that your animation is at frame 900 after one second if your fps count is 60. To achieve the same result at 30 fps you would increase the speed to 30, at 15 fps to 60, and so on.

So the calculation of the speed in your game would be:


var framesYouWantToPlayInOneSecond = 900; //or 1000 or 5000, depends on your animations
var fps = 60; //or 30, 90, 120, etc.
player.speed = framesYouWantToPlayInOneSecond/fps;

I was already thinking about setting the animation speed to a float rather than an integer. Could be benefitial for very slow playback of an animation. Would also work with the case of having higher fps than the animation frames you want to play. At the current state, this would not work. But if your spriter animation has less frames than 30, then you have to overthink the usage of Spriter ;).

Looping animations
The flag is simply indicating whether to interpolate the last frame with the frist frame if the last frame's time is smaller than the animation length.
Do I have to handle that with the animationFinished() method from the listener?
Yes.
Changing bone parent

I will have to look into this a bit further. I guess a workaround would be to immediately update the player tweener object after setting the animation, i.e. calling player.update() before player.setWeight(1)

-Trixt0r

Link to comment
Share on other sites

I extended the PlayerTweener and did some implementations that cover my needs. I added the speed calculation in a custom update(float delta) method that sets the speed depending on delta time. I hope that is the correct approach to have the same animation speed with a dynamic frame rate.


public void update(float delta){
player.speed = Math.round(900 * delta);
...
}

I still have some problems handling multiple animation tweens. It works fine when you simply tween from "anim1" to "anim2" and when it's completed to "anim3". But when you are at a weight of 0.5f in between "anim1" and "anim2" and you want to interpolate from that current state to "anim3", it don't work properly. I don't think is possible to get such a interpolation properly with a system managing two players and setting the weight in between. Or am I wrong? I know, normally in a game a transition takes about 20ms, then it doesn't matter. But in my game the transitions are a little bit slower, so there will be some problems if I have to wait the animations to be completed to switch animation.

Thanks again for your help and the great inputs.

Link to comment
Share on other sites

  • 2 weeks later...

You wrote a few posts ago that the library now works also with GWT.

Forgot to mention: The library works also with GWT now.

- Trixt0r

I tested that and it works when compiling for dev:


>gradlew html:superDev

But when I compile for distribution, I get these error:


>gradlew html:dist

Compiling module com.mygdx.game.GdxDefinition
Validating units:
[ERROR] Errors in 'file:/C:/workspace/CharacterAnimation/core/libsrc/com/brashmonkey/spriter/Spriter.java'
[ERROR] Line 75: The method getDeclaredConstructor(Class<?>[]) is undefined for the type Class
[ERROR] Line 96: No source code is available for type java.io.FileInputStream; did you forget to inherit a required module?
[ERROR] Line 113: The method getDeclaredConstructor(Class<?>[]) is undefined for the type Class
[ERROR] Line 145: The method getDeclaredConstructor(Class) is undefined for the type Class
[ERROR] Aborting compile due to errors in some input files
:html:compileGwt FAILED

Any ideas what is wrong?

Link to comment
Share on other sites

- Character map with "hidden" object => the objects are still drawed

- Project resize => animations KO

Thanks for reporting these problems. I will have a look into it next week.

@jaunusa

You are using the Spriter class, which uses reflection and that is not supported in GWT yet. Don't know why this works for you in superDev mode?

A workaround for your problem would be to replace all generic parts in the class with the LibGDX parts, i.e. every method which contains "getDeclaredConstructor" has to me re-implemented. Should be fairly easy...

- Trixt0r

Link to comment
Share on other sites

I've done some patch to fix these bugs

Character map with "hidden" object => the objects are still drawed

inside SCMLReader


protected void loadCharacterMaps(ArrayList maps, Entity entity) {
for (int i = 0; i < maps.size(); i++) {
Element map = maps.get(i);
Entity.CharacterMap charMap = new Entity.CharacterMap(map.getInt("id"), map.getAttribute("name", "charMap"
+ i));
entity.addCharacterMap(charMap);
ArrayList mappings = map.getChildrenByName("map");
for (Element mapping : mappings) {
int folder = mapping.getInt("folder");
int file = mapping.getInt("file");
if (mapping.get("target_folder", null) == null) {
charMap.put(new FileReference(folder, file), null);
} else {
charMap.put(new FileReference(folder, file), new FileReference(mapping.getInt("target_folder"),
mapping.getInt("target_file")));
}
}
}
}

and the Drawer


public void draw(Iterator it, CharacterMap[] maps) {
while (it.hasNext()) {
Timeline.Key.Object object = it.next();
if (object.ref.hasFile()) {
// apply map
if (maps != null) {
for (CharacterMap map : maps) {
// key exists
if (map != null && map.containsKey(object.ref)) {
// draw if not "hidden"
if (map.get(object.ref) != null) {
object.ref.set(map.get(object.ref));
this.draw(object);
}
break;
} else {
this.draw(object);
}
}
} else {
this.draw(object);
}

}
}
}

Project resize => animations KO

It's a bug from Spriter's resize feature, images are resized but not the width and height attributes of the scml file

initial project's scml file



the scml file (and images) resized with ratio = 0.5



instead of



The importer is OK with correct width and height

Link to comment
Share on other sites

Thank you for your answer, haven't realized that GWT doesn't support reflection. I'm relatively new to Java/LibGDX, so I have no concrete idea how to substitute the getDeclaredConstructor implementation with the one from LibGDX. LibGDX has some Reflection system that supports GWT, but it works only with constructors without parameters. Maybe that is what you mentioned, hopefully that functionality is integrated in future releases.

At the moment I don't need the static Spriter managment, so I just deleted all static methods containing getDeclaredConstructor and InputStream in the Spriter class. That works fine for me for now.

Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...

Back after a long break from coding~

 

sightly more updates about the memory leak issue in andriod devices:

I tried few XML parsers and Json Parsers to just READ SCML/SCON spriter projects and the memory issue still there , while there is still no solution in the near future for me to remove the memory leak completely here is few TIPs that might help u reduce the amount of memory being leaked from me.

 

------Solutions------

1) Limit the number of entities to 1 only

2) limit the number of animations to 5 maximum, each time you define a new animation in .scml file a new set of keys + ids + bone refrences even if you have them in all of your animations in the entity, thats like 500~1k lines of codes each time you create new animation 

2.a) I tried mixing 3 animations of mine into 1 animation only and used the following codes to swap between them :

	public static void LoopAnimation(Entites_General attacker, int framerangestart, int framerangeend) {		{			if (attacker.player.getTime() >= framerangeend) {				attacker.player.setTime(framerangestart);			}		}	}	public static void FreezeTime(Entites_General attacker, int framerangeend) {		{			if (attacker.player.getTime() >= framerangeend) {				attacker.player.setTime(framerangeend);			}		}	}

results : i saved around3k lines of code and reduced the file size from 1219 to 990kb + loading time for parsing .scml file obviously went faster

 

3)each time u finish saving the scml file edit with note pad (i use notepadd++) to check how many lines of codes you have , 5k lines of codes in each scml file should be fine

 

------Possible diffrent solution------

 

after reducing my project size from 18k lines of code into 15k line of code i'm thinking of separating the project files into 3 scml files,5k lines of code each (1 for IDLE animations , 1 for attacks , 1 for extra animations) , create 3 players in java and 1 (main player) that will swap between the animations , wonder how it will goes

 

------Memory Leak Tests------

the following way of readings  generated the following memory leaks :

Method A : Parsing A "String"

//			FileHandle FH = new FileHandle(Gdx.files.internal("Offical/Spriter/" + Folder + "/CurrentProj.scml").readString().trim());//			String s = FH.toString().trim();//			data = new SCMLReader(s).getData();
 

String s = FH.toString().trim(); line generated 40MB memory Leak in total, while data had NO memory leaks, this method we r parsing A string 

 

Method B : Parsing a stream:

		 data = new SCMLReader(Gdx.files.internal("Offical/Spriter/" + Folder			 + "/CurrentProj.scml").read()).getData();			loader = new LibGdxLoader(data);			loader.load(Gdx.files.internal("Offical/Spriter/" + Folder + "/CurrentProj.scml").file());

public Element parse(Reader reader)  from SCMLReader ,in the line of code : char[] newData = new char[data.length * 2]; generated same result,40MB memory Leak in total, this method we r parsing a stream

 

both tests were done in a project that has only these lines of codes + project files , same results , same amount of memory leak but in diffrent ways

 

//////////////////

I believe the solution lies somewhere in method A , we need to get .scml file somehow into a string without causing a memory leak then parse the string using the SCML reader because it did not generate a memory leak there in method A

 

last but not least : spriter uses tons of lines of codes in their xml files

///// 

Link to comment
Share on other sites

  • 2 weeks later...

I played around with getting soundlines into this for my JavaFX project. It works pretty well but I imagine someone could come up with a much more efficient and neat implementation. I think I should be able to able to set the volume of a sound relative to the distance of it's source from the player as well as shift balance from left to right.

Link to comment
Share on other sites

Original Post :

 

----- FINALLY after 6 months i found the solution XD!!!~

 
Ok here is the thing , XML reader class uses DOM parsing method which is not very ideal to parse huge xml files for android devices, SAX parsing on the other hand DOES NOT load xml file into memory, it is also relatively very fast , using the following code i was able to read a file with 4.8MB of data with over 100 animations with over 100 thousands lines WITHOUT any single Memory leak :))))),making it possible to create tons of animations without worrying about how big the animation file is. 
 
the android app starts with 5MB in ram and end with 6MB in RAMonly after finish reading the file~
 
finally the search is over , the only thing left is to alter the generic java importer to use SAX instead/Alongside of DOM, i don't know if you still updating the generic java importer library , but i really hope to see this library being updated again some day soon :)
 
--
 
New Post :
 
Thing is , since we are not loading the xml fileto memory , we need to creat the animations folders etc during run time using the following methods of SAX parser instead of waiting for the parser to finish parsing the original implementation of the generic java importer
 
private void SaxCons() {		SAXParserFactory spf = SAXParserFactory.newInstance();//						FileHandle FH = Gdx.files.internal("Edge/CurrentProj.scml");			SAXParser parser;			try {				parser = spf.newSAXParser();				try {					parser.parse(FH.read(), new DefaultHandler());				} catch (IOException e) {					// TODO Auto-generated catch block					e.printStackTrace();				}			} catch (ParserConfigurationException e) {				// TODO Auto-generated catch block				e.printStackTrace();			} catch (SAXException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}						}

 we ovveride the following Method in default handler to read each element : 

		try {					parser.parse(FH.read(), new org.xml.sax.helpers.DefaultHandler(){												@Override						public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {							// TODO Auto-generated method stub							super.startElement(uri, localName, qName, attributes);														String name, type;							float id , width, height,pivot_x,pivot_y,w,h;							if(qName.equals("file"))							{								 id = Float.valueOf(attributes.getValue("id").toString());								 name = (attributes.getValue("name").toString());								 width = Float.valueOf(attributes.getValue("width"));								 height = Float.valueOf(attributes.getValue("height"));								 pivot_x = Float.valueOf(attributes.getValue("pivot_x"));								 pivot_y = Float.valueOf(attributes.getValue("pivot_y"));								 								 								 System.out.println(id + name+ width+ height+pivot_x+ pivot_y);								 //store these values into a file							}														if(qName.equals("entity"))							{								if(qName.equals("obj_info")){									 name = (attributes.getValue("name"));									 type = (attributes.getValue("type"));								 w = Float.valueOf(attributes.getValue("w"));								 h = Float.valueOf(attributes.getValue("h"));								 //store these values somewhere							}							}																				}												@Override						public void characters(char[] ch, int start, int length) throws SAXException {							// TODO Auto-generated method stub							super.characters(ch, start, length);													}											});				} 

well you get the idea~ 

again : we r reading the file without loading it into memory , therefore each time we come accross a node we create  variables to store its elements 

Link to comment
Share on other sites

  • 10 months later...

hi this is probably going to be a very noobish question but i keep seeing this referred to as a library and to me it seems more like something where i have to just add the files to my project and not a library if it is saposed to be added as a library then can someone give an example and the editor i am using is netbeans 8.1 newest just reinstalled it yesterday

and if its not a library i may just make it a library with some auto gen classes for my own use as i saw that there may be a few classes that would need to be auto genned

 

it would be very apreciated if someone could help also netbeans is the editor i know how to use better and there are somethings i have on it that i use often so i don't want to change editors because it looks like the library if it is one may be eclipse or something close

 

 

[EDIT] my freind helped me with this now it is a library for me

Link to comment
Share on other sites

@sentinel It is a library which you can use from Maven central if you use maven, gradle or any other build tool which supports Maven central repository:

http://search.maven.org/#artifactdetails%7Ccom.github.trixt0r%7CSpriter%7C1.1%7Cjar

It haven't been updated for a while though; I have recently submitted a couple of small bug fixes which will become available with the next release.

Link to comment
Share on other sites

@denisk20my freind made it a libary for me from the git and i am working on a added little part basicly what its is saposed to do is add some need files to your project

(example) when you do this one call that only ever has to be run when you are first staring a project where you want to automaticly add say the loader and drawer files i'm working on that

Link to comment
Share on other sites

  • 11 months later...

Hey Guys!

After a little break, I am currently cleaning up the whole project, so dependency management with gradle or maven is easier.

I am splitting the project up into multiple git projects, so the actual generic imlementation is free from any LibGDX, Slick2D or LWJGL dependencies.

The LibGDX part is already migrated, which means all GDX guys can use a clean library which is only requiring the spriter library and libgdx. The project lives here: https://github.com/Trixt0r/gdx-spriter

All previous tests, which are based on LibGDX, live exist under https://github.com/Trixt0r/spriter-examples

There you have an example for your LibGDX projects.

As soon as I migrated the other implementations into seperate git repos, I will merge gradle-migration into the master branch.

In a next step I will try to add variable and audio support.

Btw, the generic implementation and the gdx implementation get built into the "mvn" branch, so make sure you add  https://raw.github.com/Trixt0r/***/mvn/ to your repository configuration.

- Trixt0r

 

Link to comment
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.

Guest
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...