0
\$\begingroup\$

I'm making a simple game in C# for practice and i'm having some problems when dragging a sprite and making another sprite follow it.

What i'm trying to achieve:

  • When dragging a sprite, i want another sprite to move with it.

  • While dragging, i want the two sprites to keep the same distances they where before from one another.

  • If possible, but not related to the question, i would like to adjust this distance with another offset.

Example:

  • Lets suppose i have two sprites, one at position (10, 10) and another at (10, 20).
  • If i drag the first sprite to (10, 20) the second sprite should be at (10, 30).

Example code of what i'm trying to do:

public class Drag
{
    public Sprite first;
    public Sprite second;
    
    public bool dragging = true;
    public Point mouse_position;
    
    public void Update()
    {
        if (dragging == true)
        {
            first.position = mouse_position;
            
            var offset = ???
            var another_offset = ???
            second.position = ???
        }
    }
}

Edit: I tried the code that @DMGregory posted and @Tyyppi_77 linked but it is not working as expected. Here is the code that i'm using. Currently, the second sprite is flying all over the place.

public class Sprite
{
    public Sprite parent;
    public List<Sprite> childrens;
    public Rectangle bounds;
    
    public Point World { get { return new Point(bounds.X, bounds.Y); } }
    public Point Local { get { return new Point(World.X - parent.World.X, World.Y - parent.World.Y); } }
}

public class Drag
{
    public Sprite first;
    public Sprite second;

    public Point mouse;
    public bool dragging;
    
    public void Update()
    {
        if (dragging == true)
        {   
            first.bounds.X = mouse.X - (first.bounds.Width / 2);
            first.bounds.Y = mouse.Y - (first.bounds.Height / 2);
            
            second.bounds.X = second.Local.X;
            second.bounds.Y = second.Local.Y;
        }
    }
}

Thanks in advance!

\$\endgroup\$
10
  • 1
    \$\begingroup\$ Does this answer your question? How to keep objects in the same position relative to their parent? \$\endgroup\$
    – user35344
    Commented Aug 26, 2021 at 13:38
  • \$\begingroup\$ Hello, this answer does not directly solve my problem, i need the math for the two main problems that i'm having. \$\endgroup\$
    – RickS.
    Commented Aug 26, 2021 at 13:41
  • \$\begingroup\$ It does. The first sprite is the parent object, and the position it is dragged to is the world position of the root of the transform hierarchy = new world position of the parent. The linked answer also describes how to get the initial local offset from the world position of the parent and the child. \$\endgroup\$
    – user35344
    Commented Aug 26, 2021 at 13:43
  • 2
    \$\begingroup\$ You seem to be having some difficulty generalizing. Programming and game development are not matters of memorizing some unique magic formula for each individual action. Instead, what we do is take principles that have worked elsewhere and adapt them to new situations. Getting the offset between two items is just a subtraction of coordinates. Applying an offset is then just adding that computed difference to the new point. This works no matter whether the offset relationship is parent-child or sibling-sibling etc. \$\endgroup\$
    – DMGregory
    Commented Aug 26, 2021 at 14:50
  • 1
    \$\begingroup\$ Your code does not seem to match what is in the answer of the other post, as your calculation of the second object's world position does not seem to involve adding the constant local offset to the parent's (first object) world position. \$\endgroup\$
    – user35344
    Commented Aug 26, 2021 at 15:13

1 Answer 1

1
\$\begingroup\$

The sprite class you have written is not fit for purpose. As I've repeated to you a few times now, you should treat your local position as the source of truth, and derive the world position from it and the parent.

Your code does the opposite - it takes the world bounds as the source of truth, and derives local position from it and the parent.

That means whenever your parent moves without moving the child's bounds, the child will stay in place in the world and its local position will change to compensate. This is not at all what you want.

We can fix that by making the local position the source of truth:

public class Sprite
{
    public Sprite parent;
    public List<Sprite> children; // No "s" - "children" is already plural
    public Rectangle localBounds;
    
    public Point World { 
        get {
            Point origin = default;
            if (parent != null) origin = parent.World;

            return new Point(origin.X + localBounds.X, origin.Y + localBounds.Y);
        }

        set {
            Point origin = default;
            if (parent != null) origin = parent.World;

            localBounds.x = value.X - origin.X;
            localBounds.y = value.Y - origin.Y;
        }
    }

    public Point Local { 
        get {
            return new Point(localBounds.X, localBounds.y); 
        }

        set {
            localBounds.X = value.X;
            localBounds.Y = value.Y;
        }
    }
}

With that in hand, you can drag two sprites and maintain their offset something like this.

public class Drag
{
    public Sprite first;
    public Sprite second;

    public Point mouse;
    public bool dragging;

    // Alter this offset if you want to adjust the spacing during a drag.
    private Point _offset;
    
    // Call this when you want to begin dragging a pair of objects.
    public void StartDrag() {
         _offset = new Point(second.World.X - first.World.X,
                             second.World.Y - first.World.Y);

         dragging = true;
    }

    public void Update()
    {
        if (dragging == true)
        {   
            var position = new Point(mouse.X - (first.localBounds.Width / 2),
                                     mouse.Y - (first.localBounds.Height / 2));

            first.World = position;
            second.World = new Point(position.X + _offset.X, 
                                     position.Y + _offset.Y);

            // In case the first could be a child or grandchild of second,
            // then we need to apply a fix-up after second moves.
            first.World = position;

            // (Though in that case, you'd be better off just dragging
            //  second alone, without touching first, and let it come
            //  along for the ride automatically through parenting)
        }
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ Ok, so i got the code to run but when i click to drag a sprite, the children goes to (0, 0). Any ideas? \$\endgroup\$
    – RickS.
    Commented Aug 26, 2021 at 18:54
  • 1
    \$\begingroup\$ Nope. You have not shown us enough of your code to reproduce that problem. You can post a new question containing a Minimal Complete Verifiable Example. \$\endgroup\$
    – DMGregory
    Commented Aug 26, 2021 at 18:56
  • \$\begingroup\$ Alright @DMGregory, later this day i'll post another question if i don't manage to get it to work. Thanks for all the help. \$\endgroup\$
    – RickS.
    Commented Aug 26, 2021 at 19:01
  • \$\begingroup\$ Hello, why is the Local property never assigned? Just wondering. \$\endgroup\$
    – RickS.
    Commented Aug 26, 2021 at 19:37
  • \$\begingroup\$ Because dragging is a world space operation. \$\endgroup\$
    – DMGregory
    Commented Aug 26, 2021 at 19:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .