Locking an object to another based on its image_angle

G

Glenn1990

Guest
Hello,

I'm trying to have an object 'locked' to another, so when the primary object rotates the secondary object will rotate around it at a fixed distance away from the primary.
For example a rocket booster on the back of a ship. As the ship rotates the booster always stays at the back of the ship at the same distance away from the ships origin.

I have this code on the secondary object and it seems to work fine:
x = parentObject.x + lengthdir_x(64, parentObject.image_angle);
y = parentObject.y + lengthdir_y(64, parentObject.image_angle);

However if i change one of the distance values (64) so they are no longer equal, the distance between the primary and secondary objects seems to change. Making the secondary move either closer to or away from the primary.
For example:
x = parentObject.x + lengthdir_x(256, parentObject.image_angle);
y = parentObject.y + lengthdir_y(64, parentObject.image_angle);

This has really got me stumped as I want the x and y to have different distances away from the primary origin, any help would be great.

Thanks.
 

Lite

Member
Did the same thing but instead of a space ship it was a sailing ship that had a water effect attached behind it just like a rocket booster.
In the STEP on attached object:
Code:
image_angle = parentObject.image_angle;
c = dcos(parentObject.image_angle);   //calculate cos
s = dsin(parentObject.image_angle);   //calculate sin
x = parentObject.x + (64)*c + 0*s;   //the 64 is the x difference so adjust as you need
y = parentObject.y + 0*c - (64)*s;
This should keep it attached to the parent object just as a thruster on a rocketship, the only thing you need to adjust is the x and y offset values.
 
G

Glenn1990

Guest
Did the same thing but instead of a space ship it was a sailing ship that had a water effect attached behind it just like a rocket booster.
In the STEP on attached object:
Code:
image_angle = parentObject.image_angle;
c = dcos(parentObject.image_angle);   //calculate cos
s = dsin(parentObject.image_angle);   //calculate sin
x = parentObject.x + (64)*c + 0*s;   //the 64 is the x difference so adjust as you need
y = parentObject.y + 0*c - (64)*s;
This should keep it attached to the parent object just as a thruster on a rocketship, the only thing you need to adjust is the x and y offset values.
Thanks for the reply.

This code works great if I'm using '64' in both lines (or the same number). Once you change one of them I get the same issues as before. I've researched this many time and yours and other people code is working for everyone but me. I wonder what I'm doing wrong.

For example, the code you linked works but the code below with a new X does not.
image_angle = parentObject.image_angle;
c = dcos(parentObject.image_angle); //calculate cos
s = dsin(parentObject.image_angle); //calculate sin
x = parentObject.x + (128)*c + 0*s; //the 64 is the x difference so adjust as you need
y = parentObject.y + 0*c - (64)*s;
 
Last edited by a moderator:
That's not possible. Correct me if I'm wrong but if the length in the lengthdir equation is different between the x and y values, you are calculating a value for a different point in space.
 

Electros

Member
At least for my code, to lock an exhaust to a rotatable ship, I have first calculated the hypotenuse dist:

Code:
        //Vector length calculation to set and maintain offset distance
        offsetDist = sqrt(sqr(0 - xOffset) + (sqr(0 - yOffset)));
And then used that for the lengthdir calculations, and it seems to work:

Code:
    x = enemyTracking.x + lengthdir_x(offsetDist, enemyTracking.image_angle + 90);
    y = enemyTracking.y + lengthdir_y(offsetDist, enemyTracking.image_angle + 90);
So yeah, len should be a single value (whatever it is) and the lengthdir functions used to return the x and y components based on the angle.
 
G

Glenn1990

Guest
At least for my code, to lock an exhaust to a rotatable ship, I have first calculated the hypotenuse dist:

Code:
        //Vector length calculation to set and maintain offset distance
        offsetDist = sqrt(sqr(0 - xOffset) + (sqr(0 - yOffset)));
And then used that for the lengthdir calculations, and it seems to work:

Code:
    x = enemyTracking.x + lengthdir_x(offsetDist, enemyTracking.image_angle + 90);
    y = enemyTracking.y + lengthdir_y(offsetDist, enemyTracking.image_angle + 90);
So yeah, len should be a single value (whatever it is) and the lengthdir functions used to return the x and y components based on the angle.

Still doesn't seem to work right. I cant believe it's so difficult to have something lock to another object as it spins. With unity I just made it a child and it worked automatically.

I've spent so much time on this and I just don't get it.

EDIT: I appreciate all the help despite my frustration.
 

NicoFIDI

Member
This is a circle with radius a:
Code:
t between 0 and 360
x = a*cos(t);
y = a*sin(t);
This is a ellipse:
Code:
t between 0 and 360
x = a*cos(t);
y = b*sin(t);
having a != b
i didn't get what's your problem but this is what you are doing.
if you try to make it follow a larger image and still be a circle increase both in the same ammount.
 
I'll just chip in here with my version of the rotation code, which is exactly the same as yours except I also keep track of the parent objects rotation (using my own variable called rotate_speed) and then rotate the child objects image angle to match that as well.

CREATE Event:
Code:
distance_from_center_of_parent = point_distance(x, y, parent_instance.x, parent_instance.y)
offset_angle = point_direction(parent_instance.x, parent_instance.y, x, y)
STEP Event:
Code:
if ( instance_exists(parent_instance) )
{
        var dX = lengthdir_x(distance_from_center_of_parent, (parent_instance.image_angle + offset_angle) mod 360);
        var dY = lengthdir_y(distance_from_center_of_parent, (parent_instance.image_angle + offset_angle) mod 360);

        x = parent_instance.x + dX
        y = parent_instance.y + dY
        image_angle += parent_instance.rotate_speed // Updates the image_angle of the child object correctly respective to parent object
}
Your code is doing exactly what it should be doing, given that you are only changing one of the length variables independent from the other.

Question: Can you draw us a picture of what result you actually want? That might enable us to see where to help you better.

P.S. A thing called sprite anchor points may be coming in the future sometime...not guaranteed but it's on the list somewhere, see the following link: (Also, If I've made the link correctly, it will take you to a post about halfway through the conversation, that has an alternative solution using Paths and matrix rotations that you might want to try if you are feeling game)

Alternate Anchor Points on Sprites
 

Electros

Member
Still doesn't seem to work right. I cant believe it's so difficult to have something lock to another object as it spins. With unity I just made it a child and it worked automatically.

I've spent so much time on this and I just don't get it.

EDIT: I appreciate all the help despite my frustration.
Hmm, the only other pointers I can think of are to re-examine your origins, and also are you doing any image scaling, or draw transforming of x and or y of the primary object? If so that would need to be accounted for with the locking position.

P.S Using two different values is using half a a component from two radii. Out of interest in your example, does replacing both 256 and 64 with 263.88 work?
 
Last edited:

NicoFIDI

Member
Still doesn't seem to work right. I cant believe it's so difficult to have something lock to another object as it spins. With unity I just made it a child and it worked automatically.

I've spent so much time on this and I just don't get it.

EDIT: I appreciate all the help despite my frustration.
Yeah, now you probably respect the developers of unity a little more XD.
Still, your problem it's not enought clear, you change your values from 64 to 256,
but what was your reason behind it?
what's the behaviour you want your code to do by changing that number? :)
 

bacteriaman

Member
Did the same thing but instead of a space ship it was a sailing ship that had a water effect attached behind it just like a rocket booster.
In the STEP on attached object:
Code:
image_angle = parentObject.image_angle;
c = dcos(parentObject.image_angle);   //calculate cos
s = dsin(parentObject.image_angle);   //calculate sin
x = parentObject.x + (64)*c + 0*s;   //the 64 is the x difference so adjust as you need
y = parentObject.y + 0*c - (64)*s;
This should keep it attached to the parent object just as a thruster on a rocketship, the only thing you need to adjust is the x and y offset values.
Six years later, this post is still extremely useful--thank you!
 
GML:
image_angle = parentObject.image_angle;
c = dcos(parentObject.image_angle);   //calculate cos
s = dsin(parentObject.image_angle);   //calculate sin
x = parentObject.x + (64)*c + 0*s;   //the 64 is the x difference so adjust as you need
y = parentObject.y + 0*c - (64)*s;
Six years later, this post is still extremely useful--thank you!
Please don't bump 6 year old topics like that, lol. Also, that codeblock is kinda bizarre. What do you think 0 * c and 0 * s are doing? 0 multiplied by anything is 0, so those two operations are literally doing nothing. If you remove them, the codeblock is exactly the same as:
GML:
x = parentObject.x + lengthdir_x(64, parentObject.image_angle);
y = parentObject.y + lengthdir_y(64, parentObject.image_angle);
Which is just doing basic trigonometry and is exactly equivalent to:
GML:
x = parentObject.x + length * dcos(angle);
y = parentObject.y - length * dsin(angle);
Replace length and angle with the appropriate values, obviously.
 

bacteriaman

Member
Please don't bump 6 year old topics like that, lol. Also, that codeblock is kinda bizarre. What do you think 0 * c and 0 * s are doing? 0 multiplied by anything is 0, so those two operations are literally doing nothing. If you remove them, the codeblock is exactly the same as:
GML:
x = parentObject.x + lengthdir_x(64, parentObject.image_angle);
y = parentObject.y + lengthdir_y(64, parentObject.image_angle);
Which is just doing basic trigonometry and is exactly equivalent to:
GML:
x = parentObject.x + length * dcos(angle);
y = parentObject.y - length * dsin(angle);
Replace length and angle with the appropriate values, obviously.
I wasn't saying the code was useful verbatim, but it definitely gave me a nudge in the right direction. In any event, I appreciate your comment as well.

Sidebar: In all my years of using technical forums, I've never experienced users more testy than this one. Thankfully there are other resources available.
 
Top