How to finish animation with libgdx - libgdx

I am trying to implement a simple animation with libGDX and I am currently stuck on one thing. Lets say I have a bunch of sprites which take some time to finish. For example, around 30 sprites like this link: https://github.com/libgdx/libgdx/wiki/2D-Animation
However, before the animation completes some key is pressed. For smooth animation I want the 30 frames to be completed before I start the next set of animation, to prevent an abrupt stop.
So my question is how do I achieve it this in libGDX? My current idea is to extend the Animation class, which would keep track of how frames I have and how many have been rendered and then display the rest. Or use the isAnimationFinished(float stateTime) function (though I haven't had luck using that).
The examples I have seen like superjumper have very few animations and don't really change that much.
Also, is there a way to hold the list of sprites from a TextureAtlas.createSprites method and use those with the Animation class? If not, whats the purpose of providing this function?
Thanks

You can use
animation.isAnimationFinished(stateTime);
To see if your animation is finished.
For the sprites : personnaly I use TextureRegion from a TextureAtlas and I store them in an array for my animation

I create a class AnimatedImage that extends Image to automate spriting in Image. My code will be like this:
public class AnimatedImage extends Image{
private Array<Array<Sprite>> spriteCollection;
private TextureRegionDrawable drawableSprite;
private Animation _animation;
private boolean isLooping;
private float stateTime;
private float currentTime;
public AnimatedImage(Array<Array<Sprite>> _sprites, float animTime, boolean _looping){
// set the first sprite as the initial drawable
super(_sprites.first().first());
spriteCollection = _sprites;
// set first collection of sprite to be the animation
stateTime = animTime;
currentTime = 0;
_animation = new Animation(stateTime, spriteCollection.first());
// set if the anmation needs looping
isLooping = _looping;
drawableSprite = new TextureRegionDrawable(_animation.getKeyFrame(currentTime));
this.setDrawable(drawableSprite);
}
public void update(float delta){
currentTime += delta;
TextureRegion currentSprite = _animation.getKeyFrame(currentTime, isLooping);
drawableSprite.setRegion(currentSprite);
}
public void changeToSequence(int seq){
// reset current animation time
resetTime();
_animation = new Animation(stateTime, spriteCollection.get(seq));
}
public void changeToSequence(float newseqTime, int seq){
_animation = new Animation(newseqTime, spriteCollection.get(seq));
}
public void setRepeated(boolean _repeat){
isLooping = _repeat;
}
public boolean isAnimationFinished(){
return _animation.isAnimationFinished(currentTime);
}
public void resetTime(){
currentTime = 0;
}
}
changetosequence method will make new Animation that will be used to update the current TextureRegionDrawable at the update method. resetTime will reset the total time for the animation when you call changeToSequence. You could add the event listener to call changeToSequence method.
Here is the example:
private AnimatedImage _img;
then I add the InputListener like this:
_img.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
_img.changeToSequence(1);
return true;
}
});
Hope it helps.

Use tween engine for this kind of animation. Its well documented and libgdx supports it .. Google about it , and you can find bunch of examples using libgdx .. Hope it will help you !!

Related

Libgdx: Draw a Sprite on touchdown

I want to draw A Sprite when touchDown event occurs and disposed when touchUp occurs. I tried following code:
public class Connect4Screen implements Screen {
SpriteBatch batch;
Connect4Screen(){
batch = new SpriteBatch();
camera = new OrthographicCamera(30, 20);
camera.update();
batch.setProjectionMatrix(camera.combined);
Gdx.input.setInputProcessor(new InputAdapter(){
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
drawChip();
}
}
}
public void drawChip(){
batch.begin();
batch.draw(new Texture("Images/yellow.png"), 0, 5, 1.4f,1.4f);
batch.end();
}
}
I scrapped off unnecessary code.
What is wrong here?
If you simply draw something as a one-time event, it will only be visible for 1/60 of a second. Games redraw the screen over and over in a loop, so to cause something to appear and stay on the screen, you need to set a member Boolean that indicates it should be drawn, and then in your render method you draw that item if the Boolean is true.
That's a very simplified explanation. Games tend to have many different items to draw that come and go, and keeping separate Booleans for each of them is impractical. So typically you'll have a list of items to draw, and you can add and remove items from the list based on events in the game. In your render method, you would loop through the list and draw everything in it.
Also, you must not create a new Texture without keeping a member reference to it so you can dispose() it later. Textures use native memory on the GPU and must be disposed of or they will leak memory. In LibGDX, any object that can leak memory implements Disposable, and must be disposed before you lose track of the reference.

Libgdx Hud Stage Button not Listening events

I am trying to implement a HUD stage on top of the current stage. I am able to render and draw the HUD stage but its buttons' touch events are not responding.
I am calling my drawHUD() from my draw() method of GameScreen. Code for drawHUD() is
public void drawHud(int scoreVal){
Hud.this.getCamera().update();
Hud.this.hudSpriteBatch.setProjectionMatrix(Hud.this.getCamera().combined);
hudSpriteBatch.begin();
scoreStr = "Score: " + scoreVal;
glyphLayout.setText(scoreFont, scoreStr);
halfWidth = glyphLayout.width/2;
halfHeight = glyphLayout.height/2;
scoreFont.draw(hudSpriteBatch, scoreStr, EatGame.CAMERA_WIDTH/2 - halfWidth, EatGame.CAMERA_HEIGHT - halfHeight);
hudSpriteBatch.end();
}
I have added a listener to my pauseBtn like this when creating my HUD
pauseBtn.addListener(new InputListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("PauseBtn Touched");
return false;
}
}
I have also tested by setting the bounds of the button, but it is not responding to events.
Thanks for reading and helping.
Usually you use the scene2d API for implementing buttons and stuff like that. The Stage class is responsible for handling the events on the correct actor. Look at the Stage#touchDown() how they do it. If you want to implement this on your own, you would have to implement a global touch-listener and check, if the coordinates are inside the bounds of the button and then call fire on the button with the correct Event object.
I would highly recommend to use the scene2d api, its far more easier then to write your own hit-detection-firing-event-system.
I had to use InputMultiplexer for taking input events from both the stages. I have done this that way.
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(GameScreen.this);
multiplexer.addProcessor(hud);
Gdx.input.setInputProcessor(multiplexer);
This way it will receive events from both the stages. GameScreen and Hud are Stages.

universal collision detection for action script 3

I'm writing a game where you have to go through a maze. I want this game to have different levels. But for each level, the maze is going to be different. So I drew other walls. But I do not want to write my collision detection method 50 times if I have 50 different levels.
I thought of a way of fixing it, but it's not working. I created a new symbol with nothing in it and named it wall. I think that I can make my wall = wall1 (another symbol I converted, and exported for as), and just do stage.addChild(wall). But I can't find a way to do that. So I need help!
Make a generic class e.g. Wall and make your library symbols use that for their base class. You won't need to create them at runtime using ActionScript for this inheritance to work, you can still just place your MovieClips on the stage.
The next thing you need to do is store these Walls somewhere. Because you seem inexperienced with ActionScript, and want to avoid writing code for new levels, you can automate this process using a manager type class. We will call this class WallManager and it will look like this:
public class WallManager
{
private static var _walls:Vector.<Wall> = new <Wall>[];
internal static function register(wall:Wall):void
{
_walls.push(wall);
}
public static function reset():void
{
_walls = new <Wall>[];
}
public static function get walls():Vector.<Wall>{ return _walls; }
}
Then we'll create your Wall class. Within the constructor for this class, we will automatically have the Wall add itself into the WallManager listing:
public class Wall extends Sprite
{
public function Wall()
{
WallManager.register(this);
}
public function touchingMouse(mouseX:int, mouseY:int):Boolean
{
// For this example I am checking for collisions with the
// mouse pointer. Replace this function with your own collision
// logic for whatever it is that is supposed to collide with
// these walls.
if(parent === null) return false;
var bounds:Rectangle = getBounds(parent);
return bounds.contains(mouseX, mouseY);
}
}
This setup is not 'best practice', but it is suitable in your situation because your project seems small, you appear to be working on it alone, it's simple and it gets the job done.
At the end of each level, use WallManager.reset() to remove the walls from the previous level. For checking collisions across all walls, just use a loop like this:
for each(var i:Wall in WallManager.walls)
{
var collision:Boolean = i.touchingMouse(mouseX, mouseY);
if(collision)
{
// There was a collision.
//
//
}
}
You can make one MovieClip with 50 frames saying stop() on the first frame and do your code like this:
private var wallnum:int;
public function Main()
{
stop();
wallnum = 1;
var wallobj = new Wall();
addChild(wallobj);
wallobj.gotoAndStop(wallnum);
}
For collision detection, I recommend Pixel Perfect Collision Detection (https://code.google.com/p/master-air-controller/source/browse/trunk/master-air-controller/src/PixelPerfectCollisionDetection.as?spec=svn6&r=6)

Canvas repaint should be called by itself

I have an application with jTabbedPane. There are two tab (JPanel) in jTabbedPane. First tab includes canvas and second one includes simple JLabel. Button draws rectangle into canvas.
Every thing is fine until then. However, when switching tabs, canvas would lose everything. It should be repainted by itself.
Rectangle should exist after changing tabs. Do you have any idea about the problem?
My button code is here:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Graphics g = canvas1.getGraphics();
g.drawRect(10, 10, 100, 100);
}
Thanks in advance.
First of all, you shouldn't put AWT components inside Swing components. Use JComponent or JPanel instead of Canvas.
Second, no, it shouldn't repaint itself. When the button is clicked, you should simply store what should be painted in some variable, and the paintComponent() method should be overridden in order to paint what is stored in this variable. This way, every time the component is repainted, it will repaint what has been stored last in this variable.
For example:
public class RectangleComponent extends JComponent {
private boolean shouldPaintRectangle = false;
public void setShouldPaintRectangle(boolean b) {
this.shouldPaintRectangle = b;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (shouldPaintRectangle) {
g.drawRect(10, 10, 100, 100);
}
}
}
In general, you should never ask the Graphics of a component and paint on it. Instead, you should override paintComponent() and paint the component using the Graphics passed as argument.

How to use Behavior class with Swing events?

I'm writing code for a 3D graph, and I want the scene graph to update when the user presses a JButton. I'm trying to use a Behavior class, but I can't find any information on using swing events to wake up the behavior. I would REALLY appreciate any help! Thank you!!
You can use a special behavior object which contains a queue of Runnables. You can then post runnables to the behaviour and wake it up. You will have to sort out proper synchronisation so the behaviour only goes to sleep when there are no more commands in the queue, but it should work.
Make the class into a singleton to be able to run Runnable's inside the BehaviorScheduler, analogous to the SwingUtilities.invokeLater() method.
public class ThreadTransferBehavior extends Behavior {
private final static int POST_ID = 9997;
private final WakeupOnBehaviorPost m_wakeupPost = new WakeupOnBehaviorPost(this, POST_ID);
private final Stack<Runnable> commands;
public synchronized void processStimulus(Enumeration i) {
while(!commands.isEmpty()) commands.pop().run();
wakeupOn(m_wakeupPost);
}
public synchronized void queueCommand(Runnable r) {
commands.push(r);
postId(POST_ID);
}
}