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

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

0 Members and 2 Guests are viewing this topic.

F2CPP

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • StackOverflow
Infinitely repeated tile as background sprite
« on: February 11, 2014, 07:46:59 pm »
What I've got is

        sf::RenderWindow        Window(sf::VideoMode(1536, 768), "", sf::Style::Close);
        sf::View                        View(Window.getDefaultView());
        sf::FloatRect           fBounds(0.f, 0.f, 10.f, 1000.f); // arbitrary > view height
        sf::Texture             Texture;

        Texture.loadFromFile("C:/.../.png");
        sf::IntRect                     iBounds(fBounds);
        Texture.setRepeated(true); // repeat tile over sprite height
        sf::Sprite                      Sprite(Texture, iBounds);
        // move sprite 'up' by its height except the view height for start:
        Sprite.setPosition(fBounds.left, fBounds.top - 1000.f + View.getSize().y);

        while (Window.isOpen()) {

                View.move(0.f, -1.f); // negative y to move 'up' along sprite height

                Window.clear();
                Window.setView(View);
                Window.draw(Sprite);
                Window.display();
        }

Although I got confused with the y-axis pointing downward and the .png upward, this now repeatedly tiles the sprite (vertically), up to sprite height only however.

Is it possible, and how, to make the .png tiling truly infinite, or at least overcome the iBounds restriction?

Thanks

AN71

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #1 on: February 11, 2014, 08:05:58 pm »
If I understand correctly, you just need infinite tiling, for which you could emulate by simply having the tiled object larger than the screen, and using a subRect that once the end of the object is found, it loops back to the beginning, kind of like how people emulate toroidal topology, if you understand what I'm saying. Hope this helps a bit :)
« Last Edit: February 11, 2014, 08:40:44 pm by Aeroslizer »
Quote from: Friedrich Nietzsche
He who would learn to fly one day must first learn to stand and walk and run and climb and dance; one cannot fly into flying.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #2 on: February 11, 2014, 08:28:32 pm »
You should increase the size of the fBounds width.

EDIT: for infinity, you could move the sprite upwards by the size of the sprite everytime the view moves down by that amount.

EDIT2: adapted your code to use the idea I just suggested.
#include <SFML/Graphics.hpp>
int main()
{
        sf::RenderWindow    Window(sf::VideoMode(1000, 768), "", sf::Style::Close);
        sf::View            View(Window.getDefaultView());
        sf::FloatRect       fBounds(0.f, 0.f, 1000.f, 1000.f); // arbitrary > view height
        sf::Texture     Texture;

        Texture.loadFromFile("image.png");
        sf::IntRect         iBounds(fBounds);
        Texture.setRepeated(true); // repeat tile over sprite height
        sf::Sprite          Sprite(Texture, iBounds);
        // move sprite 'up' by its height except the view height for start:
        Sprite.setPosition(fBounds.left, fBounds.top - 1000.f + View.getSize().y);

        float viewOffsetY = 0;
        float spriteOffsetY = 0;
        unsigned int textureHeight = Texture.getSize().y;

        while (Window.isOpen()) {
                sf::Event event;
                while (Window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed)
                                Window.close();
                }
                View.setCenter(500.f, 500.f - viewOffsetY); // negative y to move 'up' along sprite height
                viewOffsetY += 0.3f; // speed of view movement
                spriteOffsetY = floor(viewOffsetY / textureHeight) * textureHeight;
                Sprite.setPosition(fBounds.left, fBounds.top /* - 1000.f + View.getSize().y */ - spriteOffsetY);

                Window.clear();
                Window.setView(View);
                Window.draw(Sprite);
                Window.display();
        }
}
« Last Edit: February 11, 2014, 08:55:55 pm by Golden Eagle »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

F2CPP

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • StackOverflow
Re: Infinitely repeated tile as background sprite
« Reply #3 on: February 11, 2014, 09:28:46 pm »
Many thanks to both of you - I was hoping for some kind of ray/open end option but this will do.

A second identical sprite involves moving just as well, so as per your initial suggestion I added a move counter

float   accumulatemoves(View.getSize().y); // simply for speed of 1.f

which increments inside the game loop

    ++accumulatemoves; // must be adjusted for varying speeds

and is checked against the View's travelled distance

 if (Sprite.getTextureRect().height <= accumulatemoves) {

                        Sprite.move(0.f, -Sprite.getTextureRect().height+View.getSize().y);
                        accumulatemoves = View.getSize().y;
                }

(which should be similar to what you show, though only along y.)

Many thanks for your help

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #4 on: February 11, 2014, 09:36:41 pm »
Or you could simple set the texture rect of the sprite to whatever size you want (with texture repeat turned on).  ;)

http://www.sfml-dev.org/tutorials/2.1/graphics-sprite.php
« Last Edit: February 11, 2014, 09:38:56 pm by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

F2CPP

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • StackOverflow
Re: Infinitely repeated tile as background sprite
« Reply #5 on: February 11, 2014, 11:21:18 pm »
Thanks, I'll stretch it to a max (though not leave it open-ended)

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #6 on: February 11, 2014, 11:45:58 pm »
Or you could simple set the texture rect of the sprite to whatever size you want (with texture repeat turned on).  ;)

http://www.sfml-dev.org/tutorials/2.1/graphics-sprite.php
I don't think that tutorial actually shows you how to change your sprite's rectangle to be larger than the texture. I may just be missing it, though. F2CPP was already using a large, repeating texture, but increasing it to a gigantic size would probably cover most applications.
That's just not infinite though :P
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #7 on: February 11, 2014, 11:50:20 pm »
Yea the tutorial doesn't show that  :P as for already using a large repeating texture - it was difficult to say either way if the initial code was using a repeating texture  :)
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #8 on: February 11, 2014, 11:52:47 pm »
it was difficult to say either way if the initial code was using a repeating texture  :)
I must admit that I didn't see it at first either and I had it open in my IDE.
Weird though; it's quite obvious:
Texture.setRepeated(true); // repeat tile over sprite height
:)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Infinitely repeated tile as background sprite
« Reply #9 on: February 11, 2014, 11:55:05 pm »
I must admit that I didn't see it at first either and I had it open in my IDE.
Weird though; it's quite obvious:
Texture.setRepeated(true); // repeat tile over sprite height
:)

Yep, I saw that the first time. But this is what I was referring to:

Quote
This works only if your sprite is configured to show a rectangle which is bigger than the texture. Otherwise this property has no effect.
(quote from tutorial)
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #10 on: February 12, 2014, 12:45:49 am »
But this is what I was referring to:
Quote
[quote from tutorial]
Ah, I see what you mean now. By "initial code", I thought you meant the one on this thread, not the tutorial   :'(
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #11 on: February 12, 2014, 11:53:26 pm »
A second identical sprite involves moving just as well, so as per your initial suggestion I added a move counter

float   accumulatemoves(View.getSize().y); // simply for speed of 1.f

which increments inside the game loop

    ++accumulatemoves; // must be adjusted for varying speeds

and is checked against the View's travelled distance

 if (Sprite.getTextureRect().height <= accumulatemoves) {

                        Sprite.move(0.f, -Sprite.getTextureRect().height+View.getSize().y);
                        accumulatemoves = View.getSize().y;
                }

(which should be similar to what you show, though only along y.)

Many thanks for your help
I changed your usage of "move" to explicit positions. It seems that you prefer to use "move" for the view. Since I still had the code I posted before, I adjusted it to automatically adjust based on where the view is - so you can "move" it wherever and the tiled sprite will follow!
#include <SFML/Graphics.hpp>
int main()
{
        sf::RenderWindow    Window(sf::VideoMode(1000, 768), "", sf::Style::Close);
        sf::View            View(Window.getDefaultView());
        sf::FloatRect       fBounds(0.f, 0.f, 1500.f, 1000.f); // arbitrary > view "SIZE"
        sf::Texture     Texture;

        Texture.loadFromFile("image.png");
        sf::IntRect         iBounds(fBounds);
        Texture.setRepeated(true);
        sf::Sprite          Sprite(Texture, iBounds);

        const sf::Vector2f viewStart(fBounds.left + (fBounds.width / 2), fBounds.top + (fBounds.height / 2));
        const sf::Vector2f spriteStart(fBounds.left, fBounds.top);

        while (Window.isOpen()) {
                sf::Event event;
                while (Window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed)
                                Window.close();
                }
                View.move(-0.2f, -0.3f); // just move the view here in any direction-the tiles will follow automatically
                const sf::Vector2f viewOffset(viewStart - View.getCenter());
                sf::Vector2f spriteOffset;
                spriteOffset.x = floor(viewOffset.x / Texture.getSize().x) * Texture.getSize().x;
                spriteOffset.y = floor(viewOffset.y / Texture.getSize().y) * Texture.getSize().y;
                Sprite.setPosition(spriteStart - spriteOffset);

                Window.clear();
                Window.setView(View);
                Window.draw(Sprite);
                Window.display();
        }
}
Hope you find this useful/interesting, but even if not, I found it relaxing  :D
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

F2CPP

  • Newbie
  • *
  • Posts: 14
    • View Profile
    • StackOverflow
Re: Infinitely repeated tile as background sprite
« Reply #12 on: February 13, 2014, 07:21:20 pm »
It is useful, much more universal, I'll get back to it when my project evolves - thanks

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Infinitely repeated tile as background sprite
« Reply #13 on: July 08, 2014, 09:40:43 pm »
Hi there,
sorry to retrieve this old thread, but I've a question concerning the code that was posted in the last post.
Is it possible to get it working for multiple tiles, that are aligned horizontally to get a earth-like "map" (which means in 2D terms: If you leave it to the left side you will reappear from the right side and vice versa :-) )
Well, I've been trying to implement that for some days now (Visaual c++ 10/SFML 2.1) :-), but it produces strange efffects and doesn't work as intended. The "blue part" (s. Attachment) is somehow "finite". Many thanks in advance for any advice! Here is the code (the main part was taken from the last post where some modifications have been applied).


#include <SFML/Graphics.hpp>
int main()
{
    sf::RenderWindow    Window(sf::VideoMode(1000, 768), "", sf::Style::Close);
    sf::View            View(Window.getDefaultView());
 
        sf::FloatRect       fBounds(0.f, 0.f, 2000.f, 500.f);
        sf::FloatRect       fBounds2(0.f, 0.f, 2000.f, 500.f); // arbitrary > view "SIZE"

    sf::Texture     Texture;
        sf::Texture             Texture2;

    Texture.loadFromFile("mapleft.png");
        Texture2.loadFromFile("mapright.png");

    sf::IntRect         iBounds(fBounds);
        sf::IntRect         iBounds2(fBounds2);

    Texture.setRepeated(true);
        Texture2.setRepeated(true);

    sf::Sprite          Sprite(Texture, iBounds);
        sf::Sprite                      Sprite2(Texture2, iBounds2);

    const sf::Vector2f viewStart(fBounds.left + (fBounds.width / 2), fBounds.top + (fBounds.height / 2));
        const sf::Vector2f viewStart2(fBounds2.left + (fBounds2.width / 2), fBounds2.top + (fBounds2.height / 2));

    const sf::Vector2f spriteStart(fBounds.left, fBounds.top);
        const sf::Vector2f spriteStart2(fBounds2.left, fBounds2.top);

while (Window.isOpen())
        {
                sf::Event event;
                while (Window.pollEvent(event))
                        {
                                if (event.type == sf::Event::Closed)
                                        {
                                        Window.close();
                                        }                                                                                                                                      
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right))
                                        {
                                        View.move(+150, 0);
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Left))                                                  
                                        {
                                        View.move(-150, 0);
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Up))
                                        {
                                        View.move(0, -150);
                                        }
                                if((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Down))                                                  
                                        {
                                        View.move(0, +150);
                                        }      
                }

        const sf::Vector2f viewOffset(viewStart - View.getCenter());

        sf::Vector2f spriteOffset;
        sf::Vector2f spriteOffset2;

        spriteOffset.x = floor(viewOffset.x / Texture.getSize().x) * Texture.getSize().x;
        spriteOffset2.x = floor(viewOffset.x / Texture.getSize().x) * Texture.getSize().x;

        Sprite.setPosition(spriteStart - spriteOffset);
                Sprite2.setPosition(spriteStart2-spriteStart - spriteOffset2+spriteOffset);

        Window.clear();
        Window.setView(View);
        Window.draw(Sprite);
                Window.draw(Sprite2);
        Window.display();
    }
}


 





Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Infinitely repeated tile as background sprite
« Reply #14 on: July 09, 2014, 12:30:40 am »
I'm not sure what it is that you are attempting to achieve. Are the two tiles supposed to alternate? i.e. red, blue, red, blue, red, blue. If so, it would be easier to just a single texture that held both. The code I posted it based upon the fact that the texture is repeating - or tiled - and that single texture is tiled over the entire window. If you use a single texture to hold both red and blue, the code I posted should work fine.
However, if that's not what you want and you need red and blue to repeat (and at different rates), you should probably use some form of tile map.

That said, if the blue and red are large enough to only ever show two (or three) in the window at once, the code could be adjusted to work (so they alternate) by stopping the texture from repeating and keeping it its original size.

If you need something different, like overlapping and/or parallax scrolling, it would need more work.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*