Libgdx spine2d skeleton animation - java

This is my code:
game init:
playerAtlas = new TextureAtlas(Gdx.files.internal("spineboy.atlas"));
json = new SkeletonJson(playerAtlas);
playerSkeletonData = json.readSkeletonData(Gdx.files.internal("spineboy.json"));
playerAnimationData = new AnimationStateData(playerSkeletonData);
batch = new SpriteBatch();
skeletonRenderer = new SkeletonRenderer();
skeleton = new Skeleton(playerSkeletonData);
animationState = new AnimationState(playerAnimationData);
animationState.setAnimation(0, "walk", true); // trackIndex, name, loop
render:
animationState.update(Gdx.graphics.getDeltaTime());
animationState.apply(skeleton);
batch.begin();
skeletonRenderer.draw(batch, skeleton);
batch.end();
Gdx.app.log("rendering", "x" +skeleton.getX());
Gdx.app.log("rendering", "y"+skeleton.getY());
skeleton.setPosition(300, 300);
And for some reason, I can't get my animation to show up.
I got this code from here and copied it:
https://gamedev.stackexchange.com/questions/98890/implementing-spine-animations-in-libgdx
I cant figure out why the animation isn't rendering!!
Can anyone please help?

Try this Test Class :
public class SimpleTest1 extends ApplicationAdapter {
OrthographicCamera camera;
SpriteBatch batch;
SkeletonRenderer renderer;
SkeletonRendererDebug debugRenderer;
TextureAtlas atlas;
Skeleton skeleton;
AnimationState state;
public void create () {
camera = new OrthographicCamera();
batch = new SpriteBatch();
renderer = new SkeletonRenderer();
renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines.
debugRenderer = new SkeletonRendererDebug();
debugRenderer.setBoundingBoxes(false);
debugRenderer.setRegionAttachments(false);
atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy.atlas"));
SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless.
json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine.
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json"));
skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc).
skeleton.setPosition(250, 20);
AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations.
stateData.setMix("run", "jump", 0.2f);
stateData.setMix("jump", "run", 0.2f);
state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc).
state.setTimeScale(0.5f); // Slow all animations down to 50% speed.
// Queue animations on track 0.
state.setAnimation(0, "run", true);
state.addAnimation(0, "jump", false, 2); // Jump after 2 seconds.
state.addAnimation(0, "run", true, 0); // Run after the jump.
}
public void render () {
state.update(Gdx.graphics.getDeltaTime()); // Update the animation time.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
camera.update();
batch.getProjectionMatrix().set(camera.combined);
debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined);
batch.begin();
renderer.draw(batch, skeleton); // Draw the skeleton images.
batch.end();
debugRenderer.draw(skeleton); // Draw debug lines.
}
public void resize (int width, int height) {
camera.setToOrtho(false); // Update camera with new size.
}
public void dispose () {
atlas.dispose();
}
}

I can't add comments, but there is a some additional info for Abhishek Aryan's post.
Now (oct, 22)you should use:
PolygonSpriteBatch batch;
..
batch = new PolygonSpriteBatch ();
to make his code work.

Related

Unable to draw a font and a stage at the same time on LibGDX

I'm trying to draw a stage and a string with a specific font, but when I draw the stage, the string disappears, but the images do not. I suppose it's a simple thing, but I have no idea. I've already tried to change the order to render, but that doesn't seem to be the problem. Any help would be aprecciated.
#Override
public void create() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
batch = new SpriteBatch();
textatlas = new TextureAtlas("Agorafunfa.txt");
TextureAtlas.AtlasRegion a = textatlas.findRegion("spider");
spider = new Sprite(a);
img = new Texture("Captura.PNG");
yesa = new BitmapFont(Gdx.files.internal("yesa.fnt"));
font = "Escape Planet";
img3 = new Texture("saturno.png");
funciona = new BitmapFont(Gdx.files.internal("yesa.fnt"));
starte = "Começar";
opcoes = "Opções";
Skin skin = new Skin();
skin.addRegions(ta);
final TextButton.TextButtonStyle tbs = new TextButton.TextButtonStyle();
tbs.font = yesa;
tbs.checked = skin.getDrawable("comecaversao2");
tbs.up = skin.getDrawable("comeca");
b = new TextButton("Começar",tbs);
b.setHeight(250);
b.setWidth(300);
b.setPosition(-10, 50);
b.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
stage.addActor(b);
Gdx.input.setInputProcessor(stage);
}
public void render() {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img,0,0);
batch.draw(img3, 200,170, 250, 170);
yesa.setColor(Color.WHITE);
yesa.draw(batch,font,430,300);
stage.draw();//if I comment this line, the string appears
batch.end();
}
You're on right track, stage.draw() is causing the problem. You're calling it without closing the spritebatch before. If you look into stage's source code you'll see it has its own spritebatch. Call batch.end() before drawing the stage.
Rendering a batch inside another opened batch will result in all kind of weird behaviour that makes you think the fault lies in everything but the batch.
As these type of problems pop up frequently nowadays I checked out the stage docs, there is clear information that it uses its own batch, you can even set your own with the constructor stage(Viewport viewport, Batch batch). If you use that constructor you don't need to use the solution above. However the docs doesn't mention batches needs to be closed, not even in the batch docs. This is something that probably should be added so we can avoid the same issues popping up.
Possible duplicate of this and this.

LibGDX Tiled (TMX) Maps + Scene2D, bugs when rendering both

So I've recently started tinkering with LibGDX (desktop only, at the moment) in Java. I'm mildly experienced with other type of OGL libraries in other languages (namely SFML in C++) and quite experienced with the Java language itself, so I tackled LibGDX pretty confidently; and while the results were mostly positive, there's a bug that I just can't figure out.
What I want to achieve is simple: draw a map (Tiled .tmx), draw a Sprite (soon-to-be "player") inbetween layers 1 and 2, and render a couple of GUI widgets on top of all that, using a scene2D stage. I've managed to achieve this partially.
Here's my Game class, it's pretty messy from so much switching things around just to try, but it's pretty clear what it attempts to do:
public class Game extends ApplicationAdapter
{
private SpriteBatch batch;
private Texture img;
private Sprite playerSprite;
private TiledMap tiledMap;
private OrthographicCamera camera;
private OrthogonalTiledMapRenderer tiledMapRenderer;
private Stage stage;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("trchar000.png");
playerSprite = new Sprite(img, 0, 0, 32, 48);
playerSprite.setPosition(32, 192);
InputHandler.init();
Gdx.input.setInputProcessor(new InputHandler());
stage = new TestStage(playerSprite);
// inputs
InputMultiplexer im = new InputMultiplexer(stage, new InputHandler());
Gdx.input.setInputProcessor(im);
// tiles
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.update();
tiledMap = new TmxMapLoader().load("map2.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
tiledMapRenderer.setView(camera);
int[] groundLayers = {0};
int[] topLayers = {1};
// render layer1 -> player -> layer 2
// the .tmx map doesn't have any other layers (just those 2)
tiledMapRenderer.render(groundLayers);
// removing these 3 lines solves the issue, but doesn't render the player
// I've also tried using my regular SpriteBatch instance; same results
// Also, I tried creating a class that extends OrthogonalTiledMapRenderer and overriding the render() method, so that it would draw the player inbetween layers, but again, same results.
tiledMapRenderer.getBatch().begin();
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
tiledMapRenderer.getBatch().end();
tiledMapRenderer.render(topLayers);
batch.begin();
// just to try, I'm rendering the stage here (not calling it's draw() method). Removing this for loop solves the issue, but doesn't render the GUI
for(Actor a : stage.getActors())
a.draw(batch, 1);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
img.dispose();
tiledMapRenderer.dispose();
stage.dispose();
}
}
Also, here's my TestStage class:
public class TestStage extends Stage {
private Skin skin;
private BitmapFont newDefaultFont;
public TestStage(Sprite player)
{
super(new ScreenViewport());
// skin
FreeTypeFontGenerator freeTypeFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("segoeui.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = 14;
newDefaultFont = freeTypeFontGenerator.generateFont(parameter);
skin = new Skin();
skin.add("default-font", newDefaultFont, BitmapFont.class);
FileHandle fileHandle = Gdx.files.internal("uiskin.json");
FileHandle atlasFile = fileHandle.sibling("uiskin.atlas");
if (atlasFile.exists()) {
skin.addRegions(new TextureAtlas(atlasFile));
}
skin.load(fileHandle);
final TextButton button = new TextButton("This is a Button", skin, "default");
button.setPosition(250, 250);
button.setWidth(150);
button.setHeight(40);
final Label lbl = new Label("Test", skin);
this.addActor(lbl);
this.addActor(button);
}
}
Now here's the deal; this is what it looks like if a try to render everything (as shown in my Game class' render() method):
Image 1
The player, GUI, and layer 2 are rendered correctly, but the layer 1 is all bugged out, and I can't figure out why.
Now, here's how it looks like if a don't render the player, removing the line
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
Image 2
Everything renders fine.
Also, here's what it looks like if I decide not to render the stage actors, commenting this loop:
for(Actor a : stage.getActors())
a.draw(batch, 1);
Image 3
Again, everything renders fine.
The only other classes in my project are the default DesktopLauncher class, and an InputProcessor which I'm sure has nothing to do with this.
This is my first question here ever; I just can't figure this out.
Thanks in advance.

Libgdx: How can I load assets after screen has already rendered?

I have implemented the loading screen from this example on my Loading Screen that is a child of Game. This is how my asset init method and Screen class looks like. My init method in assets loads classes that contain my AtlasRegion. I have tested that this method is what makes my screen load a black screen as it loads a lot of resources.
public void init (AssetManager assetManager) {
this.assetManager = assetManager;
// set asset manager error handler
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
assetManager.load(Constants.TEXTURE_ATLAS_UI, TextureAtlas.class);
assetManager.finishLoading();
TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS_OBJECTS);
TextureAtlas atlasUi = assetManager.get(Constants.TEXTURE_ATLAS_UI);
//font = new BitmapFont(Gdx.files.internal("data/font.fnt"), Gdx.files.internal("data/font.png"), false);
clickSound = Gdx.audio.newSound(Gdx.files.internal("data/sounds/click.wav"));
// create game resource objects
fonts = new AssetFonts(assetManager);
skins = new AssetSkins();
background = new AssetBackgroundImage();
cards = new AssetCards(atlas);
cardimages = new AssetImages(atlas);
cardsjson = new AssetList();
suitimages = new AssetSuitImages(atlas);
}
This is my Loading Screen class:
public class LoadingScreen extends AbstractGameScreen implements Disposable {
private Stage stage;
private Image logo;
private Image loadingFrame;
private Image loadingBarHidden;
private Image screenBg;
private Image loadingBg;
private float startX, endX;
private float percent;
private Actor loadingBar;
public LoadingScreen(CardGame game) {
super(game);
}
public InputProcessor getInputProcessor () {
return (null);
}
#Override
public void show() {
// Tell the manager to load assets for the loading screen
game.manager.load("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Wait until they are finished loading
game.manager.finishLoading();
// Initialize the stage where we will place everything
stage = new Stage();
// Get our textureatlas from the manager
TextureAtlas atlas = game.manager.get("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Grab the regions from the atlas and create some images
logo = new Image(atlas.findRegion("libgdx-logo"));
loadingFrame = new Image(atlas.findRegion("loading-frame"));
loadingBarHidden = new Image(atlas.findRegion("loading-bar-hidden"));
screenBg = new Image(atlas.findRegion("screen-bg"));
loadingBg = new Image(atlas.findRegion("loading-frame-bg"));
// Add the loading bar animation
Animation anim = new Animation(0.05f, atlas.findRegions("loading-bar-anim") );
anim.setPlayMode(Animation.PlayMode.LOOP_REVERSED);
loadingBar = new LoadingBar(anim);
// Or if you only need a static bar, you can do
// loadingBar = new Image(atlas.findRegion("loading-bar1"));
// Add all the actors to the stage
stage.addActor(screenBg);
stage.addActor(loadingBar);
stage.addActor(loadingBg);
stage.addActor(loadingBarHidden);
stage.addActor(loadingFrame);
stage.addActor(logo);
// Add everything to be loaded, for instance:
Assets.instance.init(game.manager);
}
#Override
public void resize(int width, int height) {
// Set our screen to always be XXX x 480 in size
//width = 480 * width / height;
//height = 480;
stage.getViewport().update(width, height, false);
// Make the background fill the screen
screenBg.setSize(width, height);
// Place the logo in the middle of the screen and 100 px up
logo.setX((width - logo.getWidth()) / 2);
logo.setY((height - logo.getHeight()) / 2 + 100);
// Place the loading frame in the middle of the screen
loadingFrame.setX((stage.getWidth() - loadingFrame.getWidth()) / 2);
loadingFrame.setY((stage.getHeight() - loadingFrame.getHeight()) / 2);
// Place the loading bar at the same spot as the frame, adjusted a few px
loadingBar.setX(loadingFrame.getX() + 15);
loadingBar.setY(loadingFrame.getY() + 5);
// Place the image that will hide the bar on top of the bar, adjusted a few px
loadingBarHidden.setX(loadingBar.getX() + 35);
loadingBarHidden.setY(loadingBar.getY() - 3);
// The start position and how far to move the hidden loading bar
startX = loadingBarHidden.getX();
endX = 440;
// The rest of the hidden bar
loadingBg.setSize(450, 50);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setY(loadingBarHidden.getY() + 3);
}
#Override
public void render(float delta) {
// Clear the screen
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (game.manager.update()) { // Load some, will return true if done loading
if (Gdx.input.isTouched()) { // If the screen is touched after the game is done loading, go to the main menu screen
game.setScreen(new MainMenuScreen(game));
}
}
// Interpolate the percentage to make it more smooth
percent = Interpolation.linear.apply(percent, game.manager.getProgress(), 0.1f);
// Update positions (and size) to match the percentage
loadingBarHidden.setX(startX + endX * percent);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setWidth(450 - 450 * percent);
loadingBg.invalidate();
// Show the loading screen
stage.act();
stage.draw();
}
#Override
public void pause () {}
#Override
public void resume () {}
#Override
public void hide() {
// Dispose the loading assets as we no longer need them
game.manager.unload("data/images-ui/loading/loading.pack");
}
}
I need to load the screen then load my assets on this Assets.instance.init(new AssetManager()) since it is what is causing a black screen. The problem is my screen loads after loading the assets hence this makes my loading screen to be of no use. How can I load this method after the screen has rendered?
Remove the finishLoading call from your init method. That should do it. finishLoading forces the assets to finish loading immediately which is not what you want here. Calling update on it repeatedly, which you are already doing is the way to load assets asynchronously.
Here's a general structure for how it could be done. Call all the load methods on the asset manager before it ever gets to the render method. Then call update repeatedly until everything is loaded. Then get references to the assets before continuing.
private boolean loadComplete;
public void show(){
//...
loadComplete = false;
}
private void init(AssetManager assetManager){
this.assetManager = assetManager;
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
}
private void onAssetsLoaded(){
loadComplete = true;
myAtlas = assetManager.get("myAtlas.json", TextureAtlas.class);
//and so on
}
public void render(float delta){
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//load one asset at a time per frame until loading is complete
if (assetManager == null || !assetManager.update()){
//maybe draw a load screen image that's not a texture that's being managed
//by the assetManager. You could even play an animation. Otherwise,
//you can leave the screen blank.
return;
}
//will only get here when asset manager is done. The first time, you still
//need to get references to its assets
if (!loadComplete)
onAssetsLoaded();
//the rest of you render method. Everything below here only happens after assets are loaded and asset references have been aquired
}
After trying so many recommended solutions, I finally managed to fix this problem thanks to this blog post
I used a callback which displays an android framelayout with an image as the assets load asynchronously.

Incomprehensible NullPointerException

I have a very basic program, that is supposed to display a label and a text field. I am able to display the text. For the textfield, I can create it without error, but when I add it to the stage and run the program I have this error :
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.scenes.scene2d.ui.TextField.draw(TextField.java:301)
at com.badlogic.gdx.scenes.scene2d.Group.drawChildren(Group.java:111)
at com.badlogic.gdx.scenes.scene2d.Group.draw(Group.java:58)
at com.badlogic.gdx.scenes.scene2d.Stage.draw(Stage.java:128)
at com.pace.converter.MainMenuScreen.render(MainMenuScreen.java:52)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.pace.converter.MyGdxGame.render(MyGdxGame.java:21)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
As I don't know how to put line numbers in the code block of my comments, here are the lines pointed by the error :
MainMenuScreen.java: 52 is
stage.draw();
MyGdxGame.java: 21 is
super.render();
I don't understand why I have this NullPointerException as I created the TextField before adding it to the stage.
And here is my complete code :
Main activity :
public class MyGdxGame extends Game {
SpriteBatch batch;
AssetManager assets;
#Override
public void create () {
batch = new SpriteBatch();
assets = new AssetManager();
this.setScreen(new LoadingScreen(this));
}
#Override
public void render () {
super.render();
}
public void dispose () {
batch.dispose();
}
}
Main menu screen :
public MainMenuScreen(final MyGdxGame gam) {
game = gam;
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
skin = new Skin(Gdx.files.internal("skin.json"));
stage = new Stage();
labelStyle = new LabelStyle(game.assets.get("font1.ttf", BitmapFont.class), Color.WHITE);
labelTest = new Label("Test", labelStyle);
textFieldTest = new TextField("Test", skin);
stage.addActor(labelTest);
stage.addActor(textFieldTest);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.281f, 0.602f, 0.844f, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.setProjectionMatrix(camera.combined);
stage.act();
stage.draw();
}
First off all you need to check some things which could be null.. wrap your code in try-catch blocks
I don't know what is stage but check if it has been initialized or not ?
If stage is not null
then check in your Main menu Screen
skin = new Skin(Gdx.files.internal("skin.json")); // is the skin null ? if the file 'skin.json' couldn't be found then this would be null.. check this
textFieldTest = new TextField("Test", skin); // If skin is null, you're adding it here
as for the super.render(); is it even supposed to be called here ?

libgdx not displaying anything

Hey everyone I am really new to libgdx and Open GL so I am having trouble with this sample project I have to do. Here is my code it should be simply displaying a three buttons from a .batch file any help is greatly appreciated. After going through the debugger the only thing I could see was that the call to get draw able returned object[o] but if it didn't find anything why didn't it error out?
public MainScreen() {
spriteBatch = new SpriteBatch();
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false, spriteBatch);
font = new BitmapFont(Gdx.files.internal("assets/font.fnt"),
Gdx.files.internal("assets/font.png"), false);
buttons = new TextureAtlas("assets/GameButtons.pack");
images = new Skin();
images.addRegions(buttons);
SFXButton = new Button(images.getDrawable("sfxButton"));
SFXButton.setPosition(295, 310);
APIButton = new Button(images.getDrawable("apiButton"));
APIButton.setPosition(405, 310);
GameButton = new Button(images.getDrawable("gameButton"));
GameButton.setPosition(515, 310);
SFXClick = Gdx.audio.newSound(Gdx.files.internal("assets/button_click.wav"));
}
#Override
public void dispose() {
spriteBatch.dispose();
stage.dispose();
}
#Override
public void render(float delta) {
stage.act(delta);
stage.draw();
stage.addActor(SFXButton);
stage.addActor(APIButton);
stage.addActor(GameButton);
spriteBatch.begin();
font.setColor(Color.RED);
font.draw(spriteBatch, "PennyPop", 455 - font.getBounds("PennpyPop").width/2,
460 + font.getBounds("PennyPop").height/2);
if (SFXButton.isPressed())
SFXClick.play();
spriteBatch.end();
}
OUCH! No way you want to add buttons to your stage every render, with 60 FPS and 3 buttons, that would add 180 buttons to your stage per second, and for every second, until you close your app.
public void render(float delta) {
stage.act(delta);
stage.draw();
stage.addActor(SFXButton); //problem here
stage.addActor(APIButton); //and here
stage.addActor(GameButton); //and here
Move the buttons adding to the constructor, see if it will solve the problem.

Categories

Resources