Easy way to create fixtures for complex objects?

Discussion in 'Programming' started by FeNniX, Oct 5, 2019.

  1. FeNniX

    FeNniX Member

    Joined:
    Jan 24, 2019
    Posts:
    20
    if physics object is simple shape you can define fixtures directly, but with a little bit complex objects you should write code. It takes quite a long time finding exact coordinates for each fixture point.

    If you have many complex objects is there an easy way to create fixtures for them, other then fixture_bind command?
     
  2. 2Dcube

    2Dcube Member

    Joined:
    Jun 23, 2016
    Posts:
    371
    One "easy" way to create many fixtures is to build your own editor. I made one where I just click in the room a few times and press Enter, and the dots connect into a new physics fixture. Then, you'd need to save it into a file so you can load it when needed.

    I can share some code if you're interested.
     
    ParodyKnaveBob likes this.
  3. FeNniX

    FeNniX Member

    Joined:
    Jan 24, 2019
    Posts:
    20
    That sounds interesting. I would be thankful if you could share it.
     
  4. 2Dcube

    2Dcube Member

    Joined:
    Jun 23, 2016
    Posts:
    371
    Ok here is the code to create physics fixtures with the mouse. It's quite a bit but I'll try to explain.

    We have 2 objects, objController which handles the making of the fixtures and objFixture of which 1 is used for each physics instance.
    objFixture has no code, but I could add some to draw its shape if you're interested.

    objController Create event:
    Code:
    polygon_points = ds_list_create(); // this list will be used to hold the points of a polygon (x and y's) and also to draw it on screen as you're making one.
    To make a polygon you hold down Control key and click a few times, and then when you release it turns into an instance with physics fixture.
    Please note the polygon should be clockwise and convex.

    objController Step event:
    Code:
    // when we press Control, first clear the list so we start with an empty one each time
    if keyboard_check_pressed(vk_control)
        {
            ds_list_clear(polygon_points);
        }
    
    // while we are pressing Control, we add points to the list each time we click somewhere
        if keyboard_check(vk_control)
        {
            if mouse_check_button_pressed(mb_left)
            {
                ds_list_add(polygon_points,mouse_x,mouse_y);
            }
        }
    
    // now the hard part. When Control key is released, we turn it into a physics fixture.
        if keyboard_check_released(vk_control)
        {
            if ds_list_size(polygon_points) >= 6 // we need add least 3 points (3 x + 3 y) which is a triangle
            {
                // check if in correct order (clockwise)
                var sum = 0;
                for(var i=0; i<ds_list_size(polygon_points)-3; i+=2)
                {
                    sum +=
                        ((polygon_points[| i+2]) - (polygon_points[| i])) *
                        ((polygon_points[| i+3]) + (polygon_points[| i+1]));
                }
                sum += ((polygon_points[| 0]) - (polygon_points[| ds_list_size(polygon_points)-2])) *
                       ((polygon_points[| 1]) + (polygon_points[| ds_list_size(polygon_points)-1]));
                if sum >= 0
                {
                    show_message("not clockwise");
                }
                else
                {
                    // check if concave (convex is good)
                    var convex = true;
                    for(var i=0; i<ds_list_size(polygon_points)-1; i+=2)
                    {
                        x1 = polygon_points[| i];
                        y1 = polygon_points[| i+1];
             
                        for(var k=0; k<ds_list_size(polygon_points)-1; k+=2)
                        {
                            if i != k
                            {
                                x2 = polygon_points[| k];
                                y2 = polygon_points[| k+1];
                     
                                var xm,ym;
                                xm = (x1 + x2) / 2;
                                ym = (y1 + y2) / 2;
                     
                                if !point_in_polygon(xm - 2,ym - 2,polygon_points)
                                && !point_in_polygon(xm + 2,ym - 2,polygon_points)
                                && !point_in_polygon(xm - 2,ym + 2,polygon_points)
                                && !point_in_polygon(xm + 2,ym + 2,polygon_points)
                                {
                                    convex = false;
                                }
                            }
                        }
                    }
         
                    if !convex
                    {
                        show_message("concave!");
                    }
                    else
                    {
                       
    // OK! we're clockwise and convex so good to go.
    
                        // here we find the smallest x and y points to use as origin for the fixture
                        var minx = room_width;
                        var miny = room_height;
                        for(var i=0; i<ds_list_size(polygon_points)-1; i+=2)
                        {
                            minx = min(minx,polygon_points[| i]);
                            miny = min(miny,polygon_points[| i+1]);
                        }
         
                        // and then we subtract the smallest point from all points (so the smallest point will become 0,0)
                        for(var i=0; i<ds_list_size(polygon_points)-1; i+=2)
                        {
                            polygon_points[| i] -= minx;
                            polygon_points[| i+1] -= miny;
                        }
         
                        // now we use this list to make the fixture with the following script (see below code)
                        fixture_create(polygon_points,minx,miny);
                    }
                }
            }
            ds_list_clear(polygon_points);
        }
    
    fixture_create() script:
    Code:
    var list = argument0;
    var inst = instance_create_depth(argument1,argument2,0,objFixture);
    
    /*
         basically we just take the points from the list and add each to the fixture
    */
    
    var fix = physics_fixture_create();
    physics_fixture_set_polygon_shape(fix); // tell the fixture we're gonna use a polygon shape for it
    
    for(var i=0; i<ds_list_size(list)-1; i+=2)
    {
      physics_fixture_add_point(fix, list[| i], list[| i+1]); // add each x,y pair
    }
    physics_fixture_set_density(fix,0); // set density to 0 so the fixture isn't affected by gravity (unless you want it to)
    physics_fixture_bind(fix,inst); // and we end with "bind" and it's done!
    
    physics_fixture_delete(fix); // fixture is not needed anymore so we can delete it (free up some memory)
    You also need "point_in_polygon script", which you can get here: https://www.gmlscripts.com/script/point_in_polygon




    Also, so you can see what's happening as you're making a new shape, we draw it on the screen with the below code.

    objController Draw event:
    Code:
    draw_set_color(c_orange);
        if ds_list_size(polygon_points) > 0
        {
            for(var i=0; i<ds_list_size(polygon_points)-3; i+=2)
            {
                draw_circle(polygon_points[| i],polygon_points[| i+1],3,false);
                draw_line_width(polygon_points[| i],polygon_points[| i+1],polygon_points[| i+2],polygon_points[| i+3],2);
            }
            draw_circle(polygon_points[| i],polygon_points[| i+1],3,false);
        }
    
    --------------------------

    Let me know if there is a problem or something you want clarified.
    This doesn't include any code yet to save/load but it can be done by just using the polygon_points list and saving it as a json file, I can give some pointers if you'd like.
    Also, you can draw the shapes using vertexes which is a bit complicated. It depends how you want to draw your shapes.

    For now, you could add the following to the objController Draw event so you can see the fixtures:
    Code:
    physics_world_draw_debug(phy_debug_render_shapes);
     
    Last edited: Oct 9, 2019
    FeNniX, Nocturne and ParodyKnaveBob like this.
  5. FeNniX

    FeNniX Member

    Joined:
    Jan 24, 2019
    Posts:
    20
    Too late response from me but still... Thanks for sharing the code. In the end I didn't used it but it gave me an idea. Since you are using mouse to create fixture points, I did the same but with the help of 3rd party program. I downloaded Autohotkey and created simple script. In Fixture editor I click different places where I want the fixture points to be and then completed code gets copied into clipboard. Only thing left is to paste code in create event.
     
    2Dcube likes this.
  6. 2Dcube

    2Dcube Member

    Joined:
    Jun 23, 2016
    Posts:
    371
    That is actually a pretty novel idea. I might use that in the future!
     

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