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

Author Topic: SFML Scaling  (Read 14154 times)

0 Members and 1 Guest are viewing this topic.

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« on: December 06, 2009, 12:24:48 am »
Hi. I am making a game in 2d, but will look 3D. So when i'm doing this i want to use the SFML Scale function, but it seems like it shrinks both the bottom and the top, so when i walk inwards or outwards with the character he walks too fast because his feet are moved up / down (inwards / outwards). So i did this:

Code: [Select]
float characterHeightLastFrame = Character.GetSize().y;

//Set Scale
Character.SetScale(character.y / screenHeight, character.y / screenHeight);

characterWidth = Character.GetSize().x;
characterHeight = Character.GetSize().y;

//Adjustment for scaling
if (moveUp == true)
character.y += (characterHeightLastFrame - characterHeight) * 0.5;
else if (moveDown == true)
character.y -= (characterHeight - characterHeightLastFrame) * 0.5;


That was better, but he walks faster down (outwards), than inwards. So i tried this:

Code: [Select]
//Adjustment for scaling
if (moveUp == true)
character.y += (characterHeightLastFrame - characterHeight) * 0.2;
else if (moveDown == true)
character.y -= (characterHeight - characterHeightLastFrame) * 0.8;


Then it looks better, but does anyone have any idea why it is like this, and any exact numbers on how much it scales each direction? (Prefferably math i can understand, like my 0.2 / 0.8), and maybe the X axis aswell.

Thanks for your time.

Edit: the more i think about this the less i understand it and i probably did it the wrong way trying to solve it, i hope you can help me with it. Also i guess this line is important since it sets the speed.

Code: [Select]
//Speed of character
character.speed = 1 * Character.GetPosition().y / screenHeight;


Full code:

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>



struct sSlot{
       int xMin;
       int xMax;
       int yMin;
       int yMax;
       int itemNumber;
       };

struct sCharacter{
       float x;
       float y;
       int xCenter;
       int yCenter;
       float stepX;
       float stepY;
       float speed;
       };


sCharacter character;

void moveIconsInSlots(int a, int bX, int bY,
     sf::Sprite *inventoryIcon){
     for (int d = 0; d<=15; d++){
        if (a == d)
            inventoryIcon[d].SetPosition(bX, bY);
     }
}


int main(int argc, char** argv)
{
sf::WindowSettings Settings;
Settings.DepthBits         = 24; // Request a 24 bits depth buffer
Settings.StencilBits       = 8;  // Request a 8 bits stencil buffer
Settings.AntialiasingLevel = 2;  // Request 2 levels of antialiasing

//Create the Window
sf::RenderWindow App(sf::VideoMode(1280, 1024, 32), "SFML Game", sf::Style::Fullscreen, Settings);

// Limit FPS
App.SetFramerateLimit(0);

//Vertical sync
App.UseVerticalSync(true);

//Load Images
sf::Image Image[5];

if (!Image[0].LoadFromFile("Background.png"))
    return 0;
sf::Sprite background;
background.SetImage(Image[0]);

if (!Image[1].LoadFromFile("InventoryBag.png"))
    return 0;
sf::Sprite inventoryBag;
inventoryBag.SetImage(Image[1]);

if (!Image[2].LoadFromFile("character.png"))
    return 0;
sf::Sprite Character;
Character.SetImage(Image[2]);

if (!Image[3].LoadFromFile("InventoryIcons.png"))
    return 0;
sf::Sprite inventoryIcon[16];
for (int i = 0; i<=15; i++){
inventoryIcon[i].SetImage(Image[3]);
}

//Set Rects in inventoryIcon Images
int numItemRows = 4;
int numItemCols = 4;
int iconWidth = 79;
int iconHeight = 79;
int icon = 0;
for (int colk = 0; colk < numItemCols; colk++){
    for (int rowk = 0; rowk < numItemRows; rowk++) {
        int iconLeft = rowk *(iconWidth + 1);
        int iconTop = colk *(iconHeight + 1);
        int iconRight = iconLeft + iconWidth;
        int iconBottom = iconTop + iconHeight;
        inventoryIcon[icon].SetSubRect(sf::IntRect(iconLeft,iconTop,iconRight,iconBottom));
        icon += 1;
    }
}


//Set invisible color
sf::Color ColorKey(255, 0, 255, 255);
for (int i = 0; i<=4; i++){
Image[i].CreateMaskFromColor(ColorKey, 0);
}


// Get the backgrounds dimensions
int screenWidth = background.GetSize().x;
int screenHeight = background.GetSize().y;
// Get the Characters dimensions
int characterWidth = Character.GetSize().x;
int characterHeight = Character.GetSize().y;
//Set Positions
inventoryBag.SetPosition(screenWidth - 521, screenHeight - 431);
character.x = screenWidth / 2 - characterWidth / 2;
character.y = screenHeight - characterHeight;

//Inventory Slots
sSlot Slot[16]=
{
{921, 1000, 673, 752, 0},
{1004, 1083, 673, 752, 1},
{1087, 1166, 673, 752, 2},
{1170, 1249, 673, 752, 3},
{921, 1000, 756, 835, 4},
{1004, 1083, 756, 835, 5},
{1087, 1166, 756, 835, 6},
{1170, 1249, 756, 835, -1},
{921, 1000, 839, 918, -1},
{1004, 1083, 839, 918, -1},
{1087, 1166, 839, 918, -1},
{1170, 1249, 839, 918, -1},
{921, 1000, 922, 1001, -1},
{1004, 1083, 922, 1001, -1},
{1087, 1166, 922, 1001, -1},
{1170, 1249, 922, 1001, -1}
};


bool inventory = false;
int ax;
int ay;
int itemOnMouse = -1;
int mousePos;
int dragFromSlot;
int a = 0;
int bX = 0;
int bY = 0;
bool mouseOnInventory = false;
float moveToX = character.x + characterWidth / 2;
float moveToY = character.y + characterHeight;
bool movement = false;
float rangeX = 1;
float rangeY = 1;
bool animationStanding = true;
bool animationLeft = false;
bool animationRight = false;
bool animationUp = false;
bool animationDown = false;
bool animationUpLeft = false;
bool animationUpRight = false;
bool animationDownLeft = false;
bool animationDownRight = false;
bool moveLeft = false;
bool moveRight = false;
bool moveUp = false;
bool moveDown = false;


while (App.IsOpened())
{
sf::Event Event;
    while (App.GetEvent(Event))
    {
        // Window closed
        if (Event.Type == sf::Event::Closed)
            App.Close();

        // Key Pressed
        if (Event.Type == sf::Event::KeyPressed){
            //Quit
            if (Event.Key.Code == sf::Key::Escape)
            App.Close();
            //Screenshot
            if (Event.Key.Code == sf::Key::F12){
                sf::Image Screen = App.Capture();
                Screen.SaveToFile("screenshot.jpg");
            }
            //Inventory Toggle
            if (Event.Key.Code == sf::Key::I){
                if (inventory == false)
                inventory = true;

                else if (inventory == true)
                inventory = false;
            }
        }
    }
const sf::Input& Input = App.GetInput();
int mouseX = Input.GetMouseX();
int mouseY = Input.GetMouseY();
bool leftButtonDown = Input.IsMouseButtonDown(sf::Mouse::Left);

if (inventory == true){

//Position Determination
mousePos = -1;
    for (int i=0; i<=15; i++){
        if (mouseX >= Slot[i].xMin && mouseX <= Slot[i].xMax && mouseY >= Slot[i].yMin && mouseY <= Slot[i].yMax)
        mousePos = i;
    }
//Item Placing
       //Lift item
    if (leftButtonDown == true && itemOnMouse == -1 && mousePos != -1){
        dragFromSlot = mousePos;
        itemOnMouse = Slot[mousePos].itemNumber;
        Slot[mousePos].itemNumber = -1;
    }
//Item on drop position to start position
    if (leftButtonDown == false && itemOnMouse != -1 && mousePos != -1){
        Slot[dragFromSlot].itemNumber = Slot[mousePos].itemNumber;;
    }
    //Drop item
    if (leftButtonDown == false && itemOnMouse != -1){
        if (mousePos != -1)
            Slot[mousePos].itemNumber = itemOnMouse;

        else if (mousePos == -1)
            Slot[dragFromSlot].itemNumber = itemOnMouse;

itemOnMouse = -1;
    }
}
//Icons Position
for (int i = 0; i<=15; i++){
       moveIconsInSlots(Slot[i].itemNumber, Slot[i].xMin, Slot[i].yMin,
       inventoryIcon);
}


if (itemOnMouse != -1)
    inventoryIcon[itemOnMouse].SetPosition(mouseX, mouseY);


//   ####################   END OF INVENTORY CODE    ####################


//      ####################   MOVEMENT CODE   ####################
//Speed of character
character.speed = 1 * Character.GetPosition().y / screenHeight;

//Mouse on Inventory?
if (inventory == true && mouseX >= inventoryBag.GetPosition().x + 100 &&
   mouseY >= inventoryBag.GetPosition().y)
   mouseOnInventory = true;
   else
   mouseOnInventory = false;

//                    Movement Calculations
//Toggle Movement
if (leftButtonDown == true && mouseOnInventory == false && itemOnMouse == -1){
   moveToX = mouseX;
   moveToY = mouseY;
}

//Set Center of Character
character.xCenter = character.x + characterWidth / 2;
character.yCenter = character.y + characterHeight / 2;

if (character.xCenter != moveToX || (character.y + characterHeight) != moveToY)
   movement = true;
else
    movement = false;

if (movement == true){
   animationStanding = false;

//Movement Direction Left/Right
   if (moveToX < character.xCenter)
      moveLeft = true;
   else
       moveLeft = false;
   if (moveToX > character.xCenter)
      moveRight = true;
   else
       moveRight = false;

//Movement Direction Up/Down
   if (moveToY < (character.y + characterHeight))
      moveUp = true;
   else
       moveUp = false;
   if (moveToY > (character.y + characterHeight))
      moveDown = true;
   else
       moveDown = false;


   if (leftButtonDown == true){
//Range to end Pos
      if (moveLeft == true)
         rangeX = character.xCenter - moveToX;
      else if (moveRight == true)
           rangeX = moveToX - character.xCenter;

      if (moveUp == true)
         rangeY = (character.y + characterHeight) - moveToY;
      else if (moveDown == true)
           rangeY = moveToY - (character.y  + characterHeight);


   }
//Character Step
character.stepX = rangeX / (rangeX + rangeY) * 16 * character.speed;
character.stepY = rangeY / (rangeX + rangeY) * 16 * character.speed;

}
else
animationStanding = true;

float characterHeightLastFrame = Character.GetSize().y;

//Set Scale
Character.SetScale(character.y / screenHeight, character.y / screenHeight);

characterWidth = Character.GetSize().x;
characterHeight = Character.GetSize().y;

//Adjustment for scaling
if (moveUp == true)
character.y += (characterHeightLastFrame - characterHeight) * 0.0;
else if (moveDown == true)
character.y -= (characterHeight - characterHeightLastFrame) * 1.0;

//From struct to drawable
Character.SetPosition(character.x, character.y);

//Background
App.Draw(background);
//Character
App.Draw(Character);
if (inventory == true){
    //Inventory
    App.Draw(inventoryBag);
    //Icons in slots
    for (int i = 0; i<=15; i++){
        if (Slot[0].itemNumber == i || Slot[1].itemNumber == i || Slot[2].itemNumber == i || Slot[3].itemNumber == i ||
            Slot[4].itemNumber == i || Slot[5].itemNumber == i || Slot[6].itemNumber == i || Slot[7].itemNumber == i ||
            Slot[8].itemNumber == i || Slot[9].itemNumber == i || Slot[10].itemNumber == i || Slot[11].itemNumber == i ||
            Slot[12].itemNumber == i || Slot[13].itemNumber == i || Slot[14].itemNumber == i || Slot[15].itemNumber == i)
            App.Draw(inventoryIcon[i]);
    }
}
//Icons on mouse
if (itemOnMouse != -1)
App.Draw(inventoryIcon[itemOnMouse]);

App.Display();
}

return 0;


}

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #1 on: December 06, 2009, 04:49:51 am »
I've made a video clip to show you the differance between when i scale, and when i don't scale. The bottom of the character scales upwards i believe, and the top a bit aswell i think. The bottom center is supposed to end up at the end location, but since it goes upwards it will not, and it will have to adjust the last part. Don't pay too much attention to the character not stopping movement atm, that is a minor issue. I will paste you the link: http://www.youtube.com/watch?v=00Fnu4Ym-ic

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #2 on: December 07, 2009, 04:44:04 am »
I've been trying a bit more. Atm i do this

Code: [Select]
//Adjustment for scaling
if (moveUp == true){
character.y += (characterHeightLastFrame - characterHeight) * 0.57;
character.x += (characterWidthLastFrame - characterWidth) * 0.13;
}
else if (moveDown == true){
character.y -= (characterHeight - characterHeightLastFrame) * 0.57;
character.x -= (characterWidth - characterWidthLastFrame) * 0.13;
}


But it's still not good. far from it.

Noone have any suggestions of how else i could do something about the way it scales?

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
SFML Scaling
« Reply #3 on: December 08, 2009, 11:04:02 am »
SetCenter function should solve your scaling problem.

Code: [Select]
mySprite.SetCenter(spriteWidth/2, spriteHeight);


the sprite will keep centered on it's feet and move correctly, whatever the scale you apply.

Quote
The center of the object (...) represents its center of translation, rotation and scaling. You can see it as the origin of the object, which will remain unchanged when you apply geometric transformations to it.
Pluma - Plug-in Management Framework

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #4 on: December 08, 2009, 06:59:45 pm »
I believe that wont make any differance since it calculates where to move when i press the mouse button, and then the "center" is at the feet at they are at the time, but as it moves it scales in all kinds of directions and the feet will no longer end up at the end position (unless i hold the mouse button down, although then it will move in sort of a curve since the end pos changes all the time), but thanks for posting.

Syphod

  • Jr. Member
  • **
  • Posts: 51
    • View Profile
SFML Scaling
« Reply #5 on: December 08, 2009, 07:59:50 pm »
Nope, actually, SetCenter makes all the differences.
So you can just replace things like :
Code: [Select]
rectangle.SetScale(newScale);
rectangle.SetPosition(mouseX - rectangle.GetSize().x / 2, mouseY - rectangle.GetSize().y);
with
Code: [Select]
rectangle.SetCenter(rectangleSizeX/2, rectangleSizeY);
rectangle.SetScale(newScale);
rectangle.SetPosition(mouseX, mouseY);

and you shall move your character just like it was only a point on the screen :) (yet collisions shall work properly too with not many calculations)

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #6 on: December 08, 2009, 08:54:05 pm »
I really don't understand what you are getting at. I already have a center, why would it matter if i use the function for center or not? It will still calculate the path based on what the center is when i press, and then start moving, but since the character size changes upwards etc it will not end up in the right position. I don't see how what you are saying would solve anything. The only possible solution how i see it would be to move the characters actual CENTER both x and y center to a position instead of the feet because then it wouldn't matter how much every side scales. But i would like his feet to end up where i press. Or do something like i have been trying, but i have been unsuccesful at it for some reason.

I have tried to calculate how much it moves too much and remove that extra movement (made by scaling the char). This is how i tried it but it's not working:

Code: [Select]
characterXBeforeMovement = Character.GetPosition().x;
characterYBeforeMovement = Character.GetPosition().y;
//Move Char
   if (moveLeft == true)
      character.x -= character.stepX;
   else if (moveRight == true)
        character.x += character.stepX;
   if (moveUp == true)
      character.y -= character.stepY;
   else if (moveDown == true)
        character.y += character.stepY;


}
else
animation = Standing;


//Set Scale
Character.SetScale(character.y / screenHeight, character.y / screenHeight);

characterWidth = Character.GetSize().x;
characterHeight = Character.GetSize().y;

//From struct to drawable
Character.SetPosition(character.x, character.y);

if (characterYBeforeMovement > Character.GetPosition().y)
character.y -= characterYBeforeMovement - Character.GetPosition().y - character.stepY;

else if (Character.GetPosition().y > characterYBeforeMovement)
character.y += Character.GetPosition().y - characterYBeforeMovement - character.stepY;

if (characterXBeforeMovement > Character.GetPosition().x)
character.x -= characterXBeforeMovement - Character.GetPosition().x - character.stepX;

else if (Character.GetPosition().x > characterXBeforeMovement)
character.x += Character.GetPosition().x - characterXBeforeMovement - character.stepX;

//From struct to drawable
Character.SetPosition(character.x, character.y);


If you still believe that the character center thing will work please explain it better to me so even i can understand

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
SFML Scaling
« Reply #7 on: December 08, 2009, 09:23:48 pm »
This is a question of points. Image size and sprite scale as nothing to do with it.

You just want to move a point from a place to another.
An image is drawn over that point, centered on it, with some scaling factors and maybe other geometrical transforms, but we let all of that to SFML deal internally.

We just have to take care of the sprite position. And it's position is actually it's center position in the world, and not the top-left corner.


Code: [Select]
sprite.SetCenter(width/2, height)
When you do this, it makes that every time you ask the sprite for its position, it will return the position of that point on the world, and not the top left point.
If you scale the image, that point isn't changed. All around the point grows for the sides, and the center keeps the same.

So, if you set center to be sprite's "feet", then it's feet always coincide with sprite's positon, whatever the scale you apply.
SetCenter once, and move it everywhere you want, scale it as much as you would like, that it's position will always be centered on the feet.




Edit: btw, this thread should be moved to Graphics forum  :wink:
Pluma - Plug-in Management Framework

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #8 on: December 09, 2009, 03:30:00 am »
hm, so what i will do is instead of changing X and Y i say to it that it should move the Center position towards the target? I will experiment a bit and get back to you.

edit: I will show you what i think will happen though.

[/img]

It only does math at the time that i press the mouse button. So it would move the characters feet to that point, but the feet will not be where it thinks they are since they have moved due to scaling?

Now if i update the path all the time (hold mouse button) It will look something like this with the current code. Maybe not as extreme but very very noticable. (Moving a bit curved)



I would buy your argument about the center thing if the scaling would not be done from below aswell. It seems that it moves the characters feet upwards because it's scaling. I believe i already do it your way. I use the center thing, but with my own code not the function, if i am wrong and you can show me an example what would be changed in the code that would be great because i don't understand.


To further demonstrate what i mean i will show you 2 examples. One where it scales as i would like it to, and the other one that scales in some other way.



Left side is good. Right side is bad.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
SFML Scaling
« Reply #9 on: December 09, 2009, 08:34:46 am »
No you're wrong. Like gsaurus said, the point you give to SetCenter becomes the origin of the sprite's local space (i.e. the point (0, 0)). So it will never change after scale or rotation, it is truly the center.

What you show with your drawings is a scaling centered on a random point near the top-right corner, which cannot happen if you didn't set the sprite's center to this point.

If you tried this and didn't get the expected result, then you should show us your code.
Laurent Gomila - SFML developer

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #10 on: December 09, 2009, 04:52:53 pm »
Thanks for replying. I did try it, but the character was just going crazy, i guess i didn't think it through enough. I will try it again soon and see if i can get it to work, otherwise i will post you the code.

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
SFML Scaling
« Reply #11 on: December 09, 2009, 08:23:31 pm »
Ok Zippo, here goes a simple example. Run this code and see what happens ;)

Code: [Select]
#include <SFML/Graphics.hpp>

int main(int argc, char** argv){
    // let's draw 2 rectangles with different center points, changing their scale
    sf::Shape rect1 = sf::Shape::Rectangle(0, 0, 30, 70, sf::Color::Red);
    sf::Shape rect2 = sf::Shape::Rectangle(0, 0, 30, 70, sf::Color::Green);

    // a small circle to show the center of each rectangle
    sf::Shape center = sf::Shape::Circle(0, 0, 3, sf::Color::Yellow);


    //rect1.SetCenter(0,0); // center is (0,0) by default
    rect2.SetCenter(15,70); // rect2 center is now it's feet

    // put them somewhere
    rect1.SetPosition(250, 300);
    rect2.SetPosition(550, 300);

    float scale = 0.1; // scale factor to test them

    // the window...
    sf::RenderWindow app(sf::VideoMode(800, 600, 32), "Scale Example");
    while (app.IsOpened()){
        app.Clear();

        // we set same scale for both, and don't change their position nor center
        rect1.SetScale(scale,scale);
        rect2.SetScale(scale,scale);

        // increase scale...
        scale+=0.0003;

        // draw both rects
        app.Draw(rect1);
        app.Draw(rect2);

        // draw rectangle positions, that is over their center points,
        // to make sure they don't change
        center.SetPosition(rect1.GetPosition());
        app.Draw(center);
        center.SetPosition(rect2.GetPosition());
        app.Draw(center);

        app.Display();
    }
    return EXIT_SUCCESS;
}



As you can see, the yellow circles, representing rects positions, never change, they keep at the same coordinates as it was set initially. We set the center of the green rectangle to be it's feet, meaning that the shape position is always centered on it. Then you can try to move that green rectangle anywhere and set it whatever scale you wish, that it's center point, the feet, will always coincide with the position that you give to it - in your program, the mouse coordinates. Play a bit with this example, then apply to your code :)
Hope it helps ;)
Pluma - Plug-in Management Framework

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #12 on: December 10, 2009, 04:56:13 am »
Thanks i will try

Voroz

  • Full Member
  • ***
  • Posts: 128
    • View Profile
SFML Scaling
« Reply #13 on: December 10, 2009, 05:31:58 am »
Ok i tried it in my program and it's working great :). Such an easy way to solve what seemed so hard ^^. Thx alot. Now i will see if i can find a way to make him stop shaking, then the movement + inventory is done :). I'm very new to sfml btw, came from SDL. This is much better imo. More features, and 500 times faster.

Thanks for taking the time to help me i appreciate it alot.

panithadrum

  • Sr. Member
  • ****
  • Posts: 304
    • View Profile
    • Skyrpex@Github
    • Email
SFML Scaling
« Reply #14 on: December 10, 2009, 10:15:44 am »
To solve the shaking you must take care of the speed and the distance of your object. If the speed is higher than the distance to your destination, it will start shaking. In this case, you must put your object directly to your destination point.