[SOLVED] synchronizing movement of objects in a circle

Discussion in 'Advanced Programming Discussion' started by bacteriaman, Dec 28, 2019.

  1. bacteriaman

    bacteriaman Member

    Joined:
    Jun 20, 2016
    Posts:
    26
    I have a bunch of objects in a circle, like the twelve hours on a clock. The actual number of objects will vary depending on the game condition from moment to moment. Objects will be continually created and added to the circle. Likewise objects will be continually removed. The circle size will dynamically expand and retract so the current number of objects are always evenly spaced apart without touching each other.

    When pressing the mouse pointer on one object and dragging, the object will follow the mouse in a circular pattern using lengthdir_x and lengthdir_y to maintain a consistent distance from the center coordinates.

    I need a method to synchronize the rotation all of the other objects in the circle. I have previously accomplished a similar requirement by using a parent object to adjust the relative angle of each child object. However in this case all of the objects are peers and none are permanent.

    After giving this challenge some thought, one possible approach is to create an invisible "master" object with a circular sprite large enough to encompass the maximum number of "slave" objects. So when dragging a slave object, you would actually be dragging the master object and all of the slave object angles would be adjusted accordingly.

    Question: Is this a sound and reasonable approach or is there a better and simpler way to go about it?

    All comments/suggestions appreciated.
     
  2. bacteriaman

    bacteriaman Member

    Joined:
    Jun 20, 2016
    Posts:
    26
    I've made some progress since my original post.

    It seems the aforementioned master/slave approach is unnecessary. The answer (at least in part) is to assign a 360 degree offset value to each instance. So whenever the angle of one instance is changed, all the other instances rotate relative to their offset value. The next step is to make the immediate angle change smoother and less jarring.

    To be continued...
     
  3. IndianaBones

    IndianaBones Member

    Joined:
    Jul 5, 2016
    Posts:
    2,353
    Off the top of my head, if you haven't tried this already, I would maintain both a current_angle_offset and a target_angle_offset for all instances.

    current_angle_offset is obviously the actual current angle the instance is at.
    target is where it wants to be.

    Each step, each instance would lerp towards the target_angle_offset.

    When an instance is removed or added, the target_angle_offset would change quite steeply as the target_angle_offset would be recalculated, but it would be smoothed out as the instances would lerp towards it gradually.
     
  4. bacteriaman

    bacteriaman Member

    Joined:
    Jun 20, 2016
    Posts:
    26
    @IndianaBones,

    Thanks for your comment and suggestion. I think we're on the same wavelength. :)

    I got the synchronization working. The STEP event of my parent object contains:

    Code:
    x = center_x + lengthdir_x(length, current_angle);
    y = center_y + lengthdir_y(length, current_angle);
    
    if (!grabbed) {
        if (mouse_check_button_pressed(mb_left)) {
            if (position_meeting(mouse_x, mouse_y, id)) {
                grabbed = true;
          }
        }
    }
    else {
        previous_angle = current_angle;
        current_angle = point_direction(center_x, center_y, mouse_x, mouse_y);
    
        if (current_angle != previous_angle) {
            // Coordinates of instance following pointer have changed.
            // Calculate different between previous and current angle.
            target_angle = angle_difference(current_angle, previous_angle);
      
            with (obj_camper) {
                if (id != other.id) {
                    // Update other instances with the angle difference.
                    current_angle += other.target_angle;
                }
            }
        }
    
        if (mouse_check_button_released(mb_left)) {
            with (obj_camper) {
                // Snap each instance to lowest 30 degree angle.
                current_angle = 30 * floor(current_angle / 30);
            }
            grabbed = false;
        }
    }
    
    // Rotate sprite so it's always facing inwards.
    image_angle = point_direction(x, y, center_x, center_y);
    
    The "grabbed" instance follows the pointer and the other instances are updated with the angle difference.

    When each instance is created (in the controller object), a default current_angle property value is assigned:

    Code:
    center_x = room_width / 2;
    center_y = room_height / 2;
    
    for (var i = 0; i < 12; ++i) {
        var camper = instance_create_layer(center_x, center_y, "Camper", obj_camper);
        camper.current_angle = i * 30;
    }
    
    This seems good for starters, but please let me know if you have any suggestions for further improvement.

    I'm going to experiment with the idea of the other instances gradually moving towards the target_angle, but that behavior might not match the style and pace of the game.
     
    Last edited: Dec 28, 2019

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice