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

Author Topic: How to draw object with position relative to another object?  (Read 1933 times)

0 Members and 1 Guest are viewing this topic.

smurf

  • Newbie
  • *
  • Posts: 36
    • View Profile
I'm always solving this problem in a dumb way and I know theres a better way.

Suppose I have a Player class, and also a HitPoint class.
The Player object contains an instance of a HitPoint object.
When I draw the player, I also want to draw the hitpoint bar near his head.
So what I end up doing is in the Player's render method, I pass the player's relative position to the HitPoint's render method. So that I can draw the hitpoint bar at the same location of the player, but 50 pixels higher and 10 to the left.

What I'd like to avoid is somehow having to pass positions around like that. It seems like my render code is FULL of ugly little offset maths like xPos + xPos2 + 35.

Example of the problem:


class Player {
        int xPos;
        int yPos;
        HitPoint hpBar;
        public void Render() {
                DrawThePlayer();
                hpBar.Render(xPos, yPos);
        }
}
class HitPoint{
        public void Render(int x, int y) {
                DrawRect(x-10, y-50....
        }
}
 


So for example I'd prefer to have the HitPoint Render method look more like this


class HitPoint{
        public void Render() {
                DrawRect(0, 0)
        }
}
 

So I'm drwaring the hitpoint bar from (0,0) and not worrying about the Player's  position. Something else will "move" the hitpoint bar to the right place.


eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: How to draw object with position relative to another object?
« Reply #1 on: May 25, 2024, 12:22:17 pm »
What you can do for relative positioning is set a relative position on the HitPoint, then pass the transform of your player to the HitPoint and a multiply the transform of the HitPoint with the one of the Player, essentially applying all the transformations of the player to the HitPoint.

I also highly recommend to make use of Drawable and Tansformable.
Here's an example, since you seem to use  C#, I've also written in in C#:

using SFML.Graphics;
using SFML.System;
using SFML.Window;

var player = new Player();
player.Position = new Vector2f(75, 150);

var hitPoint = new HitPoint();
hitPoint.Position = new Vector2f(2, -10);

var window = new RenderWindow(new VideoMode(200, 200), "SFML.Net Test");
window.SetFramerateLimit(144);
window.Closed += (_, _) => { window.Close(); };
window.KeyPressed += (_, eventArgs) =>
{
    const int speed = 2;

    var direction = eventArgs.Code switch
    {
        Keyboard.Key.Left => -1,
        Keyboard.Key.Right => 1,
        _ => 0
    };

    player.Position += new Vector2f(direction * speed, 0);
};

while (window.IsOpen)
{
    window.DispatchEvents();
    window.Clear();
    window.Draw(player);
    window.Draw(hitPoint, new RenderStates(player.Transform));
    window.Display();
}

public class Player : Transformable, Drawable
{
    private readonly RectangleShape _shape;

    public Player()
    {
        _shape = new RectangleShape(new Vector2f(20, 20));
        _shape.FillColor = Color.Green;
    }
   
    public void Draw(RenderTarget target, RenderStates states)
    {
        states.Transform *= Transform;
        target.Draw(_shape, states);
    }
}

public class HitPoint : Transformable, Drawable
{
    private readonly RectangleShape _shape;

    public HitPoint()
    {
        _shape = new RectangleShape(new Vector2f(16, 4));
        _shape.FillColor = Color.Red;
    }
   
    public void Draw(RenderTarget target, RenderStates states)
    {
        states.Transform *= Transform;
        target.Draw(_shape, states);
    }
}
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

smurf

  • Newbie
  • *
  • Posts: 36
    • View Profile
Re: How to draw object with position relative to another object?
« Reply #2 on: May 27, 2024, 05:35:58 am »
Thanks for this!
Its better than what I had for sure.
I made a small improvement by moving the hitpoint object into the player which makes more sense to me.
Unfortunately something still seems a bit inelegant about it, specifically having to pass the new RenderStates() thing to the draw call. But I guess there is no way to make this implicit.
Anyway thanks again!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: How to draw object with position relative to another object?
« Reply #3 on: May 27, 2024, 07:57:57 am »
If you moved it inside the player, then you can draw the hitpoint inside the player's Draw call and apply the transformation there.
At some point, you need to have code that says it's relative to X ;D
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

smurf

  • Newbie
  • *
  • Posts: 36
    • View Profile
Re: How to draw object with position relative to another object?
« Reply #4 on: May 29, 2024, 05:47:50 pm »
Yup I think I have something relatively clean now.

I must have been thinking back to using raw OpenGL, when you could use Push() and Pop() to save and load transformation states, and could get the same effect without having to pass any objects around.