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

Author Topic: Best way to "SCROLL" an overworld map?  (Read 10011 times)

0 Members and 1 Guest are viewing this topic.

irri

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • http://www.irri.se
Best way to "SCROLL" an overworld map?
« on: November 29, 2008, 05:55:13 pm »
Hello!
I'm making a RPG-game for a project in school. My overworld is a tilebased one as you can see in the image. Which way is the best to SMOOTHLY SCROLL the world when I move the player? When am I supposed to load the new images and sprites and so on?



Thanks
Philip Irri
2D RPG Game (School project): http://PA.irri.se/

Wizzard

  • Full Member
  • ***
  • Posts: 213
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #1 on: November 29, 2008, 09:07:52 pm »
You should use an additional sf::View to scroll the screen, like so:
Code: [Select]
       float OffsetX = 0.f;
        float OffsetY = 0.f;

        if (Input.IsKeyDown(sf::Key::Up))    OffsetY = -128.f;
        if (Input.IsKeyDown(sf::Key::Left))  OffsetX = -128.f;
        if (Input.IsKeyDown(sf::Key::Down))  OffsetY += 128.f;
        if (Input.IsKeyDown(sf::Key::Right)) OffsetX += 128.f;

        View.Move(OffsetX, OffsetY);       // Move the player

        App.SetView(View);                 // Draw relative to the world
        App.Draw(Map);                     // Draw the map
        App.SetView(App.GetDefaultView()); // Draw relative to the GUI
        App.Draw(Player);                  // Draw the player

Unfortunately, it's not that easy. This code will make the player run at different speeds depending on how fast the computer can cycle through the code.
Code: [Select]
       float Offset  = App.GetFrameTime() * 128.f;
        float OffsetX = 0.f;
        float OffsetY = 0.f;

        if (Input.IsKeyDown(sf::Key::Up))    OffsetY = -Offset;
        if (Input.IsKeyDown(sf::Key::Left))  OffsetX = -Offset;
        if (Input.IsKeyDown(sf::Key::Down))  OffsetY += Offset;
        if (Input.IsKeyDown(sf::Key::Right)) OffsetX += Offset;

There we go. If we multiply how fast our program is cycling through the code in nanoseconds with our movement, it works at the same speed on every computer.


There is one last problem you may want to fix, though. SFML is trying to position our sprites in between pixels because of our multiplication by nanoseconds. This will create some odd distortion on our sprites. We will need to prevent SFML from doing this by rounding the player's position to the nearest whole number right before SFML goes to draw the world. We can't permanently round the position because that would cause the position to be unpredictable and also bring back the problem that we just fixed above. So, we need to set the position back as soon as SFML is done with it.
Code: [Select]
       const sf::Vector2f& Center = View.GetCenter();                    // Store the player's original position

        View.SetCenter(floorf(Center.x + 0.5f), floorf(Center.y + 0.5f)); // Round the player's position

        App.SetView(View);
        App.Draw(World);
        App.Draw(Enemy);

        View.SetCenter(Center);                                           // Go back to the original position

Edit:
As for your sprites, create them on first use and destroy them when they're no longer being used.

irri

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • http://www.irri.se
Best way to "SCROLL" an overworld map?
« Reply #2 on: November 30, 2008, 04:33:08 pm »
Thank you very much!
I didn't realise that sf::View was capable of doing such a thing. I thought  it only was for zooming and such. ^^

I have implemented it now.
Hmm, next thing to do is to load the map in via some file and make it draw only those sprites that shall be visible for the player.

Thanks
2D RPG Game (School project): http://PA.irri.se/

heishe

  • Full Member
  • ***
  • Posts: 121
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #3 on: December 01, 2008, 10:27:31 pm »
Quote from: "irri"
Thank you very much!
I didn't realise that sf::View was capable of doing such a thing. I thought  it only was for zooming and such. ^^

I have implemented it now.
Hmm, next thing to do is to load the map in via some file and make it draw only those sprites that shall be visible for the player.

Thanks


use tinyxml (search on google for the lib) and the xml file format for loading things, you won't regret it.

for only drawing sprites visible to the player, simply check which sprites collide with your "view-rectangle" and which do not. you can even take this a step further and divide your world into virtual zones, of which everyone handles pointers to the sprites belonging to them. that way, you dont have to do a collision check for every sprite.

bullno1

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #4 on: December 02, 2008, 03:07:09 am »
No, not xml. Try Google's protocol buffer. http://code.google.com/p/protobuf/

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
Best way to "SCROLL" an overworld map?
« Reply #5 on: December 02, 2008, 10:55:23 am »
Quote from: "bullno1"
No, not xml. Try Google's protocol buffer. http://code.google.com/p/protobuf/


Thanks for the link, this could be very useful. I'm using XML at the moment.

jdindia

  • Newbie
  • *
  • Posts: 13
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #6 on: December 02, 2008, 12:35:21 pm »
Can someone explain to me what exactly you would use XML or protocol buffers for?  I don't really understand the problem it's trying to solve.

Wizzard

  • Full Member
  • ***
  • Posts: 213
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #7 on: December 02, 2008, 10:04:52 pm »
Take a look at the following XML file:

world.xml
Code: [Select]
<map tileset="world.png">
    <row>
        <tile>0</tile>
        <tile>0</tile>
    </row>
    <row>
        <tile>0</tile>
        <tile>1</tile>
    </row>
</map>

The TinyXML library helps me easily take this XML file and turn it into a fully usable instance inside my application.

irri

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • http://www.irri.se
Best way to "SCROLL" an overworld map?
« Reply #8 on: December 02, 2008, 10:36:05 pm »
Hmm...
I'll think I will use TinyXML.

Let's say that I want to have event in my XML-file for overworlds and cities etc. Events that are going to be scripted using angelscript.

Code: [Select]

<map tileset="world.png">
    <row>
        <tile>0</tile>
        <tile event="onPress: Dialog("Hello");">0</tile>
    </row>
    <row>
        <tile>0</tile>
        <tile>1</tile>
    </row>
</map>


Shall I first read in the event as a String "onPress: Dialog("Hello");" and then give the string to angelscript? Or do you guys have a more simple or smarter way to do it?
2D RPG Game (School project): http://PA.irri.se/

Wizzard

  • Full Member
  • ***
  • Posts: 213
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #9 on: December 03, 2008, 04:32:21 am »
That is a perfectly acceptable way to do it, but I would format it differently in the file to make it more readable:
Code: [Select]
<map tileset="world.png">
    <row>
        <tile>0</tile>
        <tile>0</tile>
    </row>
    <row>
        <tile>0</tile>
        <tile>1</tile>
    </row>
    <script code="onPress: Dialog("Hello");" row="1" tile="2">
</map>

Also making sure to allow scripts to be in separate files:
Code: [Select]
   <script file="hello.script">

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #10 on: December 04, 2008, 09:42:21 am »
Small piece of information: if you are looking for an XML library which can read (not write!) XML files way faster than TinyXML have a look at RapidXML.

MrQuizzles

  • Newbie
  • *
  • Posts: 15
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #11 on: December 04, 2008, 09:58:19 am »
Quote from: "Wizzard"
Take a look at the following XML file:

world.xml
Code: [Select]
<map tileset="world.png">
    <row>
        <tile>0</tile>
        <tile>0</tile>
    </row>
    <row>
        <tile>0</tile>
        <tile>1</tile>
    </row>
</map>

The TinyXML library helps me easily take this XML file and turn it into a fully usable instance inside my application.


Hah, I never thought of using XML like that. That's quite nice.

irri

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • http://www.irri.se
Best way to "SCROLL" an overworld map?
« Reply #12 on: December 04, 2008, 11:23:54 pm »
Which is the best way to store the tiles?
I have a class which contains the sf::Sprite and some other variables.

Because when I move my player, lets say to the right, I want the most left column of Tiles to be erased and all the other columns shall be shifted one step left. And the the column farest to right shall be read in by my XML-map..

In what shall I store my Tiles?

Thanks
2D RPG Game (School project): http://PA.irri.se/

Wizzard

  • Full Member
  • ***
  • Posts: 213
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #13 on: December 05, 2008, 03:09:32 am »
I recommend you store all sprites and tiles in vectors, only reading the XML file once when loading. Then, when it comes time to draw them, draw only the tiles that you need.

This could be optimized a bit more by only storing a sprite per frame in your tile set. Then, when it comes time to draw, you have to continually set the position of the correct sprite to where you want the tile to be.

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
Best way to "SCROLL" an overworld map?
« Reply #14 on: December 05, 2008, 09:50:58 am »
What I do:

First I create an image in which 1 pixel represents 1 tile and in which each color in the image represents a tile texture (green pixel = grass texture, gray pixel = road texture, etc.). Such a landscape image can even be easily edited in every graphics program.

In addition I do have images with the ground textures itself of course. Those I load at program start and even create one sprite for each texture image. I use an enum to define the different texture types (TEXTURE_GRASS, TEXTURE_ROAD, etc.). For simplicity you might use a std::map<TextureTypeEnum, sf::Sprite> for that.

Then I load the landscape image and store it one in a simple 2D matrix, a custom class which has functions like loadFromLandscapeImage(const std::string& FileName) and getTextureType(int x, int y). Internally it is a simple 1D std::vector (index in vector = landscape image width * y + x; but care for boundaries!). Of course the vector already includes the texture type, based on the color code in the landscape image.

Each frame I calculate which tiles are visible (based on scrolling and zooming and window size and stuff) and afterwards calculate the width and height all the texture sprites must have (in pixel size). In case my current sprites don't have that width and height yet (and only in that case) I loop over all sprites of the textures and set their sprite scale according to the required width and height.

Then I loop over the visible tiles, call getTextureType(x, y), access the according sprite based on the texture type and finally render that sprite on the appropriate position on the screen.

After the landscape is drawn and I now loop over the visible creatures and other stuff to draw them.