GML Movement based on rotation or another instance's axis?

XirmiX

Member
So, currently I have set up for my game pretty complex spawn points. One of these complex parts is that there are two doors that open and close. The doors are set up to move in a certain direction from their current position when a player spawns in that spawn point:

Step event for one of the doors (most of this code isn't too relevant; the key areas of interest are where phy_position_y is being changed)
Code:
if (parent_spawn.spawnable == false)
{
    if(open_door && round(phy_position_y) != (parent_spawn.y-90))
    {
        phy_position_y --;
        show_debug_message("Door 1 physics 'Y' position: " + string(round(phy_position_y)));
        show_debug_message("Spawnpoint 'Y' position: " + string(parent_spawn.y-90));
    }
    else if(open_door && round(phy_position_y) == (parent_spawn.y-90))
    {
        open_door = false;
    }
    else if(open_door == false && round(phy_position_y) != parent_spawn.y)
    {
        if (parent_spawn.free_spawn == true)
        {
            phy_position_y ++;
        }
    }
    else if(open_door == false && round(phy_position_y) == parent_spawn.y)
    {
        if (parent_spawn.spawnable != true)
        {
            parent_spawn.spawnable = true;
        }
    }
}

The problem, however, is that when the spawn point is rotated, the doors don't change the direction in which they move; say if you rotated the spawn point by 90 degrees, the doors should move one to the left and the other to the right to open up, but instead they move one upwards and one downwards as if the spawn point wasn't rotated, making a weird, unintended type of movement.

What should happen:
upload_2017-8-27_22-52-46.png

What happens:
upload_2017-8-27_22-52-51.png

My question is, how can I change it so that the movement changes based on the rotation of its parent spawn point (the closest spawn point to it) as a whole and/or, based on the parent spawn point's local axis of sorts instead of the global axis. Though, I think this is essentially the same thing in this scenario.
 

CMAllen

Member
You're going to have to adjust the direction of your phys_position_x and phys_position_y values based on the parent object's phys_rotation. You can still use the point_direction() and point_distance() functions, along with lengthdir_x() and lengthdir_y() to calculate your transform values, just note that point_direction() is going to return a value that is inverse from phys_rotation.
 

XirmiX

Member
You're going to have to adjust the direction of your phys_position_x and phys_position_y values based on the parent object's phys_rotation. You can still use the point_direction() and point_distance() functions, along with lengthdir_x() and lengthdir_y() to calculate your transform values, just note that point_direction() is going to return a value that is inverse from phys_rotation.
I understood none of that, you'll need to give me some examples. And the parent spawn point isn't a physics object as it has no fixtures, so it has no phy_rotation, only direction and image_angle.
 

CMAllen

Member
So how are you rotating your door fixtures? There needs to be some way you're changing their orientation, and whatever method you use, the orientation data needs to be accessible to the door objects. In either case:
Code:
open_direction = -1 * parent.image_angle //getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_y+=openspeed_y; //Adding distances to current location.
phy_position_x+=openspeed_x;
Something roughly like that should work. There is one assumption being made -- the parent object's rotation is parallel to the direction the doors open (instead of perpendicular). Otherwise you'll have to subtract 90 from open_direction to orient the motion of the doors to the parent object's rotation.
 

XirmiX

Member
So how are you rotating your door fixtures? There needs to be some way you're changing their orientation, and whatever method you use, the orientation data needs to be accessible to the door objects. In either case:
Code:
open_direction = -1 * parent.image_angle //getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_y+=openspeed_y; //Adding distances to current location.
phy_position_x+=openspeed_x;
Something roughly like that should work. There is one assumption being made -- the parent object's rotation is parallel to the direction the doors open (instead of perpendicular). Otherwise you'll have to subtract 90 from open_direction to orient the motion of the doors to the parent object's rotation.
I still don't understand how this is supposed to do anything. I read about the lengthdir stuff and while I kind of get the idea of what it's supposed to do, I'm still confused. Could you explain what lengthdir does exactly and how it does it, because the manual doesn't explain it to me that well. What is it supposed to do and how does it do it? And the above code doesn't do me anything, tried out three things, in fact, and in all instances the doors kept going up and down instead of right and left respectively.

The doors rotate themselves after being created. And they are rotated by image_angle, direction AND phy_rotation. I have set it all up so that the doors have the same center point as the parent spawn point object. They all have the same sized textures, just that for doors, most of the sptie area is empty so that it could have that same center point, while still being the right size in terms of display.
 

CMAllen

Member
Both lengthdir functions return a value of how far along a given axis a distance is based on the angle. If you give it a direction that is exactly parallel to the axis, then it returns the distance originally given. For example
Code:
lengthdir_x(10, 0);
will return 10 (and an angle of 180 would return -10), because the direction is exactly parallel to the x axis that lengthdir_x() is measuring along. Conversely, if you pass in an angle that is exactly perpendicular to the axis, the return is always 0. The exact math behind it would be better left explained by someone far more versed in that subject (I'd likely remember or explain it incorrectly). These functions can be used to find a given point on a transformed sprite (say, where a hand is so you can draw a variable gun sprite there).

In the code previously given, the first line gets the direction the doors are opening in based on their parent's image_angle. It then uses that direction to calculate how far along either axis the necessary movement amount will be for a given distance and direction. And finally it adjusts the position of the door. In your original code, you used non-transformed positional data to limit the distance the doors moved. That obviously would not work when the doors and parent have been rotated, so you'd use point_distance() instead (adjusting your comparison values to create the same effect, since the distance is measured along both axis instead of just one).
 

XirmiX

Member
@CMAllen I think I'm starting to understand; you choose a length of either Y or X axis and then determine the point of interest through defining an angle. Okay, though would I need to have the lengthdir x and y values as 0, since when the doors are shut, and they start out like that, they will have the same x and y coordinates as their parent spawn point?

And you mentioned me using point_distance(). How would I use this exactly? Say, for instance here, where I want one of the doors to move by 1 every frame during this condition:
Code:
   if(open_door && round(phy_position_y) != (parent_spawn.y-90))
   {
       phy_position_y --;
       show_debug_message("Door 1 physics 'Y' position: " + string(round(phy_position_y)));
       show_debug_message("Spawnpoint 'Y' position: " + string(parent_spawn.y-90));
   }
How would I work with this exactly? Knowing of course that phy_position_y --; is what currently makes the door open up.
 

CMAllen

Member
point_distance() would be how you'd clamp the distance that the doors open, since you can't use a specific axis to check against, as that wouldn't take into account the rotation of the parent and doors. The point_distance() function returns the absolute distance, in pixels, between two points. Assuming I'm understanding your code correctly, you cap the distance the doors move at 90 pixels from the parent. So instead, you'd do something like this:
Code:
if(open_door && point_distance(x,y,parent.x,parent.y) != 90)
{
    //door moving code here
}
Note: since point_distance() has no direcitonal component to it, the function cannot return a negative value.
 

XirmiX

Member
@CMAllen well, I think it might be pointing in the right direction now... but this hasn't given me any change; phy_position_y does the exact same thing as before. So, I thought that perhaps phy_speed could do it. The fact is, it could, but this is physics and for some reason speed that isn't a physics attribute can be defined, but phy_speed is a read-only variable. So how the hell am I supposed to make it move as a physics object in the direction it has been specified to move without declaring any xs and ys? Idk, may be it already is with just the phy_position_y and I just need to change some other attributes, but I think that's unlikely.
 

Jezla

Member
You move a physics object by applying a force or impulse to it. However, for what you want to do here, I'd suggest you look into using a prismatic joint for each door. It's well suited for this case, as it only allows movement on one axis, and can be motorized. The movement axis of the joint is defined relative to the fixture, so you can set the instance's orientation however you want.
 

XirmiX

Member
@Jezla this seems ridiculous. If phy_speed wasn't just a read-only variable, this mess wouldn't be something for me to bother with, because anchoring isn't particularly necessary for me, just the movement and stopping at the right place, which is something I already made an algorithm for. So dumb. And, of course, this just make it hell of a harder task to get things working as intended. Here's what I've written and the door ends up not moving at all, great:

Left door's create event
Code:
door_joint = physics_joint_prismatic_create(wall_main, id, wall_main.x, wall_main.y, 0, 0, 0, 0, 1, 1, 0, 0, 0);

Left door's step event

Code:
if (parent_spawn.spawnable == false)
{
    if(open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 90))//round(phy_position_y) != (parent_spawn.y-90))
    {
        /*
        if (speed != -1)
        {
            speed --;
        }*/
        //show_debug_message("Door 1 physics 'Y' position: " + string(round(phy_position_y)));
        //show_debug_message("Spawnpoint 'Y' position: " + string(parent_spawn.y-90));
        physics_joint_set_value(door_joint, phy_joint_motor_speed, +1);
        physics_joint_enable_motor(door_joint, true);
    }
    else if(open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 90))//round(phy_position_y) == (parent_spawn.y-90))
    {
        /*
        if (speed != 0)
        {
            speed ++;
        }*/
        //point_distance(x, y, parent_spawn.x, parent_spawn.y);
        physics_joint_set_value(door_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(door_joint, false);
        open_door = false;
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 0))//round(phy_position_y) != parent_spawn.y)
    {
        if (parent_spawn.free_spawn == true)
        {
            /*
            if (speed != -1)
            {
                speed ++;
            }*/
            physics_joint_set_value(door_joint, phy_joint_motor_speed, -1);
            physics_joint_enable_motor(door_joint, true);
        }
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 0))//round(phy_position_y) == parent_spawn.y)
    {
        /*
        if (speed != 0)
        {
            speed --;
        }*/
        physics_joint_set_value(door_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(door_joint, false);
        if (parent_spawn.spawnable != true)
        {
            parent_spawn.spawnable = true;
        }
    }
}
May be I misunderstood the prismatic joint system completely, but this is how it made sense to me, but my bet is that something I've written about the logic is incorrect. Not every piece of data about this was fully clear, like the difference between max_motor_force and motor_speed.
 

Jezla

Member
It's not ridiculous, and if you're going to use physics for a project, your life will be much easier if you learn to use the features of the system. I created a simple example of a sliding door with two objects and six lines of code.

Code:
//Anchor object create event
//Create doors
door_left = instance_create(x-32, y+48, oDoor);
door_right = instance_create(x+32, y+48, oDoor);

//Create prismatic joints
left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, -1, 0, 0, 64, true, 10, 5, false, false);
right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 10, 5, false, false);

//Anchor object keyboard space press event
physics_joint_enable_motor(left_joint, true);
physics_joint_enable_motor(right_joint, true);
Both objects are physics objects.

You'll need to do a little more work to account for the varying orientation of the anchor object.
 

XirmiX

Member
It's not ridiculous, and if you're going to use physics for a project, your life will be much easier if you learn to use the features of the system. I created a simple example of a sliding door with two objects and six lines of code.

Code:
//Anchor object create event
//Create doors
door_left = instance_create(x-32, y+48, oDoor);
door_right = instance_create(x+32, y+48, oDoor);

//Create prismatic joints
left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, -1, 0, 0, 64, true, 10, 5, false, false);
right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 10, 5, false, false);

//Anchor object keyboard space press event
physics_joint_enable_motor(left_joint, true);
physics_joint_enable_motor(right_joint, true);
Both objects are physics objects.

You'll need to do a little more work to account for the varying orientation of the anchor object.
Well, that doesn't help me at all. And do I have to have the code be in a way where the joint is set within the object that doesn't move and instead holds onto the anchor? Why is the second object even needed, I don't get it? Well, may be if you want two objects, I guess, but for me it creates some problems...

I'll need to do a little more work? What kind of work? Something to do with directions? Can you please explain, this is not helping. Perhaps exaplain, if you understand completely, what each of the parameters are actually supposed to do and be for within the "physics_joint_prismatic_create" because the manual didn't help me enough to understand it well enough to be able to use it well without misunderstanding something, like it always does *cough*ds_maps*cough*.
 

Jezla

Member
Firstly, did you load my project example and run it to see how this works, and look at the code? If you haven't, I recommend you do. Since you want an explanation, I'll take you through it.

First: Two objects are required to use a joint, because that's what you are joining: one object to another. The code defining the joint does not have to be in either object; it can be in a third object. However, I find it's easiest for me to define and control the joint from within the stationary object's code.

Next, I'll take you through the code. The objects in my example are an anchor object with a 128x128 sprite, and a door object with a 64x32 sprite. Both sprite origins are centered.

Anchor object create event:

Code:
//Create doors
door_left = instance_create(x-32, y+48, oDoor);
door_right = instance_create(x+32, y+48, oDoor);
Here all I'm doing is creating two instances of the door object and assigning the ids of these instances to variables so that I can use them later. I want the doors to line up with the bottom of the anchor and meet in the center, so I've specified the locations accordingly. Next:

Code:
//Create prismatic joints
left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, -1, 0, 0, 64, true, 10, 5, false, false);
I create a prismatic joint between the anchor and the left door instance. I define the movement axis as horizontal left with a lower limit of zero and an upper limit of 64. I specify that the movement of the joint is limited, and set the maximum motor force at 10 and the motor speed to 5. At this time the motor is disabled and the objects are not allowed to collide. Here's a breakdown of what all the parameters for the function are:

The first two parameters are the two instances that you want to joint. The first instance is the stationary one, the second is the mobile one.

The next two parameters are the x and y position in the room of the anchor point. The anchor point is essentially where the joint is located and acts as a base point for the movement of the joint.

The next two parameters define the axis along which movement is permitted. This is done by defining a vector, similar to how you define the gravity direction in the physics world. First is the horizontal component (called w_axis_x in the manual), then the vertical component (w_axis_y in the manual). The actual values don't matter so much as their relation to each other. A positive w_axis_x value indicates horizontal right, negative indicates left. Likewise, a positive w-axis_y value indicates down, negative indicates left. In my example the w_axis_x is -1, the w_axis_y is 0, which means the left joint can only move horizontally to the left of the anchor point. You can define a more complex axis, but you'd have to calculate it (more on that below).

The next two parameters are the upper and lower trans limits, which simply specify the range which the moving instance can move along the axis. In my example, the left door can move from the anchor point to 64 pixels away from the anchor point.

The next parameter is whether to limit the movement of the joint or not. If set to true, the instance will be constrained by the upper and lower limits specified in the previous two parameters. If false, the instance will continue moving along the axis until it's made to stop by an outside force or command.

The next two parameters define the motor characteristics. First is the maximum force that the motor will apply to the instance to get it to move, the second is the maximum speed at which the instance will move.

The next parameter indicates whether the motor is active (true) or not (false).

The last parameter indicates if the two joined instances can collide with each other or not. If true, then they will collide if you specify a collision event; if false, they will never collide at all.

Now, you can see how I specified the parameters for the right joint:

Code:
right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 10, 5, false, false);
See how it's different, so that the right door will move right?

All that remains now is some way to activate the motors and cause the door to open. In my example I press the space bar, but you could easily do it by using an alarm event or changing a variable.

Code:
///Activate the motor
physics_joint_enable_motor(left_joint, true);
physics_joint_enable_motor(right_joint, true);
I suggested this method because from the diagram you posted above, it looks like you have a holding cell with two doors inside which your player's vehicle spawns. The cell doors open allowing the player to exit the cell and participate in the game. Is this correct? In that case, let the cell be the anchor object and control the doors by joining them with it.

Now, what I mean by doing extra work: If you want the anchor object to be oriented directly left, right, up, or down, then specifying the axis vector is easy (-1,0 is left; 0,1 is right; 0,-1 is up, 0,1 is down). Even 45 degree angle orientation is not hard (1,1 moves right and down; 1,-1 moves right and up; etc.). If the anchor object is at an odd angle however, (for instance 25 degrees) you'll have to calculate the values that the horizontal and vertical vector components should be to make the axis oriented properly. That's what I mean by extra work; it will take some more advanced math. I don't know trigonometry, so I can't help you with those calculations, but if you put time into learning how the lengthdir_ functions work, they should help you, as those are trigonometric functions.

Sorry this is a long post, but I wanted to give you a detailed explanation and break down the process for you. I hope it helps. There's a lot here, but if you take your time and focus on understanding each component, you're sure to grasp it. Just don't rush ahead with plugging code into your project and then getting upset because it doesn't work. Take time to think about how your existing system is structured and how it can be modified or re-done to incorporate this solution, should you choose to adopt it.
 
Last edited:

XirmiX

Member
@Jezla okay, so, I guess I understood pretty much everything correctly. Unfortunately, my code doesn't work for some reason. I have changed some things around to make the door execute the code. This is how I have set things up, but when pressing the spacebar, nothing moves. Why? The instances have (both the "spawn" and the door) fixtures and sprite sizes that of 32 x 32 and the spawn instance is placed atop the door instance.

Spawn instance Create event
Code:
fixture_spawnpoint = physics_fixture_create();

physics_fixture_set_polygon_shape(fixture_spawnpoint);
physics_fixture_add_point(fixture_spawnpoint, -16, -16);
physics_fixture_add_point(fixture_spawnpoint, 16, -16);
physics_fixture_add_point(fixture_spawnpoint, 16, 16);
physics_fixture_add_point(fixture_spawnpoint, -16, 16);

physics_fixture_set_collision_group(fixture_spawnpoint, 1);
physics_fixture_bind(fixture_spawnpoint, id);
Door (left) instance Create event
Code:
fixture_spawnpointdoor_01 = physics_fixture_create();

physics_fixture_set_polygon_shape(fixture_spawnpointdoor_01);
physics_fixture_add_point(fixture_spawnpointdoor_01, -16, -16);
physics_fixture_add_point(fixture_spawnpointdoor_01, 16, -16);
physics_fixture_add_point(fixture_spawnpointdoor_01, 16, 16);
physics_fixture_add_point(fixture_spawnpointdoor_01, -16, 16);

physics_fixture_set_collision_group(fixture_spawnpointdoor_01, 0);
physics_fixture_bind(fixture_spawnpointdoor_01, id);

instance_spawn = obj_spawn;
left_joint = physics_joint_prismatic_create(instance_spawn, id, id.x, id.y, -1, 0, 0, 64, true, 10, 1, false, false);
Door (left) instance Keyboard Spacebar event
Code:
physics_joint_enable_motor(left_joint, true);
 

Jezla

Member
Two things I see: first, your instance_spawn variable is holding an object index, when you need the id of the specific instance. Second, make sure your max motor force is enough to actually move the door. If your door has a high density, you'll need a higher max motor force value.

Also, there's no need to use id.x and id.y. If you're referring to the calling instance, just x and y will do.
 

XirmiX

Member
Two things I see: first, your instance_spawn variable is holding an object index, when you need the id of the specific instance. Second, make sure your max motor force is enough to actually move the door. If your door has a high density, you'll need a higher max motor force value.

Also, there's no need to use id.x and id.y. If you're referring to the calling instance, just x and y will do.
Well, fixed that, but still have issues. I thought it might be because, although the two instances have different collision groups, they might still be colliding with each other, as I previously had issues with this myself. I tried multiple things, even simply working with the visual fixture editor, and I think I forgot to add physics properties for the object to move. After I got default stuff, all seemed to work just fine. And, strangely in a good way, these two objects aren't colliding with each other due to being part of different collision groups. Before, I had the issue of having two parts for tanks for my game that, even though having two different collision groups, were still colliding, so putting them above one another was impossible :/

Now, my only question is, will what I have (essentially a fixed version of what I have done above) be enough to make it so that, if say, the door is rotated, it will move to the left relative to its rotation? Or will it just keep moving left regardless of its rotation? Because that's the whole point of this, otherwise I might as well do things the easy and kind of stupid way.
 

Jezla

Member
Okay, you're right, looking at your code in the previous post I can see where you defined the fixture shape, but not the properties, so I think in that case, the fixture is defined as static by default.

To answer your question, yes the code as you have it will keep the door moving relative to the rotation if you set the rotation after the joints are created. Otherwise, you may have to do some complex math to calculate the movement axis of the joint. Here's an updated example project to show you how it works. I've also added the ability to change the motor direction to close the doors, so you can see how that works as well.
 

XirmiX

Member
@Jezla emm, no, the object doesn't move, say, upwards when I change the phy_rotation for the spawn object to 90, or add 90, neither if I place the code for changing the phy_rotation in the instance code nor if I place it in the object code, right after I create the joint in create event. Tried also changing the direction, or both even and nothing; the door keeps moving to the left regardless!
 

Jezla

Member
Okay, post your current code for the spawn object and door object, particularly the create event code, and any code you have if you're creating an instance dynamically, such as with(inst) type code.
 

XirmiX

Member
@Jezla the door has default physics values as I'm not using fixture create for it and simply enabling physics. The Door's object has a sprite that has a center point on the center right (x = 32, y = 16), while the other object has it centered (x = 16, y = 16).

Door's Create event
Code:
instance_spawn = instance_nearest(x,y,obj_spawn);
left_joint = physics_joint_prismatic_create(instance_spawn, id, x, y, -1, 0, 0, 64, true, 1, 1, false, false);

direction = -90;
//phy_rotation = -90;
image_angle = -90;
Door's Keyboard Spacebar event
Code:
physics_joint_enable_motor(left_joint, true);
Other object's Create event
Code:
fixture_spawnpoint = physics_fixture_create();

physics_fixture_set_polygon_shape(fixture_spawnpoint);
physics_fixture_add_point(fixture_spawnpoint, -16, -16);
physics_fixture_add_point(fixture_spawnpoint, 16, -16);
physics_fixture_add_point(fixture_spawnpoint, 16, 16);
physics_fixture_add_point(fixture_spawnpoint, -16, 16);

physics_fixture_set_collision_group(fixture_spawnpoint, 1);
physics_fixture_bind(fixture_spawnpoint, id);

direction = -90;
image_angle = -90;
Room is a physics one and gravity is 0 for both X and Y axis.
 

Jezla

Member
Firstly, you need to remember that instance variables such as direction are read-only for physics enabled objects, so setting them to a value won't affect anything. Secondly, according to the code you've posted, you're not adjusting the physics rotation of the spawn object after the joint is created. In your object door create event you'd want to put:

Code:
instance_spawn.phy_rotation = -90;
after the joint is created and remove all of the direction changes.

Secondly, I strongly suggest that you do as I show in my example and have the spawn object create the door and the joint. I suggest this because it seems to me that the door object is dependent on the spawn object as its reason for being. The spawn object requires a door and determines where the player's object spawns, so it seems logical to me that the spawn object should control the doors. This would also eliminate the need to call instance_nearest(), which in my experience can cause problems if you're not careful.

EDIT: Also, you are calling physics_draw_debug() and physics_world_draw_debug(), right? That will show you if the joints and fixtures are forming correctly. You can comment it out after you get everything working right, but you should have it enabled anytime your trying to solve a problem with fixtures or joints.
 
Last edited:

XirmiX

Member
Firstly, you need to remember that instance variables such as direction are read-only for physics enabled objects, so setting them to a value won't affect anything. Secondly, according to the code you've posted, you're not adjusting the physics rotation of the spawn object after the joint is created. In your object door create event you'd want to put:

Code:
instance_spawn.phy_rotation = -90;
after the joint is created and remove all of the direction changes.

Secondly, I strongly suggest that you do as I show in my example and have the spawn object create the door and the joint. I suggest this because it seems to me that the door object is dependent on the spawn object as its reason for being. The spawn object requires a door and determines where the player's object spawns, so it seems logical to me that the spawn object should control the doors. This would also eliminate the need to call instance_nearest(), which in my experience can cause problems if you're not careful.

EDIT: Also, you are calling physics_draw_debug() and physics_world_draw_debug(), right? That will show you if the joints and fixtures are forming correctly. You can comment it out after you get everything working right, but you should have it enabled anytime your trying to solve a problem with fixtures or joints.
Oh, okay, I just did the phy_rotation on its own and it works, thanks :) And yeap, had to change the joint to be created by the parent.

On the subject of physics_draw_debug and physics_world_draw_debug, not, I had not used them. I did just use them and I find the physics_draw_debug to be very useful, but that's only for one object, meaning I would need to manually switch between having the fixture outlines and such being drawn or not for every single object when I just want to check things. I know I can simply have a statement for all of them that check one variable and then simply set that variable to either true or false in one spot, but I would still have to do this initially for every single object with a fixture every time I create a new one. How do I achieve the exact same result as with physics_draw_debug like:

Draw event for the object you want to have fixture outlines and join lines seen for

Code:
draw_self();
draw_set_colour(c_orange);
physics_draw_debug();
[CODE]

But instead using physics_world_draw_debug instead? Because I tried various things and there doesn't seem to be anything that would help me.
 

Jezla

Member
The physics drawing debug functions are very useful for making sure your fixtures and other features of your physics world are working correctly. As you've found physics_draw_debug only works for one object, which is useful if you want to see that object's fixture. If you want to see more info about your physics world, such as all physics shapes, joints, etc. then you would need to use physics_world_draw_debug.

That function only needs to be placed in one object, and it has a parameter to tell it what features of the world to draw. You select the features to draw by storing them in a variable. If you want to render multiple features, you bitwise OR them (using the | symbol). To display all the physics shapes and joints in the world you would do this:

Code:
flags = phy_debug_render_joints | phy_debug_render_shapes;

physics_world_draw_debug(flags);
The manual entry goes into more detail how to use this function, and lists all the features that it will draw. They key is this function only needs to be placed in one object to draw for all physics objects, while physics_draw_debug is placed in one object to draw its own fixture.
 

XirmiX

Member
@Jezla I think it might be that there is no line around fixtures for physics_world_draw_debug like there is for physics_draw_debug, which sucks. Just full shapes; no outlines :(

Last thing I think I should ask about is how I should go about changing the direction that a physics joint object should move in. Right now, the doors are moving; one inside and the other doesn't do anything, but can be pushed outside. I want them to move to the left and right, so, -90 and 90 degrees from the direction (or, I guess, phy_rotation) that the parent object is facing. See, the thing I was working with before was just a test, and now I'm trying to apply the same logic for doors in my main game. This is the code you kinda gave me before to regulate the direction the doors would move in:

Code:
open_direction = (-1 * (parent_spawn.image_angle));//getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_x += openspeed_x;
phy_position_y += openspeed_y;

phy_rotation = wall_main.phy_rotation;
I tried simply having -90 or +90 at the end of first line of the code above, but that didn't really change anything. This is in an alarm event that happens 1 frame after stuff has been created and all the create events have been executed. Thoughts?
 

Jezla

Member
@Jezla I think it might be that there is no line around fixtures for physics_world_draw_debug like there is for physics_draw_debug, which sucks. Just full shapes; no outlines :(

Last thing I think I should ask about is how I should go about changing the direction that a physics joint object should move in. Right now, the doors are moving; one inside and the other doesn't do anything, but can be pushed outside. I want them to move to the left and right, so, -90 and 90 degrees from the direction (or, I guess, phy_rotation) that the parent object is facing. See, the thing I was working with before was just a test, and now I'm trying to apply the same logic for doors in my main game. This is the code you kinda gave me before to regulate the direction the doors would move in:

Code:
open_direction = (-1 * (parent_spawn.image_angle));//getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_x += openspeed_x;
phy_position_y += openspeed_y;

phy_rotation = wall_main.phy_rotation;
I tried simply having -90 or +90 at the end of first line of the code above, but that didn't really change anything. This is in an alarm event that happens 1 frame after stuff has been created and all the create events have been executed. Thoughts?

That's the code that @CMAllen gave you, not me. If you use my method of using prismatic joints for your doors, then you need to remove this code. All you would need in an alarm event would be the function to enable the motors. It sounds like you're defining each door joint identical to each other. Look at the joint definitions from my example:

Code:
left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, -1, 0, 0, 64, true, 10, 5, false, false);
right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 10, 5, false, false);
See how they're different? The w_axis_x parameter is different for each. The left joint is -1 and the right joint is 1. This ensures that the doors will move in the opposite direction from one another. If you define everything correctly, the spawn object and the joint will determine which way the doors move. You just need to define the joint correctly and orient the spawn object, the physics system will take care of the rest.
 

XirmiX

Member
@Jezla I can't change the direction that the doors move, at all, no matter what I do. I'll give you relevant code, may be you can see if I have done something stupid that prevents me from changing the direction the doors move. But the problem is that the doors keep moving forwards and backwards, instead of left and right, relative to the phy_rotation of the parent wall. If the parent wall is pointed left, doors should move up and down, but instead they move left and right, and when the parent wall is pointed downward, the doors move upwards and downwards as well. They're in synch with their phy_rotation, but I need the doors to be 90 degrees from that.

Parent Wall Create Event
Code:
//image_angle = direction;
parent_spawn = instance_nearest(x,y,obj_spawnpoint);//This is the parent spawn point. Spawn point creates this parent wall, which then creates the doors. Parent spawn doesn't have any fixtures, it's just an object for spawning in players and holding everything together, so-to-speak. Its variables also determine whether the doors should be opened or closed, based on whether the player is meeting place with it or not.
alarm[0] = 1;

//Some fixture code I've removed from displaying, as it's a lot and not really relevant, but I know that the fixture placement is correct.

door_left = instance_create(x,y,obj_doorspawnpoint_1);
door_right = instance_create(x,y,obj_doorspawnpoint_2);

left_rote = phy_rotation +90;
left_dire = phy_rotation -90;

door_left.phy_rotation = left_rote;
door_left.direction = left_dire;
door_right.phy_rotation = phy_rotation;

door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 1, 0, 0, 64, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 1, 1, false, false);
Parent Wall Alarm 0 Event
Code:
var parent_image_angle = parent_spawn.image_angle;
image_angle = parent_image_angle;
direction = image_angle;
phy_rotation = -image_angle;

show_debug_message("");
show_debug_message("Parent direction: " + string(parent_image_angle));
show_debug_message("Child direction: " + string(direction));
show_debug_message("Child phy_rotation: " + string(phy_rotation));
show_debug_message("Child image_angle: " + string(image_angle));
Left Door Step Event
Code:
if (parent_spawn.spawnable == false)
{
    if (open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 90))
    {
        //show_debug_message("Door 1 physics 'Y' position: " + string(round(phy_position_y)));
        //show_debug_message("Spawnpoint 'Y' position: " + string(parent_spawn.y-90));
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 1);
        physics_joint_enable_motor(wall_main.door_left_joint, true);
    }
    else if(open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 90))
    {
        //point_distance(x, y, parent_spawn.x, parent_spawn.y);
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        open_door = false;
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 0))
    {
        if (parent_spawn.free_spawn == true)
        {
            physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, -1);
            physics_joint_enable_motor(wall_main.door_left_joint, true);
        }
    }
    else if(open_door == false && round(phy_position_y) == parent_spawn.y)
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        if (parent_spawn.spawnable != true)
        {
            parent_spawn.spawnable = true;
        }
    }
}
Left Door Alarm 0 Event
Code:
var parent_image_angle = parent_spawn.image_angle;

open_direction = (-1 * (parent_spawn.image_angle) +90);//getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_x += openspeed_x;
phy_position_y += openspeed_y;

Also, for whatever reason, with the joints system, I don't have the game responding to the else if statements at all anymore. It was working fine when I was still just changing the phy_position.
 
Last edited:

Jezla

Member
I don't have a lot of time right now to go into all that I think is incorrect, but your main problem is in these lines:

door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 1, 0, 0, 64, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 1, 1, false, false);

Specifically the parameters in red. I don't know how your parent wall is oriented when it's first created (facing up, down, left or right), but these parameters depend on the wall's initial phy_rotation. If the wall points down when it's created, the joint creation will look just like my example:

Code:
door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, -1, 0, 0, 64, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 1, 0, 0, 64, true, 1, 1, false, false);
If the wall initially points right, the joints are created like this:

Code:
door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 0, -1, 0, 64, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 0, 1, 0, 64, true, 1, 1, false, false);
I'll add more this afternoon when I get home.
 

XirmiX

Member
@Jezla oh, just to update you, I've made some progress... I can't explain much since, I don't fully understand this myself, but the doors' directions of moving are now correct and their positions are also correct, and while the left door opens up as necessary, it doesn't close up as necessary (when the player isn't touching the spawn point anymore) and the right door doesn't open up at all. The right door thing is connected to the joint code being incorrect, while the closing up code and such may be connected to the directions code within the step events of the doors.

Parent Wall Create Event
Code:
parent_spawn = instance_nearest(x,y,obj_spawnpoint);
alarm[0] = 1;

//Some fixture code I've removed from displaying

door_left = instance_create(x,y,obj_doorspawnpoint_1);
door_right = instance_create(x,y,obj_doorspawnpoint_2);

left_rote = phy_rotation +90;
left_dire = phy_rotation -90;
right_rote = phy_rotation -90;
right_dire = phy_rotation +90;

door_left.phy_rotation = phy_rotation;
door_right.phy_rotation = phy_rotation;

door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 0, -1, 0, 90, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 0, 1, 0, -90, true, 1, 1, false, false);
Parent Wall Alarm 0 Event
Code:
open_door = true;
parent_spawn = instance_nearest(x,y,obj_spawnpoint);
wall_main = instance_nearest(x,y,obj_wallspawnpoint);

fixture_spawnpointdoor_01 = physics_fixture_create();

physics_fixture_set_polygon_shape(fixture_spawnpointdoor_01);
physics_fixture_add_point(fixture_spawnpointdoor_01, 110, -100);
physics_fixture_add_point(fixture_spawnpointdoor_01, 140, -100);
physics_fixture_add_point(fixture_spawnpointdoor_01, 140, 0);
physics_fixture_add_point(fixture_spawnpointdoor_01, 110, 0);

physics_fixture_set_density(fixture_spawnpointdoor_01, 0.5);
physics_fixture_set_restitution(fixture_spawnpointdoor_01, 0);
physics_fixture_set_collision_group(fixture_spawnpointdoor_01, 0);
physics_fixture_set_linear_damping(fixture_spawnpointdoor_01, 10);
physics_fixture_set_angular_damping(fixture_spawnpointdoor_01, 0);
//friction = 0;

physics_fixture_bind(fixture_spawnpointdoor_01, id);
Left Door Step Event
Code:
var parent_image_angle = parent_spawn.image_angle;
image_angle = parent_image_angle;
direction = image_angle;
phy_rotation = -image_angle;

show_debug_message("");
show_debug_message("Parent direction: " + string(parent_image_angle));
show_debug_message("Child direction: " + string(direction));
show_debug_message("Child phy_rotation: " + string(phy_rotation));
show_debug_message("Child image_angle: " + string(image_angle));
Left Door Alarm 0 Event
Code:
if (parent_spawn.spawnable == false)
{
    if (open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 90))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 1);
        physics_joint_enable_motor(wall_main.door_left_joint, true);
    }
    else if(open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 90))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        open_door = false;
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 0))
    {
        if (parent_spawn.free_spawn == true)
        {
            physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, -1);
            physics_joint_enable_motor(wall_main.door_left_joint, true);
        }
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 0))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        if (parent_spawn.spawnable != true)
        {
            parent_spawn.spawnable = true;
        }
    }
}
 

Jezla

Member
The joint motor speed determines whether the door opens or closes. A positive motor speed moves away from the anchor point and a negative number moves toward the anchor point.

Looking at your code, here's some suggestions:

1) You're setting the parent_spawn variable in the parent wall twice, in the create event and the alarm event. It may not be causing you any problems, but it could. If you want to make sure you're always referring to the same instance, set it in the create event only. (unless your code blocks in the post are labeled incorrectly)

2) The left door not closing is probably related to your conditions for opening and closing the door, but I'm not sure what all of the variables in the door alarm event refer to, and I'm still a little unsure how your system works (I made an assumption above and you haven't really confirmed or corrected it)

Could you post a screenshot of your room, so I can see how this is supposed to work? So far I can tell you have a spawn point object, a wall object, two door objects, and a player object. Which are placed in the room using the room editor and which are created dynamically (besides the doors)?
 

XirmiX

Member
@Jezla ahh, it turns out I messed up with the ordering of some code. Taking in consideration what you've . But remember one thing; the doors should (and the left door does, the one from the perspective of looking at the doors upwards) move open as indicated with previous images.

The way they should open and shut is by having their variable "open_door" (both have one of their own) determine whether they should go to being open and stay open or go to being shut and stay shut (hence the 4 if statements). However, there is another variable "spawnable", declared in the spawn point object, which determines whether a player is touching the spawnpoint. Afterwards, I'd want to make it so that the doors don't open even if the player is touching them after they have exited the door, but that's for later. Right now I need this to be functional.

What happens right now, however, is that, when the player spawns in, the left door opens, the right doesn't move, and once the player exits the spawnpoint, neither of the doors make any sort of motion. The spawnpoint, the parent wall and the doors all have the same center point, even though having different textures (but with the same sprite sizes). Here is the code and some screenshots:

Spawn Point Create Event
Code:
spawnable = true;
spawnin = false;
free_spawn = true;
direction = image_angle;

this_wall = instance_create(x,y,obj_wallspawnpoint);
Spawn Point Step Event
Code:
if place_meeting(x, y, obj_hull)
{
    spawnable = false;
    free_spawn = false;
}
else
{
    free_spawn = true;
    if (this_wall.door_left.phy_position_x == x) && (this_wall.door_right.phy_position_x == x)
    {
        spawnable = true;
    }
}
Parent Wall Create Event
Code:
parent_spawn = instance_nearest(x,y,obj_spawnpoint);
alarm[0] = 1;

//Fixture code here

door_left = instance_create(x,y,obj_doorspawnpoint_1);
door_right = instance_create(x,y,obj_doorspawnpoint_2);

left_rote = phy_rotation +90;
left_dire = phy_rotation -90;
right_rote = phy_rotation -90;
right_dire = phy_rotation +90;

door_left.phy_rotation = phy_rotation;
door_right.phy_rotation = phy_rotation;

door_left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 0, -1, 0, 90, true, 1, 1, false, false);
door_right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 0, 1, 0, -90, true, 1, 1, false, false);
Parent Wall Alarm 0 Event
Code:
var parent_image_angle = parent_spawn.image_angle;
image_angle = parent_image_angle;
direction = image_angle;
phy_rotation = -image_angle;

//Debug messages here
Left Door Create Event
Code:
open_door = true;
parent_spawn = instance_nearest(x,y,obj_spawnpoint);
wall_main = instance_nearest(x,y,obj_wallspawnpoint);

fixture_spawnpointdoor_01 = physics_fixture_create();

physics_fixture_set_polygon_shape(fixture_spawnpointdoor_01);
physics_fixture_add_point(fixture_spawnpointdoor_01, 110, -100);
physics_fixture_add_point(fixture_spawnpointdoor_01, 140, -100);
physics_fixture_add_point(fixture_spawnpointdoor_01, 140, 0);
physics_fixture_add_point(fixture_spawnpointdoor_01, 110, 0);

physics_fixture_set_density(fixture_spawnpointdoor_01, 0.5);
physics_fixture_set_restitution(fixture_spawnpointdoor_01, 0);
physics_fixture_set_collision_group(fixture_spawnpointdoor_01, 0);
physics_fixture_set_linear_damping(fixture_spawnpointdoor_01, 10);
physics_fixture_set_angular_damping(fixture_spawnpointdoor_01, 0);

physics_fixture_bind(fixture_spawnpointdoor_01, id);
Left Door Alarm 0 Event
Code:
var parent_image_angle = parent_spawn.image_angle;

open_direction = (-1 * (parent_spawn.image_angle) +90);//getting door opening angle based on parent's orientation, converting to phys direction.
openspeed_x = lengthdir_x(1.0, open_direction); //Getting open speed amount based on open_direction.
openspeed_y = lengthdir_y(1.0, open_direction);
phy_position_x += openspeed_x;
phy_position_y += openspeed_y;
Left Door Step Event
Code:
if (parent_spawn.spawnable == false)
{
    if (open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 90))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 1);
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_anchor_2_x, 90);
        physics_joint_enable_motor(wall_main.door_left_joint, true);
    }
    else if(open_door && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 90))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_anchor_2_x, 90);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        open_door = false;
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) != 0))
    {
        if (parent_spawn.free_spawn == true)
        {
            physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, -1);
            physics_joint_set_value(wall_main.door_left_joint, phy_joint_anchor_2_x, 0);
            physics_joint_enable_motor(wall_main.door_left_joint, true);
        }
    }
    else if(open_door == false && (point_distance(x, y, parent_spawn.x, parent_spawn.y) == 0))
    {
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_motor_speed, 0);
        physics_joint_set_value(wall_main.door_left_joint, phy_joint_anchor_2_x, 0);
        physics_joint_enable_motor(wall_main.door_left_joint, false);
        if (parent_spawn.spawnable != true)
        {
            parent_spawn.spawnable = true;
        }
    }
}
Before the player spawns (example, rotation may be different if I change the instance image_angle, or rotation for instance properties):
upload_2017-9-11_13-19-42.png

After the player spawns:
upload_2017-9-11_13-27-50.png

After the player gets out:
upload_2017-9-11_13-32-16.png

Hope this helps understanding what's going on and what's supposed to happen.
 

Jezla

Member
Okay, I think I can simplify this for you a great deal, but I have a couple of questions first. Firstly, the variable "spawnable" indicates that the spawn point can spawn a player (once the player is in the spawn point, "spawnable" is set to false), if I'm reading everything correctly. Second, what does "free_spawn" indicate? I see that once the player is not in the spawn point it is set to true. Thirdly, the condition that sets "spawnable" back to true when the player leaves the spawn point is confusing to me. Are you checking that the doors have closed again? I'm talking about these lines:

Code:
if (this_wall.door_left.phy_position_x == x) && (this_wall.door_right.phy_position_x == x)
    {
        spawnable = true;
    }
Lastly, are all of your spawn points placed in the room from the room editor, and does every spawn point spawn a parent wall with doors? Or are some spawn points not used for some rooms?

I hope you're not put off by all the questions when you're wanting a solution, but as I said, I think I can help you simplify this setup greatly, but I want to make sure I understand what's happening first. Also, you haven't posted the code for the right door yet. Is it the same as the left door, or is it different?
 

XirmiX

Member
Okay, I think I can simplify this for you a great deal, but I have a couple of questions first. Firstly, the variable "spawnable" indicates that the spawn point can spawn a player (once the player is in the spawn point, "spawnable" is set to false), if I'm reading everything correctly.
Right... so the "spawnable" variable is actually supposed to become true once the doors close behind the player object...

Second, what does "free_spawn" indicate? I see that once the player is not in the spawn point it is set to true.
...as for "free_spawn" I think you can ignore that for now, that's an unfinished mechanic. Basically it's supposed to determine whether a spawn point has a player touching it or not and then further determine some things with doors (what I had previously mis-described to you about "spawnable" pretty much honestly), although I might tinker and reconsider some things with this mechanic, so, it's best left there if it's not affecting anything.

Thirdly, the condition that sets "spawnable" back to true when the player leaves the spawn point is confusing to me. Are you checking that the doors have closed again? I'm talking about these lines:

Code:
if (this_wall.door_left.phy_position_x == x) && (this_wall.door_right.phy_position_x == x)
    {
        spawnable = true;
    }
Yes, that's correct.

I hope you're not put off by all the questions when you're wanting a solution, but as I said, I think I can help you simplify this setup greatly, but I want to make sure I understand what's happening first. Also, you haven't posted the code for the right door yet. Is it the same as the left door, or is it different?
No worries, I'm grateful that I'm genuinely getting proper help here, so answering questions if possible is my responsibility for that :)
 

Jezla

Member
Okay, I'm going to try and knock together a simple copy of this system and see if I can't make it easier to deal with.

EDIT: UPDATE: I've made good progress, but unfortunately I've got to call it a night. I've got it to where I can spawn a player vehicle which causes the doors to open; when the player leaves the spawn box the doors will close, at which point another player can be spawned in the box. Tomorrow I'll work on adjusting the orientation of the spawn box.

I'll have an example project and a detailed explanation of the code for you tomorrow, but I can fairly say I did manage to simplify everything quite a bit. The bad news is you'll have to scrap your current code (at least what you've shared here).
 
Last edited:

Jezla

Member
Okay, I've managed to set up a system like you've described. I've built on my previous example file, so download it, import it, and run it to see how it operates. Now I'll take you through it:

The project has five objects:

1) A spawn point object (non-physics) 140x140 sprite
2) A door anchor object (or 'wall' object) 128x128 sprite
3) A door object 64x32 sprite
4)A player vehicle object 64x32 sprite
5) A debug object no sprite

The debug object simply displays the instructional text and allows toggling physics world debug drawing on and off, set to display shapes and joints.

Here's how it works, then I'll take you through the code. The spawn object is placed in the room and rotated using the rotation control in the room editor (the rotation is the image_angle). Each spawn object creates its own door anchor and sets the anchor's phy_rotation to match the spawn point image_angle. Each door anchor instance creates its own doors. If you press enter, a player vehicle will spawn at each door anchor, causing the doors to open, and setting the anchor to not allow another player to spawn. Once the player moves off of the door anchor, the doors will close. Once the doors are nearly closed, the anchor object is set to allow player spawning.

Here's the code:

First, I create a script to help control the doors. This is to keep our code more readable, since any time we manipulate one door, we'll also manipulate its counterpart. Here it is:

Code:
///scr_change_door_dir()
/*
    Changes the direction of the doors' movement.
*/

var rs, ls;

ls = physics_joint_get_value(left_joint, phy_joint_motor_speed);
rs = physics_joint_get_value(right_joint, phy_joint_motor_speed);

ls = -ls;
rs = -rs;

physics_joint_set_value(left_joint, phy_joint_motor_speed, ls);
physics_joint_set_value(right_joint, phy_joint_motor_speed, rs);

Now for the spawn point.

Code:
///Create my door anchor object and set its rotation

my_anchor = instance_create(x, y, oDoorAnchor);

with(my_anchor)
    {
        phy_rotation = -other.image_angle;
    }

This is all the code for the spawn point. The thing to remember is that instance variable such as image angle and direction don't work in physics objects, but they still work in non-physics objects (like the spawn point). they also increae in opposite directions, which is why the other.image_angle is negative.

Then the door anchor:

Code:
///Set Up
image_speed = 0; //don't animate

//Create my fixture - defines a basic box shape and binds it
fix = physics_fixture_create();
physics_fixture_set_box_shape(fix, 64, 64);
physics_fixture_set_density(fix, 0);
my_fix = physics_fixture_bind(fix, id);
physics_fixture_delete(fix);


//Create doors and set their rotation
door_left = instance_create(x+48, y-32, oDoor);
door_right = instance_create(x+48, y+32, oDoor);
with(door_left) phy_rotation = 90;
with(door_right) phy_rotation = 90;

//Create prismatic joints
left_joint = physics_joint_prismatic_create(id, door_left, door_left.x, door_left.y, 0, -1, 0, 64, true, 10, -5, true, false);
right_joint = physics_joint_prismatic_create(id, door_right, door_right.x, door_right.y, 0, 1, 0, 64, true, 10, -5, true, false);

//Other variables
spawn = true; //we can spawn a player object

This sets up the fixture and creates the doors that belong to this anchor, then sets "spawn" to true, allowing us to spawn a player on this instance. Notice a couple of things: first, I assigned the bound fixture to a variable. This allows us the ability to alter certain physics properties later (or remove the fixture) if we need to. I've also deleted the fixture after it is bound, to prevent memory leaks. Second, notice that the joint code is different from what we used before. This time, I've enabled the motors when the joint is created, and set the motor speed so that the doors are moving toward the anchor point of the joint (e.g. they are closing when they are created). I found that this works better because to control the doors all we need to do is change the motor speed without worrying about enabling or disabling the motor.

Code:
///Check Player

//If player sprite is in contact with our sprite,
//open doors and prevent spawning another player and
//set the door close alarm
if (physics_test_overlap(x, y, phy_rotation, oPlayer))
    {
        spawn = false;
        alarm[0] = 5;
    }  
else if (physics_joint_get_value(left_joint, phy_joint_translation) <= 10) &&
    (physics_joint_get_value(right_joint, phy_joint_translation) <= 10)
    {
        //If the doors are nearly closed, we can spawn another player
        spawn = true;
    }

//Change the sprite == This is to visually indicate that a player can spawn
if (spawn)
    {
        image_index = 1;
    }
else image_index = 0;

In the step event is where our control happens. We want to check if a player object's physics shape is overlapping ours (physics_test_overlap() is kind of like a place_meeting() function for physics objects). If true, we set disallow player spawns on this instance and set an alarm. Now, as long as the player is overlapping the anchor, the alarm is continually being set to 5, so it doesn't actually count down until the overlap no longer occurs.

Next, if there's no overlap, we want to check a property of the door joints called translation. This is how far from the anchor point the door is along it's travel axis. If both doors are within 10 units (pixels?) of closing, we allow player spawns again. Why not check if translation is 0? I tried that and if something applied force to the doors before they opened (like an overzealous player), it prevented the translation from returning to zero. It works better to allow a bit of leeway. You can check less than 10 or more than 10 if you want, it was just most convenient.

Finally, we set the sprite frame based on whether 'spawn' is true or false. This is a handy way to see if the variable is set without using debug messages.

Code:
///Change the door direction
scr_change_door_dir();

Once the alarm finally counts down, we simply call our script to change the direction of the anchor's doors.

The door anchor object also has a press enter event with code to spawn a player object and set its phy_rotation, and a draw event which will allow physics debug drawing when the debug draw is toggled. You can look at the file for the code for these events, as it's secondary to our situation.

The door objects are unchanged from the previous example. Their physics shape and properties are defined in the object editor, and they have no code other than a draw event (for debug drawing).

The player object simply ahs control code that applies an impulse for forward movement and turning, and a collision with the door object. I didn't define a collision with the anchor because I'm not sure how you want to handle the player colliding with the walls of the cell, and it seems like you've already got a handle on that. There is also a draw event for the player (again, for debugging).

This is most important: if you want to use this system as I've built it here, you must discard all the code you've posted in this thread! All of the stuff you have now will interfere with this setup and probably prevent it from working. Be sure to remember that when you are using the physics system, you must use the properties of that system! Setting things such as image_angle and direction on physics objects will at best have no effect, and at worst cause unexpected behaviors. You also want to make sure that if you need to move and manipulate physics objects, you must apply a force or impulse to it, or make it part of a motorized joint, such as we have here.

There's probably more I could have done better here, such as setting up proper physics parenting, but you should have already done that, so I elected to keep it simple. I've used some functions that may be new to you (and some I learned while doing this), so make sure you look up anything unfamiliar in the manual and study it carefully.

Again, sorry for the extremely long post, but I wanted to make sure you understood everything in the example file, so I thought it best to write a tutorial post to go with it.
 

XirmiX

Member
@Jezla emm... I didn't expect you to re-write everything. That code might work, but it won't make me understand where I went wrong with my code, and my code seems to be close, but not exactly there and I think it would be better if I can simply edit what I have right now and understand what I did wrong, instead of taking code that I some-what can comprehend, but that doesn't show where exactly I went wrong. I mean, most of what you've done is basically what my code does, or is supposed to do, with a few exceptions.

Testing your example, there is still a glitch with the system; the doors spaz out at the beginning, and I believe that is because of the angle of rotation being as such. May be the joint system is bugged or something, though I couldn't really tell due to how much goddamn ridiculous amount of variables are there to be set and not everything still makes sense to me about those variables. Why I think it might be that the rotation system is bugged to a certain degree, is because I had mechanics set up for when I was doing physics for my game and instead of the point of shooting for the weapon being the same, changing in kind of like a circled direction, it was ovalling instead for some reason. They didn't do that before, only after a certain point, possibly an update, did my system start to glitch out.

It would probably be best for me to try and work around with what I had before (changing phy_rotation_x or phy_rotation_y) but with some sin or cosin added to help out with the slope of the angle, because the bad thing about this system is that the doors spaz out if you try to push them beyond their max joint point, where as changing phy_position doesn't, and that is because the former has joint system + dynamic objects, where as the other is just static objects changing their position. Or, if that doesn't work either, I'll just need to deal with the engine not allowing me to do this and just set up 4 or 8 or so different types of spawn points, all rotated and who have x and y door-opening and closing mechanics be slightly different. I can't leave it be this glitchy.

I appreciate your effort to help me out here, but it seems this system may not be good at all for what I'm trying to achieve :(

It would be really helpful if phy_speed was a variable you could set up as well and not just read, like the speed variable. That would make things a ton easier.
 
Last edited:

Jezla

Member
Okay, the 'glitch' at the beginning comes from the door anchor object being forcibly rotated after the doors are joined to it. This is unavoidable unless you want to do a lot of vector math to create the doors and define the joints with the anchor already at it's final orientation. My math skills aren't that advanced, so I opted to re-orient the door after the joints are created. It's not a bug, but a consequence of using a physical simulation. You could hide the 'glitch' by doing a fade-from-black transition when your room starts.

Where you went wrong is enabling the physics system and then trying to circumvent its proper operation by trying to manipulate objects by using non-physics properties (direction, image_angle) or without using forces (by setting phy_position_x and _y). As I said above, if you're going to use physics, then you need to learn the features of the system and how to use them properly. In addition, it looks as if you've just taken code suggestions that were given to you and plugged them in without regard for whether or not it would fit with what you already had. Case in point is your door alarm event, which is working against what is in your step event. You're also not properly deleting fixtures after you bind them, so I expect at some point you'll have problems with memory leaks. Your system for controlling the doors' movement is needlessly complex, and there are, in my opinion, too many instance_nearest() calls. These are some of the reasons I suggested that you scrap all of your existing code.

If you're realistic about this feature that's giving you so much trouble, you'll realize that at heart what your working on with these doors is merely an effect to enhance your game experience, not an integral mechanical feature. That's why I think you'll do better following the example I gave you: It's simple, self-contained, and versatile. I don't see how you can fail to comprehend it when I've given you a project file and a detailed post that takes you through it step by step. You can also open the manual when you're viewing the project and check out each function I used.

I don't mean to sound angry or impatient, but I'm trying to impress upon you the importance of understanding the fundamentals of the tools you're using.
 

XirmiX

Member
@Jezla I know you're trying to help out, but I now realise that no, this mechanic won't be good for me. The spazzing out when the doors are getting their right angle and such, fine, I'm sure I could fix that eventually. But the system itself allows for the doors to wiggle when you push against them and allows for players to forcefully push them open. I cannot have that.

Changing phy_position_x and phy_position_y will do me good if I can just get sin and cosin right, because with it, I can move the doors while they are static and so the player objects or the like won't be able to move them. I also noticed that with the joint system there is the issue of projectiles going through the dynamic walls sometimes and I can't have that either. I already had most of the mechanics working correctly with this and now have (with the joint code commented out).

I'll need to search more on how to use sin and cosin, since sohcahtoa was pretty much the only thing in math that I never got to understand, or perhaps even ask for an explanation with some examples in a new thread if I can't find sources on my own that can teach it to me well enough so that I can apply it to GML. You've been great help, and while I have decided not to use this system, that decision from your influence in and of itself deserves a thank you, so I'll mention you in the game's credits, if you want, as a special thanks.
 

Jezla

Member
Well, you can use whichever method you choose, but I have to disagree with your choice. The issues you have with the method I showed you can be overcome with some creative design choices. My purpose was not to write your system for you, but to show you how it can be done while keeping to the proper confines of your chosen toolset (the Box2D physics engine). Continuing to manual set the positions of your physical objects is working directly against how the engine is designed. If you wan to do things this way, you'd have less headaches by re-writing your whole game using traditional movement and ditching the physics system altogether.

Good luck to you.
 
Top