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

Author Topic: Animated tiles  (Read 7365 times)

0 Members and 1 Guest are viewing this topic.

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Animated tiles
« on: September 16, 2012, 03:23:49 am »
Hi all,

I almost finished implementing a basic tile engine, utilizing vertex arrays (thanks again to all the people who taught me how to handle them in an earlier topic). Now I'm at the point were I have to figure out how to render animated tiles.

So far, I have two ways in my mind. The first one is to exclude the animated tiles from the vertex array during map loading, and render them as sprites. In this way, they could be animated just like any other sprites, setting the texture rect according to the playback speed. However, I'm a bit worried that this method could become slow when rendering many animated tiles at once (when displaying large water surfaces, for example), since as far as I know, SFML doesn't do any kind of batch processing for sprites.

My other idea is to place all the animated tiles (of the same tile) on a separate layer, then manipulate the vertex array texture coordinates to do the animation. Since there would be no other tiles on these layers, it would be fast enough (I guess).

In your opinion, which way would be better/safer/faster? I haven't really played with the vertex array texture coordinates yet, but it doesn't seems to be more difficult to manipulate them than manipulating a texture rect. Is it safe to manipulate them dynamically?

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #1 on: September 16, 2012, 03:33:08 am »
What I'd do:
If they can be synchronized:
get main layer with all tiles
get few other layers each with all animated tiled changed to their next frame and holes for static tiles
draw main and then one of few others which gets updated somehow
If not sync:
same as above but during loading desynchronize the few other layers randomly
Quote
Is it safe to manipulate them dynamically?
Yes but you'll just die keeping all the information to do that stored, organised and accessible.
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #2 on: September 16, 2012, 05:23:33 am »
What I'd do:
If they can be synchronized:
get main layer with all tiles
get few other layers each with all animated tiled changed to their next frame and holes for static tiles
draw main and then one of few others which gets updated somehow
If not sync:
same as above but during loading desynchronize the few other layers randomly

What do you mean by "synchronized"? Like having different animations playing at the same speed?

Yes but you'll just die keeping all the information to do that stored, organised and accessible.

So in the end, it would be easier to render them as sprites? Thinking about it, sooner or later, I'll need to implement some kind of visibility determination system to hide all the sprites (players and dynamic objects) that are not in the view. And if I do that, I think I can safely fill the screen with sprite-based tiles without slowing the system down.

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #3 on: September 16, 2012, 02:15:21 pm »
Sprites hold transform, texture rect, texture pointer, ect. which is less than ideal, 4 vertices is ~80 bytes, sprite is over 200 I think.
Quote
What do you mean by "synchronized"? Like having different animations playing at the same speed?
By synchronized I mean every animation has same amount of frames, same framerate and at any time, all animated tiles of one kind look the same = they're all on same frame.
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #4 on: September 16, 2012, 11:21:24 pm »
I've made a little experiment, and came up with this:

for(int x3=0; x3 < layer_width; ++x3)
{
        for(int y3=0; y3 < layer_height; ++y3)
        {
                if(Layer2->GetTileId(x3, y3) != 0 && Layer2->GetTileId(x3, y3) != 29)
                {
                        int currentTile3 = Layer2->GetTileId(x3, y3);
                        int tx3 = currentTile3 % horizontalTiles;
                        int ty3 = currentTile3 / horizontalTiles;

                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 0) * tile_x, (y3 + 0) * tile_y), sf::Vector2f((tx3 + 0) * tile_x, (ty3 + 0) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 0) * tile_x, (y3 + 1) * tile_y), sf::Vector2f((tx3 + 0) * tile_x, (ty3 + 1) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 1) * tile_x, (y3 + 1) * tile_y), sf::Vector2f((tx3 + 1) * tile_x, (ty3 + 1) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 1) * tile_x, (y3 + 0) * tile_y), sf::Vector2f((tx3 + 1) * tile_x, (ty3 + 0) * tile_y)));
                }
                else if (Layer2->GetTileId(x3, y3) == 29)
                {
                        int currentTile4 = currentFrame;
                        int tx3 = currentTile4 % horizontalTiles;
                        int ty3 = currentTile4 / horizontalTiles;

                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 0) * tile_x, (y3 + 0) * tile_y), sf::Vector2f((tx3 + 0) * tile_x, (ty3 + 0) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 0) * tile_x, (y3 + 1) * tile_y), sf::Vector2f((tx3 + 0) * tile_x, (ty3 + 1) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 1) * tile_x, (y3 + 1) * tile_y), sf::Vector2f((tx3 + 1) * tile_x, (ty3 + 1) * tile_y)));
                        Array2.append(sf::Vertex(sf::Vector2f((x3 + 1) * tile_x, (y3 + 0) * tile_y), sf::Vector2f((tx3 + 1) * tile_x, (ty3 + 0) * tile_y)));
                }
        }
}

(Just like last time, GetTileId(X, Y) returns the ID of the tile at position XY, Layer2 is the tile layer that is being parsed, and Array2 is sf::VertexArray Array2(sf::Quads).)

It kinda works, if the tile ID is zero or 29 , the quad is not being created. But at the next step, if the tile ID is 29, the quads are being created after the base layout has been parsed. Then, I can manipulate currentTile4 to change the texture coordinates. But I'm a bit concerned: won't this mess up the vertex array? (It's hard to examine how these quads look like withouth having a wireframe/point rendering mode, and my computer is fast enought to not to lag when something's wrong while rendering this few polygons.)

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #5 on: September 16, 2012, 11:52:58 pm »
Do you ever clear your vertex array or are you just appending..
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #6 on: September 17, 2012, 12:10:29 am »
Just appending. When/why should I clear them?

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #7 on: September 17, 2012, 12:16:36 am »
Quote
Just appending. When/why should I clear them?
Seriously? ???
If you never clear and keep appending it's obviosuly not good.
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #8 on: September 17, 2012, 01:15:20 am »
I believe you, but still not sure when I need to clear them. Since there are no memory leaks at exit (at least neither Visual Leak Detector nor the integrated MSVS debugger found any), it seems that SFML cleans them up automatically.

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #9 on: September 17, 2012, 01:28:59 am »
Yes but you're covering the old quads with new ones instead of removing the old ones(which is going to be hard if you have holes between quads in your vertexarray).
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #10 on: September 17, 2012, 01:57:32 am »
That's it, I'll go with the sprite based approach. Using vertex arrays/polygons/quads are certainly beyond my current capabilities. I'll wait until you release your Eduard Engine as open source so I can look at how the professionals do it. :P Until that, I just won't render oceans using animated sprites.

On a side note, I just started up a game that was made with RPG Maker 2000 (which is written in Object Pascal/Delphi (so there's no extreme Assembly-optimization), and uses no hardware acceleration at all (dates back to 1996 when 3D-capable cards were very expensive), and used to run fine on a (definitely) non-3D S3 card back then). There is a map which is filled with animated water tiles, yet the system is able to keep running at constant 60 FPS, so I honestly don't know why wouldn't this approach work in SFML.

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #11 on: September 17, 2012, 02:23:05 am »
Quote
That's it, I'll go with the sprite based approach. Using vertex arrays/polygons/quads are certainly beyond my current capabilities. I'll wait until you release your Eduard Engine as open source so I can look at how the professionals do it.  Until that, I just won't render oceans using animated sprites.
I'm not professional, I don't have animated tiles in ee(I might consider it but it'd mean api breaking changes to several classes), and it's open source release is not happening anytime soon.
Quote
so I honestly don't know why wouldn't this approach work in SFML.
It would, kind of :), I might write example of my approach to that tomorrow.

Oh, and don't get fooled by 'engine', it's not like it's going to be a real usable engine*, it's just work in progress name for that.

*Altho someone could probably throw almost everything out but leave game core like abc for screens, animation manager and tickets, texture manager and tickets, mouse, keyboard and resolution options and use them and their apis for something.
« Last Edit: September 17, 2012, 02:46:43 am by FRex »
Back to C++ gamedev with SFML in May 2023

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Animated tiles
« Reply #12 on: September 17, 2012, 05:12:08 am »
Yes but you're covering the old quads with new ones instead of removing the old ones(which is going to be hard if you have holes between quads in your vertexarray).

Although I completely abandoned the idea to use vertex arrays for the animated tiles, I can't sleep because of this.  :)

In what way did I cover the old quads? When the tile index is zero or 29, it hasn't been created at all on the first pass, so with my test app, there were no quads created at all and the array was empty. Then, at the second pass, the parser iterated through the map again, and only rendered tiles with ID 29. So in the end, these were the only quads created.

I'm not professional, I don't have animated tiles in ee(I might consider it but it'd mean api breaking changes to several classes), and it's open source release is not happening anytime soon.

Okay then, the sprite based system will stay for a while...  ;D (Unless I learn how to properly use SFML.)

I might write example of my approach to that tomorrow.

Now that would be great.

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Animated tiles
« Reply #13 on: September 17, 2012, 03:01:50 pm »
Quote
Now that would be great.
Not really, no.  :P
The way I could do it is have one vertex array and few textures and keep switching texture pointers that I'm giving to states object. Like that:
#pragma once
#include "EETiledMap.h"
class EEAnimatedTiledMap : public EETiledMap
{
private:
        virtual void draw(sf::RenderTarget& target,sf::RenderStates states)const;
        std::vector<EETextureTicket> m_textures;
        unsigned frame;
        float frame_progress;
public:
        EEAnimatedTiledMap(void);
        virtual ~EEAnimatedTiledMap(void);
        void Update(float gprogress);
};
#include "StdAfx.h"
#include "EEAnimatedTiledMap.h"
void EEAnimatedTiledMap::draw(sf::RenderTarget& target,sf::RenderStates states)const
{
        states.texture=m_textures[frame].GetTexPtr();
        for(int x=left;x<right;++x)
        {
                for(int y=top;y<bottom;++y)
                {
                        target.draw(my_chunks[x][y],states);
                }
        }
}
EEAnimatedTiledMap::EEAnimatedTiledMap(void):frame(0),frame_progress(0.f)
{
        /*load textures to m_textures somehow*/
}
EEAnimatedTiledMap::~EEAnimatedTiledMap(void)
{

}
void EEAnimatedTiledMap::Update(float gprogress)
{
        frame_progress+=gprogress;
        if(frame_progress>=1.f)
        {
                frame_progress=0.f;
                ++frame;
                if(frame>=m_textures.size())
                {
                        frame=0;
                }
        }
}
But that requires animations to all have same amount of frames and be synchronized(every animation is at any time at frame x, you can't have one tile be on middle frame of it's animation and other be at the end frame), and still tiles to have same graphic in same place in every texture.
The EETiledMap fills my_chunks with proper vertices and left right top bottom are set by it every frame to limit drawing to arrays visible in view.
EETextureTicket is class that gets texture pointer from my core texture manager and can return pointers, references, name, ect.
EEVertices is my version of vertex array, almost same.
« Last Edit: September 17, 2012, 03:06:49 pm by FRex »
Back to C++ gamedev with SFML in May 2023