You basically have to do 3D->2D transformations. Even if you have a 2D game, you're simulating depth, therefore you have to store your object's positions using a 3D coordinate system and transform them into 2D for rendering. You won't run into trouble with hacking your positions anymore.
x and y of each object can still be transformed 1:1, however you have to transform z into x and/or y (because those are the only axes you have for rendering). When an object moves further afar, the z value decreases (or increases, which depends on your implementation of your coordinate system). Visually you see that by moving the object up, that means you decrease y of the rendered visual (for a good effect you should also scale objects down that are far).
A very simple example for a transformation:
sf::Vector2f transform_to_screen( const sf::Vector3f& origin ) {
return sf::Vector2f( origin.x, origin.y - origin.z );
}
You might want to play around with how origin.z is added to origin.y. However you won't mix axes anymore like you tried to do before (to recall: jumping affects y axis, moving far/near not, that's why you had issues).