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

Author Topic: Infinitely repeated tile as background sprite  (Read 26579 times)

0 Members and 1 Guest are viewing this topic.

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #15 on: July 09, 2014, 06:43:02 am »
Yes, I'd like them to alternate and being aligned horizontally like the left and right part of a world map.
It would look like this: <--left right left right left right-->
And with three parts <--left middle right left middle right-->
In the end version I would have 20*20 equally sized parts, whereas the parts would alternate only on the x-axis. If you went  to the north or south on the y-axis on such a map, it would be finite.

A single texture is not possible in my case, because I'm working on a huge world map with 32400*32400 pixels, that is cut into 20*20 = 400--> 1620*1620 pixel sized slices. (or even smaller, if it has to be)

In case of using a tilemap, it would have 400 tiles, where every single tile has a different texture and I don't know if a tilemap makes sence here (it't not going to be a tile based game).

As for the window holding only a certain number of textures, it is supposed to zoom theoretically infinitely in and out, so as a consequence the window should be a able to hold many many "map repeats".

Is it still ok to use a tilemap in such case, even though this map will be stored/used only as a large background image and not for calculations or collisions of any kind or do I need only minimal adjustments of the code I've given as example. It's difficult for me to imagine it visually, where to change the "formula". I've been experimenting with different numbers in many ways for some time now , but to no avail. Do I have to only change the setPosition line of sprite2?
« Last Edit: July 09, 2014, 11:05:30 am by Bogdan »

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #16 on: July 09, 2014, 10:20:21 am »
Tilemap didn't work either, because the exe crashes instantly. I suppose my example map of 16200*16200 (half the size of my real map) is too big for him to handle. Is there no way "to learn him" accepting such big image file? This here is altered tutorial code:

#include <SFML/Graphics.hpp>

class TileMap : public sf::Drawable, public sf::Transformable
{
public:

    bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
    {
        if (!m_tileset.loadFromFile(tileset))
            return false;

        m_vertices.setPrimitiveType(sf::Quads);
        m_vertices.resize(width * height * 10);

        for (unsigned int i = 0; i < width; ++i)
            for (unsigned int j = 0; j < height; ++j)
            {
                int tileNumber = tiles[i + j * width];

                int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                sf::Vertex* quad = &m_vertices[(i + j * width) * 10];

                quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
                quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
                quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);

                quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
            }

        return true;
    }

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();

        // apply the tileset texture
        states.texture = &m_tileset;

        // draw the vertex array
        target.draw(m_vertices, states);
    }

    sf::VertexArray m_vertices;
    sf::Texture m_tileset;
};


int main()
{
    // create the window
    sf::RenderWindow window(sf::VideoMode(1200, 900), "Tilemap");

    // define the level with an array of tile indices
    const int level[] =
    {
        0,   2,  3,  4,  5,  6,  7,  8 , 9, 10,
        11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
        21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
                31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
                51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
                61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
                71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
                81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
                91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
    };

    TileMap map;
    if (!map.load("world.jpeg", sf::Vector2u(1620, 1620), level, 10, 10))
        return -1;

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
                        {
                                if (event.type == sf::Event::Closed)
                                        {
                                        window.close();
                                        }                                                                                                                                      
                        }
        window.clear();
        window.draw(map);
        window.display();
    }

    return 0;
}

 
« Last Edit: July 09, 2014, 11:16:46 am by Bogdan »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #17 on: July 09, 2014, 12:51:49 pm »
A texture of 16200x16200 will be too big for most of today's graphics cards. But your application shouldn't crash, instead it should show an error on the standard output (console) and display nothing.
Laurent Gomila - SFML developer

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #18 on: July 09, 2014, 02:22:36 pm »
Take a look at Third BigTexture class. Maybe that can help you.
http://www.bromeon.ch/libraries/thor/v2.0/doc/classthor_1_1_big_texture.html

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #19 on: July 09, 2014, 03:24:10 pm »
BigTexture only works with BigSprite. It won't be of any help with a vertex array.
Laurent Gomila - SFML developer

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #20 on: July 09, 2014, 06:02:29 pm »
it is supposed to zoom theoretically infinitely in and out
Don't worry about what it should be theoretically be able to do; make it do only what is necessary for the project that it is for. If that project actually requires it to zoom out a large amount, you'll need to dynamically replace the maps with smaller ones as you zoom out (similarly, replace with larger maps as you zoom in). If it actually needs to be able to zoom out forever, it will need to be able to resample them automatically.

The original point of this thread was allow infinite scrolling - not infinite zooming - using a tiling texture. Using multiple textures requires some form of tile map (not necessarily the same code as the tutorial) and zooming requires dynamic replacement.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #21 on: July 10, 2014, 04:21:35 pm »
After some days of trial & error, contemplating and analysing, I've found a "sufficient" solution. It's even in some way an infinitely repeating sprite (or more precise: multiple sprites/tiles) and perfect for my prospective game. Here is some exemplaric code (at the moment only covering the right bound) Forgive the "magic" numbers, but I feel better with them than with constants, with which I'm not yet too familiar (only in theory):



#include <SFML/Graphics.hpp>
#include <iostream>
using namespace std;

int main()
{
        sf::RenderWindow mMainWindow(sf::VideoMode(1200, 900), "Map");
       

        sf::Image image;
        image.loadFromFile("topleft.jpeg");
        sf::Texture texture;
        texture.loadFromImage(image);
        sf::Sprite sprite(texture);
        sprite.setPosition(0, 0);


        sf::Image image2;
        image2.loadFromFile("bottomleft.jpeg");
        sf::Texture texture2;
        texture2.loadFromImage(image2);
        sf::Sprite sprite2(texture2);
        sprite2.setPosition(0, 300);

       
        sf::Image image3;
        image3.loadFromFile("topright.jpeg");
        sf::Texture texture3;
        texture3.loadFromImage(image3);
        sf::Sprite sprite3(texture3);
        sprite3.setPosition(600, 0);


        sf::Image image4;
        image4.loadFromFile("bottomright.jpeg");
        sf::Texture texture4;
        texture4.loadFromImage(image4);
        sf::Sprite sprite4(texture4);
        sprite4.setPosition(600, 300);


        sf::View view(sf::Vector2f(600, 300), sf::Vector2f(1200, 900));
        view.setSize(1200,900);

        sf::RectangleShape rectangle;
        rectangle.setSize(sf::Vector2f(200, 2000));
        rectangle.setFillColor(sf::Color(100,80,100,235));
        rectangle.setPosition(1190, -500);

        sf::FloatRect rightBound = rectangle.getGlobalBounds();


        sf::RectangleShape colliderrectangle;
        colliderrectangle.setSize(sf::Vector2f(20, 20));
        colliderrectangle.setFillColor(sf::Color(255,250,255,235));
        colliderrectangle.setPosition(1160, 450);


        sf::FloatRect collider = colliderrectangle.getGlobalBounds();



while (mMainWindow.isOpen())
        {
                sf::Event event;
                while (mMainWindow.pollEvent(event))
                        {
                        if (event.type == sf::Event::Closed)
                                {
                                mMainWindow.close();
                                }
                            if (event.type == sf::Event::Resized)
                                        {
                                        sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
                                        mMainWindow.setView(sf::View(visibleArea));
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right))
                                {
                                        view.move(+150, 0);
                                        colliderrectangle.move(+150,0);
                                }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right))
                                        if (colliderrectangle.getGlobalBounds().intersects(rightBound))
                                                        {
                                                        cout << "they touch each another" << endl;
                                                        view.setCenter(0,colliderrectangle.getPosition().y-450);
                                                        colliderrectangle.setPosition(100,colliderrectangle.getPosition().y);
                                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Left))                                                  
                                        {
                                        view.move(-150, 0);
                                        colliderrectangle.move(-150,0);
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Up))                                                
                                        {
                                        view.move(0, -150);
                                        colliderrectangle.move(0,-150);
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Down))
                                        {
                                        view.move(0, +150);
                                        colliderrectangle.move(0,+150);
                                        }

                }

       

        mMainWindow.setView(view);
        mMainWindow.draw(sprite);
        mMainWindow.draw(sprite2);
        mMainWindow.draw(sprite3);
        mMainWindow.draw(sprite4);
        mMainWindow.draw(rectangle);
        mMainWindow.draw(colliderrectangle);
        mMainWindow.display();
        mMainWindow.clear();

        }

        return 0;
}
« Last Edit: July 10, 2014, 04:26:49 pm by Bogdan »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #22 on: July 11, 2014, 01:20:36 am »
I don't think I understand your goal.
Your code doesn't repeat anything. The only thing I can see your code doing is resetting the view to the left-side of the "map" when it reaches the right-size of it. If all you wanted is to wrap back to the opposite side when a side is reached, I think it can be done much more simply than this. In fact, the code I posted for a repeating texture should be able to do this if you switch off the...repeatingness. If I remember correctly, the code I posted alters the sprite's position instead of the view's location. That could be easily adapted if that's what is preferred.

I'm not sure why you have a problem with constants. You should look them up, even if it is to just save you changing every instance of "150" when you want them all to be "100"  ;)

Most of your "magic numbers" could be function calls. e.g. sprite.getSize(), mMainWindow.getSize().

Oh, that remind me. Just out of curiosity, could you tell me what the m prefix means in mMainWindow?

I don't know if your final project requires to modify images after loading them before using them as textures but if they don't, it would be simpler to leave out the sf::Image and do the loadFromFile() directly on the sf::Texture.

Your event conditions look messy (to me). I think it would be better to test for the event type being sf::Event::KeyPressed just once and then nest the tests for which code has been pressed inside it, rather than testing the type for each key.

Also, you test exactly the same conditions twice - one straight after the other - so the code could be contained within the first block. However, the second one, which tests for the collision, should probably not be inside the event loop; it can be tested afterwards.

All that said, if you just want the view to reset position, see if you can adapt my code, or let me know because I might actually be up for trying it myself  :P
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #23 on: July 11, 2014, 04:55:17 pm »
Neither did I know it before :-). But now I know that all I want, is to reset the view, because I need the static coordinates of the map for unit movments....(I've even found a method for units to leave the map to one bound and appear at the other one). I will try your code out again, after having solved my unit removal problem :-) A good  "finite", but "boundless" map filled with sprites will be the next big step....
Ok, I will look deeper into constants
m Präfix means = main function ?

All right, thats a good idea to leave out the "image" step...

Regarding the event conditions, I'm glad for them to be operational at all :-) But I will see what I can do, if I find some proper examples. For now I don't know how to do it differently.
« Last Edit: July 11, 2014, 04:58:02 pm by Bogdan »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #24 on: July 11, 2014, 05:20:52 pm »
So, you want the view to the boundary of one side when you exit the opposite side? Just test for position of the view against the map and if it passes that value, set to to the opposite position
e.g. if (viewCenter.x > map.size.x) { viewCenter.x = 0; } if (viewCenter.x < 0) { viewCenter.x = map.size.x; }
Where map.size would be the visual size of the map i.e. number of tiles * tile size.

Regarding the event conditions, I'm glad for them to be operational at all :-) But I will see what I can do, if I find some proper examples. For now I don't know how to do it differently.
if (event.type == sf::Event::KeyPressed)
{
    if (event.key.code == sf::Keyboard::Right)
    {
        // right is pressed
    }
    else if (event.key.code == sf::Keyboard::Left)
    {
        // left is pressed
    }
    // add "else if" for each key
}

p.s. If you're still having problem with things, I think you should make a new thread so that notifications aren't given to the people involved in this one.
« Last Edit: July 11, 2014, 05:22:57 pm by Golden Eagle »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything