• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

[SOLVED] is it possible to move physics object along predefined path?

Tornado

Member
I know it sounds stupid at first, but I'm trying to achieve following:

I have an object "A" wich participates in physics world. But after it touches some other object "B" I change the collision group of "A", because from that point on, the object "A" should not collide with anything anymore, because it is marked to be destroyed. Before I destroy it I want to move in a predefined way. I put those points of my "predefined movement line" into a relative path object.
Then i start the path for instance "A".
But then I discovered that path doesn't work on physics instances, i guess. Or I'm not using it in a correct way!

I tried to set
phy_active = false;

but it doesn't help, i guess it only disables collisions and so, but the object is still an object of the physics world.
I checked this by setting for example some fix values:
x=300;
y=300;
but nothing happens.

But when I set
phy_position_x = 300;
phy_position_y = 300;
object "A" is moved there.

That means it is stll an object in physics world.

Can you please give me some pointers if it possible to achieve something like this and how?

Thank you!
 
I use pathing with physics as a way to move my objects.
The way I do this is I have a step event follow the path.

So, I will have the variables path and pathIndex assigned to the object upon creation and set to zero when a path is populated or started to be followed.

Then when I want that object to move, I will populate its path.
Then, with a step event, I have it move along that path.

Below, I pasted a bit from my step event, removing parts of the code that I did not think were related to your question. I denoted the removed parts with //[...]

Code:
// [...]

var _rangeStop = MOVEMENT_ACCURACY;
var _totalPoints = path_get_number(path);
var _distanceToEnd = 0;

if(_totalPoints > 0){
    var _lastPointX = path_get_point_x(path, _totalPoints-1);
    var _lastPointY = path_get_point_y(path, _totalPoints-1);
 
    var _distanceToEnd = point_distance(self.x, self.y, _lastPointX, _lastPointY);
}

if(_distanceToEnd < _rangeStop){
 //   [...]
 //destination arrival stuff goes here
    pathIndex = 0;
    return true;
}

var _nextPathPointX = path_get_point_x(path, pathIndex);
var _nextPathPointY = path_get_point_y(path, pathIndex);

var _distanceToNextPathPoint = point_distance(x,y,_nextPathPointX, _nextPathPointY);

if(_distanceToNextPathPoint < self.moveToAccuracy){
    if(pathIndex + 1 < _totalPoints){
        pathIndex += 1;
    }
}

//Get direction
self.direction360 = point_direction(x, y, _nextPathPointX,_nextPathPointY);
scr_lifeform_update_face();
 
//Get length
self.length = self.currentMoveSpeed;

// Get speeds
hSpeed = lengthdir_x(self.length, self.direction360);
vSpeed = lengthdir_y(self.length, self.direction360);

//Control sprite speed
self.image_speed = sign(self.length) * self.imageSpeed;
if(self.length == 0) self.image_index = 0;

//Move
scr_obj_move_phy(self, hSpeed, vSpeed);
My scr_obj_move_phy is simply:
Code:
///scr_obj_move_phy(object, phy_offsetX, phy_offsetY)

argument0.phy_position_x += argument1;
argument0.phy_position_y += argument2;
 
Last edited:

Tornado

Member
Ok, thank you very much for your response!
I'll analyze your code (I'm new to GMS).

But that means you cannot use
path_start(path, speed, endaction, absolute);
for physics objects, right?

Therefore you are doing this manually in the step event.
You are using the path more or less like a normal array.
I already have all movement points in a list, so I can basically use the list directly,
because having a path in this case isn't giving me much extras.

Do I have correct understanding on this?
 
Last edited:
Ok, thank you very much for your response!
I'll analyze your code (I'm new to GMS).

But that means you cannot use
path_start(path, speed, endaction, absolute);
for physics objects, right?

Therefore you are doing this manually in the step event.
You are using the path more or less like a normal array.
I already have all movement points in a list, so I can basically use the list directly,
because having a path in this case isn't giving me much extras.

Do I have correct understanding on this?
Yup! I inch along the path with every step call.
The reason for this is because I use an mp_grid and that path is dynamically generated based on surrounding objects and enemies.
The beginning of this, which I excluded, has it searching for possible enemies, which may change its path.
If you have any questions, feel free to ask or PM me.
 

Tornado

Member
ah ok, my movement won't be disturbed by anything, the object "A" does this last movement without any interruption.
Therefore I hoped I can just populate a GMS path with points and then just conveniently call
path_start(path, speed, endaction, absolute);
But apparently it was a wrong hope.
I'll then also do it in the step event.

Thank you for your kind help!
 

Jezla

Member
You can have a physics object follow a path the same as a non-physics object. It just needs to be set to kinematic.

Edit: it doesn't have to be kinematic, but I found that it helps.
 

Tornado

Member
Hmm...I also tried kinematic but it doesn't help.
At the time of the collision I change some fixture properties of object "A" and do path_start(), but the previous impuls (which was applied before changing fixture properties) is still moving the object "A".

Could it be that I cannot move it along the path because the previous movement which was done by impuls haven't finished yet?

Is there any command to stop physics object from moving immediately?
Thx
 
Last edited:

makas

Member
You could try to use a non physics object as a target for your physic object add the path to this object make it invisible, and then make your physics object follow the target, I learned this on a physics based racing game tutorial, and it worked like a charm, also you can add some code to the target object so if for some reason your physics object is too far away you reduce the speed until the physic objects catch up... I can elaborate a little more if you need it
 

Tornado

Member
@makas: I'll take a look at that tutorial if I decide to go that way. Thank you very much.

@Jezla: I think the best would be for me to prepare again a small project which shows the problem directly and post it. I'll do it tonight when I get back from work.

Maybe I'll get new insights in the process of making small example :)

Thanks a lot to all helping!!!
Really cool people on yoyo forums.
 

Tornado

Member
Hi!
Finally I found time to prepare a small sample project. (I have family and full-time job :) )

Here is this sample project:
https://drive.google.com/file/d/0B7uW3owO7qdIVnJ6Z1NMT3MxOG8/view?usp=sharing

The circle is not movable object I also marked it as sensor because I read in the documentation that sensor is getting collision event just one time as long as the objects are still colliding.
The square gets the implus in the direction of the left click. I also drew the path on the screen, that's the shape of the movement which square should make (from outside to the inside of the spiral) when it collides with the circle.

So, when I move (with mouse clicks anywhere in the room) that square toward the circle when it collides with the circle I want the square to start spinining and to perform the movement in the shape of that spiral from the place where collision happend.
I count the collisions for debugging puproses, so you can see in the output window how many collision happen and when.

I have a problem here:

obj_Block (square) just ignores
path_start(global.blockSpinningPath, 5, path_action_stop, false);
It doesn't move on that path. Acually it doesn't move at all.

Also I thought, ok, the square is still moving from the impuls, so maybe that is the reason why my path doesn't work. So, I created an alarm which fires 10 seconds after collision has happend.
That means I leave square some time to stop movement then after 10 second alarm triggers spinning and start the path.
You will see the spining but the object doesn't move a bit.
If you don't want to wait for alarm just replace in obj_Sensor collision event
other.alarm[0]= room_speed * 10;
with the code from alarm
spiralMovementInitiated = true;
show_debug_message("spiralMovementInitiated=true");

If you do that then also the spinning is not performed!

How can I do all of this?

I just want a spin and path movement after collision.
After this, my plan is to destroy square as it will not be needed anymore. (therefore I change its collision group after first collision, so that it cannot collide with anything anymore)

Thank you for your help!
 
Last edited:

Jezla

Member
I'll try and take a look at it tonight or tomorrow and see what I can tell you (family man here, too!).

EDIT: I'm looking at it now. I still haven;t got it to work yet, but I see a number of things I'd suggest you do differently. I think I'll try and throw together a blank project, but I want to be clear about what you want to accomplish. You want the square to spin and spiral once it hits the circle, and when it's done with the spiral, to be destroyed. That correct?
 
Last edited:

Jezla

Member
Okay, I've played around a bit, and the only way I was able to get the behavior to work was to have two square objects, one dynamic, and the other kinematic. In the kinematic object's create event I called path_start(). In the sensor's collision event, I have the dynamic square perform an instance_change into the kinematic square, with perform events argument set to true.

Objects created as kinematic objects have no problem following a path. To make it spin, just change the phy_rotation in the step event. Note that kinematic objects must have 0 (infinite) density. I wish I could offer a better solution!

Regarding your example project, here's some things I noticed:

  1. I didn't like leaving the ending fixture in memory. I think it would be better to put that in a script that returns the new bound fixture id, that way the fixture can be properly destroyed.
  2. Rather than putting the collision code in the step event of the square, it should be in the collision event of the sensor. Less need for checking variables because it will only fire once anyway. You can make use of the dot accessor or with() statement.
  3. Changing the collision group of the fixture is overridden by the collision event in the sensor, so they'll still register a collision anyway. Collision groups are designed to work without a collision event.
  4. Interesting way of defining the path! My math skills are not the best, and I wouldn't have thought of using a ds_stack to hold the points.
 

Tornado

Member
That is correct.

I still haven't managed to directly apply the path on obj_Block.
I also tried to apply
phy_active = false;
and then immediatelly
phy_active = true;
hoping that this will stop any previous physics influence on obj_Block and "free" it for next influences, but it didn't work.
Also with 10sec. delay path_start doesn't move obj_Block.

But I tried the "Online Handle's" suggestion using the path indirectly for feeding phy_position_x and phy_position_x in the step event, like:
phy_position_x = xx + path_get_point_x(global.blockSpinningPath, pathIndex);
phy_position_y = yy + path_get_point_y(global.blockSpinningPath, pathIndex);
pathIndex++;
(where xx and yy are coordinates of the obj_Block at the time of collision)
This worked!
(it still doesn't work perfectly, but the general idea works - I still have to somehow match the end of the spiral to the position of obj_Block so that it strat moving from that point and do not jump somwhere for the first point, but that's another topic)

I guess also the suggestion from "makas" is going to work by putting an invisible non-physics object in the room, start the path on it, and obj_Block will follow that invisible object.

I still wonder if this is possible without any workarounds. Jezla, maybe GMS's paths really doesn't work for physics objects!
 

Tornado

Member
ok cool!!!
After I read you last post, I tried in my sample to set
...
physics_fixture_set_density(endingFixture, 0);
physics_fixture_set_kinematic(endingFixture);
...
but it didn't help. I guess it must really be separate instance which has density 0 and kinematic from the beginning.

1) in my "real" project, I have many obj_Block on the screen, each of them can be destroyed at some point, so I needed endingFixture over and over again to be applied on each object which will be destroyed.
Therefore I didn't destroy this fixture. Is that ok?

2) ok I can use
with other {
...
}

I ended up anyway using something like
other.xx = phy_position_x;
other.yy = phy_position_y;
physics_remove_fixture(other, other.currentBoundFixture);
other.currentBoundFixture = physics_fixture_bind(other.endingFixture, other);
other.spiralMovementInitiated = true;

You are right I could also move the the movement code into the collision event!

3)
hm...I don't quite understand this. how is it overriden? In my "real" project, I also have obj_Player which is also in collision group 1 and obj_Player can push around obj_Block. When it pushes it to the circle object and collision is detected (like in the sample project) I change collision group of obj_Block to 99. Then obj_Player cannot push it anymore.
Or you say that I should set collision group of objSensor to 0, because it contains collision event? Do you mean if you have defined a collision event that automatically overrides the fixture settings of that object and sets the collision group to 0?

4)
I suck at maths big time! I took me half a day to google for spiral and to find formula and some code in other programming languages and to apply it here.
I used stack because spiral function draws from inside to outside, but I need my object to move from outside to inside of the spiral. Today I saw there is path_reverse function, I guess now I don't have to use stack anymore.
I guess I'll will spend some more hours on fine tunning this now, so that when obj_Block collides with circle that this position matches the end of the spiral (for the object it is the beginning of the spiral) and that the center of the spiral matches the center of the circle object. My goal is that at the time of collision obj_Block start spiraling from that position and it ends exactly at the center of the circle. (My actual obj_Block are much smaller as in the sample.)
I think I'll have to use path_rotate function for that. Good luck with that :)

I would like to thank you all for your time!
Jezla, thanks a lot for looking at it in such detail!
 

Jezla

Member
You're welcome! In response...

1. That's what I was concerned about. With each block object, you're creating a fixture in the create event, and asking the computer to allocate memory for it. Having a lot of these, and if you don't keep tight control over when or how they're created, could cause a memory leak. That's why I suggest moving the code for creating and binding the ending fixture to a script, and running that when you need to. In that way you can properly destroy the fixtures that are not needed, safeguarding against possible leaks.

3. I was talking about the collision between the block and the sensor object. Changing the group will work as you intend for other objects (as you point out), as long as there are no collision events set between the opposing objects.

Good luck!
 

Tornado

Member
1) ah ok, I thought I'm safe because I'm creating fixtures in the create event of the parent object and that will be done only once!
But I overlooked the fact that children have the call
event_inherited();
so every square object will create 2 new fixtures!
What a mistake!

Thank you for pointing out that! It's a valuable lesson for me!
 
H

hackerG7

Guest
var speed = 10000 //force
var target_x = 100
var target_y = 100
physics_apply_force(phy_position_x,phy_position_y,-phy_speed_x*725,-phy_speed_y*725) //this code can make the physics object stop moving
physics_apply_force(phy_position_x,phy_position_y,lengthdir_x(speed,point_direction(x,y,target_x,target_y)),lengthdir_y(speed,point_direction(x,y,target_x,target_y)))

//the physics object will move towards target point in a fixed speed
 
Top