SFML Scaling issue

Started by
7 comments, last by evillive2 14 years, 4 months ago
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: 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: //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. //Speed of character character.speed = 1 * Character.GetPosition().y / screenHeight; Full Code:
#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.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.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.xMin && mouseX <= Slot.xMax && mouseY >= Slot.yMin && mouseY <= Slot.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.itemNumber, Slot.xMin, Slot.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);
    }
}
//Icons on mouse
if (itemOnMouse != -1)
App.Draw(inventoryIcon[itemOnMouse]);

App.Display();
}

return 0;


}

[Edited by - zippo88 on December 5, 2009 5:39:10 PM]
Advertisement
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:
I've been trying a bit more. Atm i do this

//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?
I believe you want something like this:



If that's really the case, instead of coupling the x/y positions of the character with it's scaling, add another value to its attributes, for instance, depth. Whenever you say "move up", increase the depth value by a certain amount, and do the opposite when going down. Let scaling be a function of depth, choose the "max scale", when the character is at it's bigger size (when it's "closer to the screen"), and a "minimum scale" (when it's far from the screen) and linearly interpolate between them. Given the values of minScale, maxScale, minDepth, maxDepth, the current scaling at a given depth would be given by:
scaling = minScale + (depth-minDepth)*(maxScale-minScale)/(maxDepth-minDepth)
You can then reposition the character wherever you want. If you want, its position can also be a function of depth, as to keep him always tied to the ground.

Just a note on your code: you have a lot of animation* booleans in there, and supposedly only one is active at a time. Consider using an enum instead, as it will represent all those animations using only one variable. It will be more concise for changing animations later. The same partly applies for movement direction, you might want to change the way you handle it.

Hi first thanks for replying. The reason i handle animations with alot of different bools are because it's easier to read then what direction it is going to rather than having ints. And for movement i need it because 2 can be active at the same time Left + up for example.

And for my problem i don't really understand :/. It sounds like you want me to replace X and Y with another value, but what differance would it make? And 1 thing to note is that it calculates where to move on mouseclick so if the characters feet position changes during the traveling, it won't make up for that. I somehow must remove the problem with how it scales so it won't look as he moves too fast in depth + then he will also end up in the correct position at the start.

Atm i try to calculate how much further it has moved than it's supposed to and then remove that from the position but it's not working. This is how i do it:

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);//This is after movement. It will check how long the char traveled and remove how much too far it went. Although it's not working for some reason.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);


Maybe you can explain how to use that depth value, or look at this code and see if anything is wrong.

Edit: didn't know what an enum is, but i googled it and i shall use that instead :).

[Edited by - zippo88 on December 8, 2009 12:33:55 PM]
Ok it's solved now. got help in SFML forums.
Could you tell what changes have you done?
Yes, there is a function called SetCenter, and what this does is basically moving the X and Y coordinates to a new point, and then it's no longer allowed to change that point while it's scaling, or atleast this is the impression i got of how it works. So i set center at the bottom Y and center X, and now it works.
This is still doing "depth" as fcoelho mentioned. SFML is using the relative distance from that point to determine the depth and viewing angle to draw the rest of the scene.
Evillive2

This topic is closed to new replies.

Advertisement