### Author Topic: SFML Scaling  (Read 14315 times)

0 Members and 1 Guest are viewing this topic.

#### Voroz

• Full Member
• Posts: 128
##### 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 ScaleCharacter.SetScale(character.y / screenHeight, character.y / screenHeight);characterWidth = Character.GetSize().x;characterHeight = Character.GetSize().y;//Adjustment for scalingif (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 scalingif (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., and maybe the X axis aswell.

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 charactercharacter.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 bufferSettings.StencilBits       = 8;  // Request a 8 bits stencil bufferSettings.AntialiasingLevel = 2;  // Request 2 levels of antialiasing//Create the Windowsf::RenderWindow App(sf::VideoMode(1280, 1024, 32), "SFML Game", sf::Style::Fullscreen, Settings);// Limit FPSApp.SetFramerateLimit(0);//Vertical syncApp.UseVerticalSync(true);//Load Imagessf::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 Imagesint 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 colorsf::Color ColorKey(255, 0, 255, 255);for (int i = 0; i<=4; i++){Image[i].CreateMaskFromColor(ColorKey, 0);}// Get the backgrounds dimensionsint screenWidth = background.GetSize().x;int screenHeight = background.GetSize().y;// Get the Characters dimensionsint characterWidth = Character.GetSize().x;int characterHeight = Character.GetSize().y;//Set PositionsinventoryBag.SetPosition(screenWidth - 521, screenHeight - 431);character.x = screenWidth / 2 - characterWidth / 2;character.y = screenHeight - characterHeight;//Inventory SlotssSlot 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 DeterminationmousePos = -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 Positionfor (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 charactercharacter.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 Movementif (leftButtonDown == true && mouseOnInventory == false && itemOnMouse == -1){   moveToX = mouseX;   moveToY = mouseY;}//Set Center of Charactercharacter.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 Stepcharacter.stepX = rangeX / (rangeX + rangeY) * 16 * character.speed;character.stepY = rangeY / (rangeX + rangeY) * 16 * character.speed;}elseanimationStanding = true;float characterHeightLastFrame = Character.GetSize().y;//Set ScaleCharacter.SetScale(character.y / screenHeight, character.y / screenHeight);characterWidth = Character.GetSize().x;characterHeight = Character.GetSize().y;//Adjustment for scalingif (moveUp == true)character.y += (characterHeightLastFrame - characterHeight) * 0.0;else if (moveDown == true)character.y -= (characterHeight - characterHeightLastFrame) * 1.0;//From struct to drawableCharacter.SetPosition(character.x, character.y);//BackgroundApp.Draw(background);//CharacterApp.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 mouseif (itemOnMouse != -1)App.Draw(inventoryIcon[itemOnMouse]);App.Display();}return 0;}`

#### Voroz

• Full Member
• Posts: 128
##### 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
##### 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 scalingif (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
##### 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
##### 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
##### 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
##### 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;}elseanimation = Standing;//Set ScaleCharacter.SetScale(character.y / screenHeight, character.y / screenHeight);characterWidth = Character.GetSize().x;characterHeight = Character.GetSize().y;//From struct to drawableCharacter.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 drawableCharacter.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
##### 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
##### 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

• Hero Member
• Posts: 32504
##### 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
##### 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
##### 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
##### SFML Scaling
« Reply #12 on: December 10, 2009, 04:56:13 am »
Thanks i will try

#### Voroz

• Full Member
• Posts: 128
##### 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.