1
\$\begingroup\$

In my Gamemaker: Studio game, I have a collision script for my enemy. The enemy is an alien, oSwarmer, moving through space which is also filled with drifting, spinning bits of debris. Some debris barely spins at all, others spin quite fast.

When oSwarmer executes the following collision script every step. As you can see, if it is about to come into contact with some debris (here called oSolid) it changes direction away from the colliding oSolid and maintains its original speed.

SolidTouching = instance_place(x + hspeed, y + vspeed, oSolid)

if instance_exists(SolidTouching) {

OriginalSpeed = CurrentSetSwarmerSpeed

if speed > 0 {
direction = direction - random_range(130,220)
} else if speed <= 0 {
direction = point_distance(x,y,SolidTouching.x,SolidTouching.y) - random_range(130,220)
}
speed = OriginalSpeed
}

However, sometimes when coming into contact with an oSolid, they spin madly on the spot. I've noticed that this seems to occur when the oSolid is spinning. These creatures do not move very fast, so their initial 'bounce' is not enough to carry them out of the path of the rest of the oSolid which is coming around to meet them. I think they then get caught in a loop of constantly trying to move in the opposite direction to the colliding oSolid (which is changing every step because it is spinning).

What I cannot work out is how to remedy this. Does anybody have a suggestion?

\$\endgroup\$
3
  • \$\begingroup\$ Maybe a problem with your mask. You're using which kind of colission mask for both oSolid and oSwarmer? And I didn't know that speed change both xspeed and yspeed values(based on direction ofc). \$\endgroup\$
    – DH.
    Jan 22, 2016 at 12:21
  • \$\begingroup\$ To know how and why they get in the infinite loop you describe we will need some more information i think. Such as under what conditions does speed become negative or CurrentSetSwarmer speed for that matter. And what is point_distance exactly? \$\endgroup\$
    – Dusky
    Jan 22, 2016 at 16:36
  • \$\begingroup\$ In both cases the mask is Precise. Speed doesn't become negative, but I was always taught it was good practice to write '<=0' rather than just '=0', just in case. CurrentSetSwarmerSpeed is just a variable that I set at the Swarmer's Create event; it just means the default speed for the Swarmer object. It's in Variable form to make it easier to change. I believe it is currently 120 / room_speed. Point Distance is a Gamemaker function for getting the distance in pixels between two points, but I now realise I've been using it wrong! I meant to use point_direction. That fix doesn't help, tho. \$\endgroup\$ Jan 25, 2016 at 18:41

2 Answers 2

0
\$\begingroup\$

When working with direction and speed, if you change the value of the former you don't need to update the value of the latter, as GM:S automatically updates hspeed and vspeed in order to reflect the changes on the speed vector upon its separate components. Also, you can change the value of speed making it both greater or smaller than zero, but if you only change values of hspeed and vspeed you'll find out speed will always evaluate to a number greater than or equal to zero. Just sayin'.

That said, you need to make your oSwarm avoid space debris by changing smoothly its moving direction. I think there are countless ways to achieve this, so we can focus on an easy solution.

But first, you talked about oSwarms spinning madly when colliding with certain debris. I think that happens because when using random_range() you are changing their direction using high values, and that may result in jittery movements. Try using smaller values, like random_value(30,60) before to proceed with reading my answer.

So, you can test when oSwarm collides with an oSolid in Step Event and change your alien moving direction according to its relative position with the debris:

// Check collision
var my_solid = instance_place(x+hspeed,y+vspeed);

// Support variables
var my_dir, my_angle, my_prod;

// Did collision occur?
if (my_solid!=noone)
{
    my_dir = point_direction(x,y,my_solid.x,my_solid.y);  // Direction toward object
    my_angle = ((direction+360)+(my_dir+360))%360;        // Angle between my_dir and direction
    my_prod = direction*my_dir*sin(degtorad(my_angle));   // Cross product

    // Test cross product
    if (my_prod>=0)
        direction -= irandom_range(0,30);  // Better steer clockwise
    else
        direction += irandom_range(0,30);  // Better steer counter-clockwise
}

If you need further help with this code, just comment and I'll respond.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks very much for this comprehensive answer! I have since converted my game to use Gamemaker's physics engine (both because I thought this would make the various collisions much easier to simulate, and because it was about time that I learnt how physics works in Gamemaker). However, your point about using large values when changing direction on collision will still apply, and I'll be sure to use it. Thanks again. \$\endgroup\$ Jun 7, 2016 at 14:53
  • \$\begingroup\$ Physics engine is much more powerful, yet still remember is more CPU-expensive, works at a different update rate than your room_speed, and the convention for angle direction is different: while in GM:S direction is 0 when 'facing' leftwards, the physics engine assumes direction 0 as upwards. Nothing hard to deal with, all in all ;) \$\endgroup\$
    – liggiorgio
    Jun 7, 2016 at 16:47
1
\$\begingroup\$

May no be a greater answer to your question, but have you tried using GM:S's physics engine?

You can simply assign physics fixtures to the objects and let the program do the collision for you, if these two objects are the only ones you want collision with, you can just give physics properties to these two and everything else stay in your original design.

The coding would look something like this for oSwarmer in the "collision" event:

if phy_speed>0.1

{
phy_rotation+=random_range(130,220)
}

if phy_speed<=0.1

{
SolidTouching=instance_place(x,y,oSolid)
direction = point_direction(x,y,SolidTouching.x,SolidTouching.y) - random_range(130,220)
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for this - as noted above, I've since switched to the physics engine in my game, so this will now be very useful. The other answer is still applicable to my original query, however, and will be useful for anybody else not using the physics engine. \$\endgroup\$ Jun 7, 2016 at 14:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .