Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Animated tiles without looping ?  (Read 2450 times)

0 Members and 1 Guest are viewing this topic.

lezebulon

  • Full Member
  • ***
  • Posts: 235
    • View Profile
Animated tiles without looping ?
« on: December 24, 2014, 04:34:52 pm »
Hi guys

I'm making a 2D overhead game where the world is made of 32x32 tiles.
Some tiles are just a picture, some tiles are animated ie they cycle through a few frames during gameplay.

For now, each tile in my 2D map is a sprite. Now let's say that at a given frame, the animated tile frame should change. All I could manage to do for this effect was to call setTextureRect() on every animated tile and manually change the texture rectangle for each sprite, so that it matches the current frame. This works fine but it seems to me that I'm doing something wrong with editing manually *each* sprite's texture rectangle.
Is there a more logical way to do this that avoid looping over all the tiles ? Like doing some work directly on the texture itself?
Also, if I intend to change things later to a vertex array instead of a 2D table of sprites, would my concerns still apply ? what would be the solution then?

Thanks!

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Animated tiles without looping ?
« Reply #1 on: December 24, 2014, 05:20:52 pm »
I don't think that looping through all relevant sprites that need to change is incorrect, just to change a textureRect is incorrect. I'm not sure why you think you're doing something wrong.
If your map extends beyond the visible view, you may want to only check the visible tiles but even then, adjusting some textureRects is unlikely to slow anything down.

Also, I'm not sure what you meant by the word "manually" in this context.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Animated tiles without looping ?
« Reply #2 on: December 24, 2014, 05:36:52 pm »
I'm guessing you have code vaguely resembling this:

int main() {
    ...
    sf::Sprite animatedSprite1;
    ...

    sf::Clock clock;
    while(window.isOpen) {
        // handle events

        sf::Time deltaTime = clock.restart();
        animatedSprite1.setTextureRect((deltaTime.asSeconds() / 10) * 32, 0); // a 1 x 10 spritesheet
        animatedSprite2.setTextureRect((deltaTime.asSeconds() / 5) * 32,
                                       (deltaTime.asSeconds() > (5 * 32)) ? 32 : 0); // a 2 x 5 spritesheet
        animatedSprite3.setTextureRect(...); // you get the idea
        ...
        // clear/draw/display
    }
}
 

If so, the answer is a class with an update() method:

class AnimatedSprite {
    public:
        AnimatedSprite(const sf::Texture&, /* tile size/count/etc */) { ... }
        update(sf::Time deltaTime) {
            d_sprite.setTextureRect(...);
        }
        draw(sf::RenderTarget target) { target.draw(d_sprite); }
    private:
        sf::Sprite d_sprite;
        /* tile size/count/etc */
}

int main() {
    ...
    AnimatedSprite animatedSprite1(...);
    ...

    sf::Clock clock;
    while(window.isOpen) {
        // handle events

        sf::Time deltaTime = clock.restart();
        animatedSprite1.update(deltaTime);
        ...
        // clear/draw/display
    }
}

Note that Thor has some animation classes to help do stuff like this: http://www.bromeon.ch/libraries/thor/v2.0/tutorial-animations.html


Hapax is right that you do have to loop over all your animating entities every frame no matter what, but when you reduce main()'s job to simply calling update() on them, it's not much of a problem.
« Last Edit: December 24, 2014, 05:42:07 pm by Ixrec »

lezebulon

  • Full Member
  • ***
  • Posts: 235
    • View Profile
Re: Animated tiles without looping ?
« Reply #3 on: December 25, 2014, 03:51:01 pm »
Hi
no I'm already doing the second solution in the code you posted.
Basically I'm asking if there's a way for the code that updates the animated tiles to not call a function on each instance of sf::Sprite (whether it's hidden away or not). I'm guessing the only way then would be to change the sf::Texture directly but it's going to be even slower and more complex.


Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Animated tiles without looping ?
« Reply #4 on: December 25, 2014, 04:26:24 pm »
In principle, no.  The main() loop always has to update every entity that needs updating.

You can do things like store all the sprites in a container so you can update all of them with a 2-3 line foreach loop (usually a good idea), or if you're feeling OOP-y have an AnimatedSpriteManager that wraps this container in a single update method (which would technically solve the question as you just phrased it, but I'm guessing that's not what you want).  In the end, yes it is all about how much hiding you want to do.

In theory you can put the update logic inside the draw() function, since you also have to call draw() on everyone, but that tends to cause a lot of other far worse problems.