AnimatedSprite.java

Any community contributions to libgdx go here! Some may get included in the core API when permission is granted.

Re: AnimatedSprite.java

Postby cyble » Fri Mar 04, 2011 11:09 pm

I had some troubles with the implementation of your class.
Turned out the following lines should be after setregion (copied the lines from the AtlasSprite constructor in the svn):
Code: Select all
if (region.rotate) rotate90(true);
setOrigin(region.originalWidth / 2, region.originalHeight / 2);
super.setBounds(region.offsetX, region.offsetY, Math.abs(region.getRegionWidth()), Math.abs(region.getRegionHeight()));
setColor(1, 1, 1, 1);


If I don't, the sprites will be all messed up and jaggy (like it's scaled). Don't really know exactly why, but it worked...

A minor improvement: using an arraylist with findRegions, eliminates the need to know the number of frames needed for the AnimatedSprite constructor. Since the region has a name, why not get the framecount ourselves :)
cyble
 
Posts: 42
Joined: Fri Feb 18, 2011 9:18 pm

Re: AnimatedSprite.java

Postby mzechner » Sat Mar 05, 2011 12:12 am

Made this a sticky
mzechner
Site Admin
 
Posts: 4721
Joined: Sat Jul 10, 2010 3:50 pm

Re: AnimatedSprite.java

Postby cyble » Tue Mar 08, 2011 9:16 pm

I studied Wavesonic's implementation and the example from the tests branch and I think it would be cool to have a generic animatedsprite class that should work with textureatlas, file handles, inmemory textures and have all benefits from our known sprite class.

So here it is (including different playback and looping types (reversed, pingpong, random)).

You can change the packagenames and stuff offcourse to your needs :)

Some examples:

Example 1: Create an animated sprite from texture atlas
*
* Create the sprite (in create() method):
* atlas = new TextureAtlas(Gdx.files.internal("data/sprites.txt"), Gdx.files.internal("data/"));
* mySprite = new AnimatedSprite(atlas, "mySprite");
*
* mySprite.setAnimationRate(60);
* mySprite.loop(true);
* mySprite.play();
*
* Render the sprite (in render() method):
* mySprite.update(Gdx.graphics.getDeltaTime());
* mySprite.draw(batch);
*

Example 2: Create an animated sprite from file and play reversed and after that pingpong-loop :)
*
* Create the sprite (in create() method):
* mySprite = new AnimatedSprite(Gdx.files.internal("data/walkanim.png"), 64, 64);
*
* mySprite.setAnimationRate(8);
* mySprite.loop(true, AnimatedSprite_LoopType.PINGPONG);
* mySprite.play(AnimatedSprite_PlayType.REVERSED);
*
* Render the sprite (in render() method):
* mySprite.update(Gdx.graphics.getDeltaTime());
* mySprite.draw(batch);


File "AnimatedSprite.java":
Code: Select all
package com.atomiccrew;

/*
 * Copyright 2011 Dennis van Haazel (info@dvh-productions.nl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;

/*
 * Example 1: Create an animated sprite from texture atlas
 *
 * Create the sprite (in create() method):
 *     atlas = new TextureAtlas(Gdx.files.internal("data/sprites.txt"), Gdx.files.internal("data/"));
 *     mySprite = new AnimatedSprite(atlas, "mySprite");
 *
 *     mySprite.setAnimationRate(60);
 *     mySprite.loop(true);
 *     mySprite.play();
 * 
 * Render the sprite (in render() method):
 *     mySprite.update(Gdx.graphics.getDeltaTime());
 *     mySprite.draw(batch);
 *
 * Example 2: Create an animated sprite from file and play reversed and after that pingpong-loop :)
 *
 * Create the sprite (in create() method):
 *     mySprite = new AnimatedSprite(Gdx.files.internal("data/walkanim.png"), 64, 64);
 *
 *     mySprite.setAnimationRate(8);
 *      mySprite.loop(true, AnimatedSprite_LoopType.PINGPONG);
 *      mySprite.play(AnimatedSprite_PlayType.REVERSED);
 * 
 * Render the sprite (in render() method):
 *     mySprite.update(Gdx.graphics.getDeltaTime());
 *     mySprite.draw(batch);
 *
 *
 *
 * @author cyble
 *
 */
public class AnimatedSprite extends Sprite

   protected List<TextureRegion> frameRegions;
   protected int currentFrame;
   
   protected float frameRate;
   protected float totalDeltaTime;
   protected boolean isPlaying;
   protected boolean isLooping;
   protected boolean isReversed;
   
   protected AnimatedSprite_PlayType playType;
   protected AnimatedSprite_LoopType loopType;

   public final boolean looping()
   {
      return isLooping;
   }
 
   /*
    * Initialize
    */
   private void Init()
   {
         frameRate = 1.0f;
         isPlaying = false;
         isLooping = true;
         isReversed = false;
        
         currentFrame = 0;
        
         frameRegions = new ArrayList<TextureRegion>();
   }
   
   // Initialize our textureregion (too bad the super constructor must be the first call in overloaded constructors in java,
   // because it's the same code as in the super constructor. Maybe badlogic can create a protected init in the sprite class ?)
   private void CreateSprite(TextureRegion region)
   {
      setRegion(region);
       setColor(1, 1, 1, 1);
       setSize(Math.abs(region.getRegionWidth()), Math.abs(region.getRegionHeight()));
       setOrigin(getWidth() / 2, getHeight() / 2);

       // Set our playhead at the correct position
       stop();
   }
   

   /*
    * Create an animated sprite, based on texture-atlas content.
    * @param textureAtlas Reference to the TextureAtlas instance
    * @param regionName Name of region to be used
   */
   public AnimatedSprite(final TextureAtlas textureAtlas, final String regionName)
   {
      Init();
       
       List<AtlasRegion> atlasFrameRegions = textureAtlas.findRegions(regionName);
       for(AtlasRegion rg : atlasFrameRegions)
          frameRegions.add((TextureRegion)rg);
    
       // Initialize our first frame
       CreateSprite(frameRegions.get(0));
   }

   
   /*
    * Create an animated sprite, based on a filehandle
    * @param file File to load
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   public AnimatedSprite(final FileHandle file, final int tileWidth, final int tileHeight)
   {
       Texture texture = new Texture(file);
       CreateAnimatedSpriteFromTexture(texture, tileWidth, tileHeight);
   }   
   
   
   /*
    * Create an animated sprite, based on an existing texture instance
    * @param texture Reference to the texture instance
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   public AnimatedSprite(final Texture texture, final int tileWidth, final int tileHeight)
   {
      CreateAnimatedSpriteFromTexture(texture, tileWidth, tileHeight);
   }
   
   
   /* Wrapper for our texture based constructors.
    * @param texture Reference to the texture instance
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   private void CreateAnimatedSpriteFromTexture(final Texture texture, final int tileWidth, final int tileHeight)
   {
       Init();
       
      // Split the texture into tiles (from upper left corner to bottom right corner)      
      TextureRegion[][] tiles = TextureRegion.split(texture, tileWidth, tileHeight);               
       
      // Now unwrap the two dimensional array into a single array with all the tiles in the correct animation order.
      for(int row = 0; row < tiles.length; row++) {
               for(int col = 0; col < tiles[row].length; col++) {
                      frameRegions.add(tiles[row][col]);
               }
       }
       
       // Initialize our first frame
      CreateSprite(frameRegions.get(0));
   }
   
   
   /*
    * Set at what rate the animated sprite should be playing.
    * @param fps Framerate in frames per second
    */
   public void setAnimationRate(final int fps)
   {
      frameRate = 1.0f / (float)fps;
   }

   
   /*
    * Loop the animation
    * @param isLooping If true: the animation plays infinite
    */
   public void loop(boolean isLooping)
   {
      loop(isLooping, AnimatedSprite_LoopType.NORMAL);
   }
   
   /*
    * Loop the animation (use special looping abilities)
    * @param isLooping If true: the animation plays infinite
    * @param loopType NORMAL: last frame ? start at frame 0. PINGPONG: last frame ? reverse animation.
    */   
   public void loop(boolean isLooping, AnimatedSprite_LoopType loopType)
   {
     this.loopType = loopType;
      this.isLooping = isLooping;
   }
 
   
   /*
    * Stop (and therefore rewind and play)
    *
    */
   public void restart()
   {
      stop();
      play();
   }

   
   /*
    * Start or resume animation
    */
   public void play()
   {
      play(AnimatedSprite_PlayType.NORMAL);
   }
   
   
   /*
    * Start or resume animation (use special playing abilities) 
    * @param playType NORMAL: start at first frame. REVERSED: start at last frame. RANDOM: pick a random frame.
    */
   public void play(AnimatedSprite_PlayType playType)
   {
     this.playType = playType;
     isReversed = this.playType == AnimatedSprite_PlayType.REVERSED;
      isPlaying = true;
      totalDeltaTime = 0;
   }
   
   /*
    * Pauses animation
    */
   public void pause()
   {
      isPlaying = false;
      totalDeltaTime = 0;
   }
   
   
   /*
    * Stops and rewinds animation.
    */
   public void stop()
   {
      pause();
      currentFrame = getFirstFrameNumber();
   }
   
   
   /* Gets the index of the last frame.
    * @return Returns 0 or last frame index.
    */
   private int getFirstFrameNumber()
   {
      return (playType == AnimatedSprite_PlayType.REVERSED ? frameRegions.size()-1 : 0);
   }
   
   
   /* Updates and increments the animation playhead to the next frame
    * @param deltaTime Frame duration in seconds.
    */
   public void update(final float deltaTime)
   {
      if( isPlaying )
      {
         totalDeltaTime += deltaTime;
         if (totalDeltaTime > frameRate)
         {
            totalDeltaTime = 0;
           
            if (this.playType == AnimatedSprite_PlayType.RANDOM)
            {
                currentFrame = (int)Math.round(Math.random() * (frameRegions.size()-1));   
            }
            else
            {
                currentFrame += (isReversed ? -1 : 1);
           
               // Back to first
               if (currentFrame >= frameRegions.size() || currentFrame < 0)
               {
                  // If not looping, stop
                  if(!isLooping)
                  {
                     stop();
                  }
                  else
                  {
                    switch (loopType)
                    {
                         case PINGPONG:
                            isReversed = !isReversed;
                            if (isReversed)
                            {
                            currentFrame = frameRegions.size() - 2;
                            if (currentFrame < 0)
                             currentFrame = 0;
                            }
                            else
                             currentFrame = 0;
                           
                            break;
                         case NORMAL:
                       default:
                          currentFrame = getFirstFrameNumber();    
                          break;
                    }
                   
                  }
               }
            }
           
            TextureRegion region = frameRegions.get(currentFrame);
           // set the region
            setRegion(region);

            // Give an AtlasRegion some special attention (boundaries may be trimmed)
            if (region instanceof AtlasRegion)
            {
               // Set the region and make sure the sprite is set at the original cell size
               AtlasRegion atlasRegion = (AtlasRegion)region;
               if (atlasRegion.rotate) rotate90(true);
               setOrigin(atlasRegion.originalWidth / 2, atlasRegion.originalHeight / 2);
               super.setBounds(atlasRegion.offsetX, atlasRegion.offsetY, Math.abs(atlasRegion.getRegionWidth()), Math.abs(atlasRegion.getRegionHeight()));
            }

            setColor(1, 1, 1, 1);
         }
      }
   }
}




File "AnimatedSprite_PlayType.java":
Code: Select all
package com.atomiccrew;

public enum AnimatedSprite_PlayType {NORMAL, REVERSED, RANDOM}


File "AnimatedSprite_LoopType.java":
Code: Select all
package com.atomiccrew;

public enum AnimatedSprite_LoopType {NORMAL, PINGPONG}
cyble
 
Posts: 42
Joined: Fri Feb 18, 2011 9:18 pm

Re: AnimatedSprite.java

Postby mzechner » Tue Mar 08, 2011 10:08 pm

Sweet! I'm a little reluctant to put in an AnimatedSprite class as it couldn't handle whitestripped texture atlas sprites. Hrm. I'll look into it.
mzechner
Site Admin
 
Posts: 4721
Joined: Sat Jul 10, 2010 3:50 pm

Re: AnimatedSprite.java

Postby cyble » Wed Mar 09, 2011 6:56 pm

mzechner wrote:Sweet! I'm a little reluctant to put in an AnimatedSprite class as it couldn't handle whitestripped texture atlas sprites. Hrm. I'll look into it.


Tested it with a sprite of a rotating bar that gets smaller. Used TexturePacker with LibGDX export and trim checked. And all showed up perfectly. But to ensure all properties are maintained like the AtlasSprite class, I expanded the class.

However, what would be much cleaner is deriving from the AtlasSprite. But I'm having some trouble overriding the constructor. Will get into that soon.

Code: Select all
package com.atomiccrew;

/*
 * Copyright 2011 Dennis van Haazel (info@dvh-productions.nl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;

/*
 * Example 1: Create an animated sprite from texture atlas
 *
 * Create the sprite (in create() method):
 *     atlas = new TextureAtlas(Gdx.files.internal("data/sprites.txt"), Gdx.files.internal("data/"));
 *     mySprite = new AnimatedSprite(atlas, "mySprite");
 *
 *     mySprite.setAnimationRate(60);
 *     mySprite.loop(true);
 *     mySprite.play();
 * 
 * Render the sprite (in render() method):
 *     mySprite.update(Gdx.graphics.getDeltaTime());
 *     mySprite.draw(batch);
 *
 * Example 2: Create an animated sprite from file and play reversed and after that pingpong-loop :)
 *
 * Create the sprite (in create() method):
 *     mySprite = new AnimatedSprite(Gdx.files.internal("data/walkanim.png"), 64, 64);
 *
 *     mySprite.setAnimationRate(8);
 *      mySprite.loop(true, AnimatedSprite_LoopType.PINGPONG);
 *      mySprite.play(AnimatedSprite_PlayType.REVERSED);
 * 
 * Render the sprite (in render() method):
 *     mySprite.update(Gdx.graphics.getDeltaTime());
 *     mySprite.draw(batch);
 *
 *
 *
 * @author cyble
 *
 */
public class AnimatedSprite extends Sprite
{
   protected TextureRegion region;
   
   protected List<TextureRegion> frameRegions;
   protected int currentFrame;
   
   protected float frameRate;
   protected float totalDeltaTime;
   protected boolean isPlaying;
   protected boolean isLooping;
   protected boolean isReversed;
   
   protected AnimatedSprite_PlayType playType;
   protected AnimatedSprite_LoopType loopType;

   public boolean isAtlasSprite;

   public final boolean looping()
   {
      return isLooping;
   }
 
   /*
    * Initialize
    */
   private void Init()
   {
         frameRate = 1.0f;
         isPlaying = false;
         isLooping = true;
         isReversed = false;
        
         currentFrame = 0;
        
         frameRegions = new ArrayList<TextureRegion>();
   }
   
   // Initialize our textureregion (too bad the super constructor must be the first call in overloaded constructors in java,
   // because it's the same code as in the super constructor. Maybe badlogic can create a protected init in the sprite class ?)
   private void CreateSprite(final TextureRegion region)
   {
      setRegion(region);
      
      if (isAtlasSprite)
      {
         AtlasRegion atlasRegion = (AtlasRegion)region;
         if (atlasRegion.rotate) rotate90(true);
           setOrigin(atlasRegion.originalWidth / 2, atlasRegion.originalHeight / 2);
           super.setBounds(atlasRegion.offsetX, atlasRegion.offsetY, Math.abs(atlasRegion.getRegionWidth()), Math.abs(atlasRegion.getRegionHeight()));
      }
      
       setColor(1, 1, 1, 1);
       
       setSize(Math.abs(region.getRegionWidth()), Math.abs(region.getRegionHeight()));
       setOrigin(getWidth() / 2, getHeight() / 2);

       // Set our playhead at the correct position
       stop();
   }
   

   /*
    * Create an animated sprite, based on texture-atlas content.
    * @param textureAtlas Reference to the TextureAtlas instance
    * @param regionName Name of region to be used
   */
   public AnimatedSprite(final TextureAtlas textureAtlas, final String regionName)
   {
      Init();
       
       List<AtlasRegion> atlasFrameRegions = textureAtlas.findRegions(regionName);
       for(AtlasRegion rg : atlasFrameRegions)
          frameRegions.add((TextureRegion)rg);
    
       // Initialize our first frame
       CreateSprite(frameRegions.get(0));
   }

   
   /*
    * Create an animated sprite, based on a filehandle
    * @param file File to load
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   public AnimatedSprite(final FileHandle file, final int tileWidth, final int tileHeight)
   {
       Texture texture = new Texture(file);
       CreateAnimatedSpriteFromTexture(texture, tileWidth, tileHeight);
   }   
   
   
   /*
    * Create an animated sprite, based on an existing texture instance
    * @param texture Reference to the texture instance
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   public AnimatedSprite(final Texture texture, final int tileWidth, final int tileHeight)
   {
      CreateAnimatedSpriteFromTexture(texture, tileWidth, tileHeight);
   }
   
   
   /* Wrapper for our texture based constructors.
    * @param texture Reference to the texture instance
    * @param tileWidth Width of each frame tile
    * @param tileHeight Height of each frame tile
    */
   private void CreateAnimatedSpriteFromTexture(final Texture texture, final int tileWidth, final int tileHeight)
   {
       Init();
       
      // Split the texture into tiles (from upper left corner to bottom right corner)      
      TextureRegion[][] tiles = TextureRegion.split(texture, tileWidth, tileHeight);               
       
      // Now unwrap the two dimensional array into a single array with all the tiles in the correct animation order.
      for(int row = 0; row < tiles.length; row++) {
               for(int col = 0; col < tiles[row].length; col++) {
                      frameRegions.add(tiles[row][col]);
               }
       }
       
       // Initialize our first frame
      CreateSprite(frameRegions.get(0));
   }
   
   
   /*
    * Set at what rate the animated sprite should be playing.
    * @param fps Framerate in frames per second
    */
   public void setAnimationRate(final int fps)
   {
      frameRate = 1.0f / (float)fps;
   }

   
   /*
    * Loop the animation
    * @param isLooping If true: the animation plays infinite
    */
   public void loop(boolean isLooping)
   {
      loop(isLooping, AnimatedSprite_LoopType.NORMAL);
   }
   
   /*
    * Loop the animation (use special looping abilities)
    * @param isLooping If true: the animation plays infinite
    * @param loopType NORMAL: last frame ? start at frame 0. PINGPONG: last frame ? reverse animation.
    */   
   public void loop(boolean isLooping, AnimatedSprite_LoopType loopType)
   {
     this.loopType = loopType;
      this.isLooping = isLooping;
   }
 
   
   /*
    * Stop (and therefore rewind and play)
    *
    */
   public void restart()
   {
      stop();
      play();
   }

   
   /*
    * Start or resume animation
    */
   public void play()
   {
      play(AnimatedSprite_PlayType.NORMAL);
   }
   
   
   /*
    * Start or resume animation (use special playing abilities) 
    * @param playType NORMAL: start at first frame. REVERSED: start at last frame. RANDOM: pick a random frame.
    */
   public void play(AnimatedSprite_PlayType playType)
   {
     this.playType = playType;
     isReversed = this.playType == AnimatedSprite_PlayType.REVERSED;
      isPlaying = true;
      totalDeltaTime = 0;
   }
   
   /*
    * Pauses animation
    */
   public void pause()
   {
      isPlaying = false;
      totalDeltaTime = 0;
   }
   
   
   /*
    * Stops and rewinds animation.
    */
   public void stop()
   {
      pause();
      currentFrame = getFirstFrameNumber();
   }
   
   
   /* Gets the index of the last frame.
    * @return Returns 0 or last frame index.
    */
   private int getFirstFrameNumber()
   {
      return (playType == AnimatedSprite_PlayType.REVERSED ? frameRegions.size()-1 : 0);
   }
   
   
   /* Updates and increments the animation playhead to the next frame
    * @param deltaTime Frame duration in seconds.
    */
   public void update(final float deltaTime)
   {
      if( isPlaying )
      {
         totalDeltaTime += deltaTime;
         if (totalDeltaTime > frameRate)
         {
            totalDeltaTime = 0;
           
            if (this.playType == AnimatedSprite_PlayType.RANDOM)
            {
                currentFrame = (int)Math.round(Math.random() * (frameRegions.size()-1));   
            }
            else
            {
                currentFrame += (isReversed ? -1 : 1);
           
               // Back to first
               if (currentFrame >= frameRegions.size() || currentFrame < 0)
               {
                  // If not looping, stop
                  if(!isLooping)
                  {
                     stop();
                  }
                  else
                  {
                    switch (loopType)
                    {
                         case PINGPONG:
                            isReversed = !isReversed;
                            if (isReversed)
                            {
                            currentFrame = frameRegions.size() - 2;
                            if (currentFrame < 0)
                             currentFrame = 0;
                            }
                            else
                             currentFrame = 0;
                           
                            break;
                         case NORMAL:
                       default:
                          currentFrame = getFirstFrameNumber();    
                          break;
                    }
                   
                  }
               }
            }
           
            TextureRegion region = frameRegions.get(currentFrame);
           // set the region
            setRegion(region);

            // Give an AtlasRegion some special attention (boundaries may be trimmed)
            if (isAtlasSprite)
            {
               // Set the region and make sure the sprite is set at the original cell size
               AtlasRegion atlasRegion = (AtlasRegion)region;
               if (atlasRegion.rotate) rotate90(true);
               setOrigin(atlasRegion.originalWidth / 2, atlasRegion.originalHeight / 2);
               super.setBounds(atlasRegion.offsetX, atlasRegion.offsetY, Math.abs(atlasRegion.getRegionWidth()), Math.abs(atlasRegion.getRegionHeight()));
            }

            setColor(1, 1, 1, 1);
         }
      }
   }
   
   public void setRegion(TextureRegion region)
   {
      isAtlasSprite = region instanceof AtlasRegion;
        this.region = region;
      super.setRegion(region);
   }
   
   public void setPosition (float x, float y) {
      if (isAtlasSprite)
            super.setPosition(x + ((AtlasRegion)region).offsetX, y + ((AtlasRegion)region).offsetY);
      else
            super.setPosition(x, y);
         
   }
   
   public void setBounds (float x, float y, float width, float height) {
      if (isAtlasSprite)
            super.setBounds(x + ((AtlasRegion)region).offsetX, y + ((AtlasRegion)region).offsetY, width, height);
      else
           super.setBounds(x, y, width, height);
   }
   
   public void setOrigin (float originX, float originY) {
      if (isAtlasSprite)
           super.setOrigin(originX + ((AtlasRegion)region).offsetX, originY + ((AtlasRegion)region).offsetY);
      else
         super.setOrigin(originX, originY);
   }
   
   public void flip (boolean x, boolean y) {
           // Flip texture.
           super.flip(x, y);
          
         if (isAtlasSprite)
         {
                float oldOffsetX = ((AtlasRegion)region).offsetX;
                float oldOffsetY = ((AtlasRegion)region).offsetY;
                // Update x and y offsets.
                ((AtlasRegion)region).flip(x, y);
         
                // Update position with new offsets.
                translate(((AtlasRegion)region).offsetX - oldOffsetX, ((AtlasRegion)region).offsetY - oldOffsetY);
         }
   }
   
   public float getX () {
          return isAtlasSprite ? super.getX() - ((AtlasRegion)region).offsetX : super.getX();
   }
   
   public float getY () {
          return isAtlasSprite ? super.getY() - ((AtlasRegion)region).offsetY : super.getY();
   }


}
Attachments
test.zip
(2.14 KiB) Downloaded 314 times
test.png
test.png (1.7 KiB) Viewed 4699 times
cyble
 
Posts: 42
Joined: Fri Feb 18, 2011 9:18 pm

Re: AnimatedSprite.java

Postby cyble » Thu Mar 10, 2011 3:27 pm

To keep the discussion in a central spot :) :

Mario says:
March 10, 2011 at 2:22 pm
"Oh, maybe i didn’t explain to well what i mean by pattern. With an AnimatedSprite class you actually have logical object state (walking, flying etc.) in a graphics object. Even worse, when people start to derrive from Sprite/AnimatedSprite and add logical members and methods to it you have a tight coupling between graphics and logic. In my opinion that’s a bad idea, even for simple games, as it does not allow for separation of concern. Instead we offer the stateless Animation class. Each instance encodes a list of TextureRegions for one animation (e.g. walking, jumping etc.) and the frame duration. No further states are kept. When you render your object, you simply take an objects state (walking, jumping) and the time it has been in that state (which is also a logical state) and pass it to the Animation class which will return the proper TextureRegion. The logical object has no idea that it is actually rendered which is a cleaner design imo. Bonus: you can simply change the rendering of your world without touching any of your logical objects."

Again I agree, didn't know about the animation class yet (I'm new with libgdx). But in your illustration you are talking about sprites that you control and have a state, like characters in a platform game. However, the reason I wanted an animated sprite was a bit different. I wanted a stateless simple fire-and-forget loopable animation, where the animation had no meaning at all. Where animation is just part of the design, it should belong in the graphics object imho. Like waves in an ocean tile or some blinking non-controllable lights in scene dressing. Offcourse I may be entirely wrong and I love to hear some suggestions.

(I hope the javadocs gets an update or something because I couldn't find the animation class in there, only in the source subversion branches. Same for some other stuff that got moved to the g2d class.)
cyble
 
Posts: 42
Joined: Fri Feb 18, 2011 9:18 pm

Re: AnimatedSprite.java

Postby mzechner » Thu Mar 10, 2011 5:58 pm

I can agree to that. For one time effects that don't have a corresponding logical representatin (altough most effects have at least a position and/or velocity) it makes sense to have an AnimatedSprite i guess, in combination with an effect manager you can tell to fire of an effect at any point. We are in agreement then, just need to document it.

I plan on writting a tutorial explaining the process of greating a full game according to the principles i like to use when writting games (not necessarily the correct or best ones of course). The idea of fire and forget graphic only objects will fit in perfectly!
mzechner
Site Admin
 
Posts: 4721
Joined: Sat Jul 10, 2010 3:50 pm

Re: AnimatedSprite.java

Postby cyble » Thu Mar 10, 2011 6:35 pm

mzechner wrote:I can agree to that. For one time effects that don't have a corresponding logical representatin (altough most effects have at least a position and/or velocity) it makes sense to have an AnimatedSprite i guess, in combination with an effect manager you can tell to fire of an effect at any point. We are in agreement then, just need to document it.

I plan on writting a tutorial explaining the process of greating a full game according to the principles i like to use when writting games (not necessarily the correct or best ones of course). The idea of fire and forget graphic only objects will fit in perfectly!


Great! I'm currently studying your animationtest and other examples to fully understand what libgdx has to offer; it's huge ! After that I will definately upgrade my class to get rid of the redundant code of the atlassprite. The code is currently fully documented, although I think you have better things to do judging from your roadmap :).

After that it's opengl es 2 time for me :) almost finished the opengl es 2 book. Keep up the good work! 8-)
cyble
 
Posts: 42
Joined: Fri Feb 18, 2011 9:18 pm

Re: AnimatedSprite.java

Postby lolomarx » Fri Sep 09, 2011 9:28 pm

It‘s useful
lolomarx
 
Posts: 9
Joined: Sun Sep 04, 2011 7:33 am

Re: AnimatedSprite.java

Postby StillCarl » Fri Sep 30, 2011 11:41 pm

Hello,

Just to point that an article about animated sprites has been added to the wiki.

Once again, a big thank you to the badlogic team !

Carl
StillCarl
 
Posts: 18
Joined: Fri Sep 30, 2011 11:08 pm

PreviousNext

Return to Libgdx Contributions

Who is online

Users browsing this forum: No registered users and 2 guests