YoYoGames / GameMaker-Bugs

Public tracking for GameMaker bugs
26 stars 8 forks source link

Access physics fixture created by "Uses physics" checkbox #6067

Open old-rob opened 5 months ago

old-rob commented 5 months ago

Is your feature request related to a problem?

I would like to be able to access default physics fixtures from code. It's frustrating to use the built in gamemaker tools meant to make things easier and faster, and then run into problems where using the friendly UI makes it not possible to access all features. Currently I have a character that changes shape and uses physics, but there's no way to change the coordinates of the collision box on this default fixture

Describe the solution you'd like

If anything were possible, I would like there to be a function to update the collision shape of a physics object at runtime. The documentation says: "Modifying Bound Fixtures You can also set certain properties of the fixture after it has been bound to an instance. When binding the "base" fixture, you can choose to store the unique index for the bound physical properties in a variable. This can then be used in the following functions to change certain properties, or to get the current values for them" And you have access to physics_set_density I would like a physics_set_box_shape function that works the same way

If that isn't possible, I know there is already a physics_fixture_set_box_shape function, but it requires the fixture id. I would be delighted if there were an instance variable for the current bound fixture, that way I could just use that to unbind the default fixture, make a new one, and bind that.

Describe alternatives you've considered

Alternatives I've considered: Most of the forums talk about just doing it all from code. Not checking "Uses Physics" apparently doesn't bind a fixture to the object (although that isn't said anywhere in the IDE from what I can tell), so using code to create one fixture for each shape and then binding and removing them as necessary. This proved to be difficult and frustrating.

Another alternative would be to use multiple instances, one with each collision shape. I decided to go with this one. It's very simple and easy to understand for me, but I don't like splitting my state management into different objects ugh. Also, I ran into a lot of issues where the code seems to do different things than the room editor? Stretching a physics object scales the fixture, but I can't for the life of me figure out a way to create a stretched object from code. Changing the image_xscale and image_yscale leave the fixture the same size. Is the only way to scale an object in the room editor? That's also extremely frustrating.

Additional context

No response

Limekys commented 5 months ago

I didn't quite understand the problem, but maybe one of my tips will help. For example, if you want to control the physical model of an object, one of my solutions was to set the object to "convex shape" in the IDE, but do not specify any point, i.e. leave it empty. And already through the code create your own shape and specify the necessary properties to it. And one more tip on stretching the form not in the editor. I needed to make it so that the stretched shape had a small indentation, so that the physical model was smaller than the sprite. By default, the physical model is stretched if the object is stretched in the room editor, but this only works correctly when the physical model is set at the edges of the entire object. And if you set the physical model of the object slightly smaller than the sprite, then when stretching the indentation from the model to the edge of the sprite will become the more the model is stretched. This did not suit me and to fix it I used the first way that I described above to remove the default physical model, and already through the code to create the correct one with the set indentation with the help of this functions, where _offset is the set indentation in pixels from the model to the edge of the sprite. For a rectangular object:

function CreateRectangleFixture(_offset, _friction = 1, _restitution = 0.1) {
    var _half_w = sprite_width / 2 - _offset * image_xscale;
    var _half_h = sprite_height / 2 - _offset * image_yscale;

    var _1_x = lengthdir_x(_half_w, 0)           + lengthdir_x(_half_h, 0           + 90);
    var _1_y = lengthdir_y(_half_w, 0)           + lengthdir_y(_half_h, 0           + 90);
    var _2_x = lengthdir_x(_half_h, 0 - 90)      + lengthdir_x(_half_w, 0 - 90      + 90);
    var _2_y = lengthdir_y(_half_h, 0 - 90)      + lengthdir_y(_half_w, 0 - 90      + 90);
    var _3_x = lengthdir_x(_half_w, 0 - 180)     + lengthdir_x(_half_h, 0 - 180     + 90);
    var _3_y = lengthdir_y(_half_w, 0 - 180)     + lengthdir_y(_half_h, 0 - 180     + 90);
    var _4_x = lengthdir_x(_half_h, 0 - 270)     + lengthdir_x(_half_w, 0 - 270     + 90);
    var _4_y = lengthdir_y(_half_h, 0 - 270)     + lengthdir_y(_half_w, 0 - 270     + 90);

    var _fix = physics_fixture_create();
    physics_fixture_set_friction(_fix, _friction);
    physics_fixture_set_restitution(_fix, _restitution);
    physics_fixture_set_polygon_shape(_fix);
    if sign(image_xscale) == sign(image_yscale) {
        physics_fixture_add_point(_fix, _1_x, _1_y);
        physics_fixture_add_point(_fix, _2_x, _2_y);
        physics_fixture_add_point(_fix, _3_x, _3_y);
        physics_fixture_add_point(_fix, _4_x, _4_y);
    } else {
        physics_fixture_add_point(_fix, _4_x, _4_y);
        physics_fixture_add_point(_fix, _3_x, _3_y);
        physics_fixture_add_point(_fix, _2_x, _2_y);
        physics_fixture_add_point(_fix, _1_x, _1_y);
    }
    physics_fixture_bind(_fix, self);
    physics_fixture_delete(_fix);
}

For triangular objects:

function CreateTriangleFixture(_offset, _friction = 1, _restitution = 0.1) {
    var _half_w = sprite_width / 2 - _offset * image_xscale;
    var _half_h = sprite_height / 2 - _offset * image_yscale;

    var _2_x = lengthdir_x(_half_h, 0 - 90)      + lengthdir_x(_half_w, 0 - 90      + 90);
    var _2_y = lengthdir_y(_half_h, 0 - 90)      + lengthdir_y(_half_w, 0 - 90      + 90);
    var _3_x = lengthdir_x(_half_w, 0 - 180)     + lengthdir_x(_half_h, 0 - 180     + 90);
    var _3_y = lengthdir_y(_half_w, 0 - 180)     + lengthdir_y(_half_h, 0 - 180     + 90);
    var _4_x = lengthdir_x(_half_h, 0 - 270)     + lengthdir_x(_half_w, 0 - 270     + 90);
    var _4_y = lengthdir_y(_half_h, 0 - 270)     + lengthdir_y(_half_w, 0 - 270     + 90);

    var _fix = physics_fixture_create();
    physics_fixture_set_friction(_fix, _friction);
    physics_fixture_set_restitution(_fix, _restitution);
    physics_fixture_set_polygon_shape(_fix);
    if sign(image_xscale) == sign(image_yscale) {
        physics_fixture_add_point(_fix, _2_x, _2_y);
        physics_fixture_add_point(_fix, _3_x, _3_y);
        physics_fixture_add_point(_fix, _4_x, _4_y);
    } else {
        physics_fixture_add_point(_fix, _4_x, _4_y);
        physics_fixture_add_point(_fix, _3_x, _3_y);
        physics_fixture_add_point(_fix, _2_x, _2_y);
    }
    physics_fixture_bind(_fix, self);
    physics_fixture_delete(_fix);
}

And for round objects:

function CreateCircleFixture(_offset, _friction = 1, _restitution = 0.1) {
    var _half_w = sprite_width / 2 - _offset * image_xscale;
    var _fix = physics_fixture_create();
    physics_fixture_set_friction(_fix, _friction);
    physics_fixture_set_restitution(_fix, _restitution);
    physics_fixture_set_circle_shape(_fix, _half_w);
    physics_fixture_bind(_fix, self);
    physics_fixture_delete(_fix);
}

I didn't make such functions for the other forms, as I only needed to make these simple forms.

old-rob commented 5 months ago

Thank you so much for the code snippets and the tips! I finally got around to trying them out. I'm still not sure how to fix the problem though. I will try to explain it again.

If I have a barrel that tips onto its side and becomes round, to roll down a hill for instance, there is no way to swap out the fixture. I can change the sprite, but if I call one of these create fixture functions again then it will simply have a rectangle fixture AND a round fixture. The only way I've found to get what I'm looking for is to make two objects, one of each shape, and swap them out when the state changes.

If there is any other way to change the collision group, shape, or other properties of a bound physics fixture I would be very interested in that.

Limekys commented 5 months ago

Yes we can't change the collision group on the go, I hope this will be fixed. And in general I would like to see a full-fledged update of the Box2D system. For example, give us the ability to use more than 7 points in the creation of physical shapes and make concave shapes.