Tower defense - how to slow down tanks while their turn on smooth paths?

MartinK12

Member
TowerDefense game, tanks moving on smooth path. Paths go in all directions.

I’d like to slow tanks down (reduce their speed) on path when they are turning so it looks better.
Unfortunately I don’t have idea how to handle it based on path because path has plenty points to make turning look better?
The only solution I come up with is to place obj_slow_down_speed before turn and obj_speed_normal after turn and check collision with those objects.

Anyone have ideas how I could slow tanks down while their turn on path? Thank you :)
Image of example path.
 

Attachments

Slyddar

Member
When you view the path, you can set the speed percentage per path point. I've used slow down before on paths by adjusting these values to lower numbers to simulate speed changes, so it works quite well.
 

MartinK12

Member
Thank you, I wasn't aware of this bcs I always set paths inside room and this can be adjusted only inside path object. Easier than my solution :)

But still this is manual work, so I'd like to make something inside code, just no ideas.
 

TailBit

Member
make a copy of that path just for the tank, and then loop through each set of lines in it and compare their angle difference, then adjust the path speed based between the points based on that?
 

Yal

🐧 *penguin noises*
GMC Elder
Store the direction variable in "old_direction" End Step. (It's updated automatically while you're on a path to correspond to the direction to the next path point). In the step event, if abs(angle_difference(direction,old_direction)) > turn_tolerance, reduce the path speed. Else, approach the intended path speed again. It might get tricky to get turn_tolerance to the right value since it's in degrees / step (and thus is pretty small for a smooth path), so you'll have to play around a bit with different values to see what looks the best.
 

MartinK12

Member
@Yal I like your idea but difference is always 0.00000... so I would require something like previous_position.direction ??
or even better direction of path few positions in front of tank - that could work the best

So far I have in end step:
old_direction = direction;

in step:
GML:
if (global.game_speed_multiplier > 0) {
    if (path_direction == 1) { //going forward on path
        dif = abs(angle_difference(direction, old_direction))
        if  dif > turn_tolerance {
            path_speed = 0.5 * enemy_speed * global.game_speed_multiplier;  
        } else {
            path_speed = 1 //enemy_speed * global.game_speed_multiplier;
        }
    } else { //path_direction = -1; //going backwards on path
        dif = abs(angle_difference(direction, old_direction))
        if  dif > turn_tolerance {
            path_speed = 0.5 * -enemy_speed * global.game_speed_multiplier;  
        } else {
            path_speed = -1 //enemy_speed * global.game_speed_multiplier;  
        }
    }
}
 

TailBit

Member
You could find a point further back and ahead in the path and then find the angle between those from its position
GML:
var offset = ( 10/path_get_length(path_index) ) *path_direction; // find out the percentage value 10 pixels is
var dir_prev = point_direction( path_get_x( path_index, clamp(path_position - offset,0,1) ), path_get_y( path_index, clamp(path_position - offset,0,1), x,y);
var dir_next = point_direction( x,y,path_get_x( path_index, clamp(path_position + offset,0,1) ), path_get_y( path_index, clamp(path_position + offset,0,1) ));

dif = abs(angle_difference(dir_next,dir_past))
if  dif > turn_tolerance {
    path_speed = 0.5 * enemy_speed * global.game_speed_multiplier * path_direction;
} else {
    path_speed = path_direction;
}
Tried to use path_direction to shorten your code a bit ..dunno if it works
 

MartinK12

Member
@TailBit Thank you very much - working as intended :)
I added some more stuff to make it easier to tweak.
If direction_next is slightly more in front of object it makes it look like it's slowing down before making turn which looks more realistic.
Also added acceleration - looks perfect.

LAST PROBLEM:
Unfortunately added acceleration and making so many speed calculations made me confuse about global.game_speed_multiplier. Where should I put it?
If I had it only in path_speed - changing game speed made problems. So I added it to acceleration too, but not sure if that's the place it should be?

Full commented code so others can use it, just not sure about global.game_speed_multiplier?
GML:
//CREATE-code to make object slow down when making turn on path
path_movement = 1; //forwrd or backward on path

//direction of path on previous point
offset_prev = 0;
path_get_x_prev = 0;
path_get_y_prev = 0;
direction_prev = 0;

//direction of path on next point
offset_next = 0;
path_get_x_next = 0;
path_get_y_next = 0;
direction_next = 0; //next

direction_difference = 0; //angle difference between previous and next direction

//speeds
acceleration = 0.01;
min_speed = 1;
max_speed = 2
enemy_speed = 1;
GML:
//STEP-code to make object slow down when making turn on path
//direction of movement on path, changed path_direction to path_movement to avoid confusion
if (path_speed > 0) {
    path_movement = 1; //going forward = from start to end of path
} else if (path_speed < 0) {
    path_movement = -1; //going backwards = from end to start of path
}
    
//find if there's a turn on path and how sharp it is
offset_prev = (1 / path_get_length(path_index)) * path_movement; // find out the percentage value
path_get_x_prev = path_get_x(path_index, clamp(path_position - offset_prev, 0, 1))
path_get_y_prev = path_get_y(path_index, clamp(path_position - offset_prev, 0, 1))
direction_prev = point_direction(path_get_x_prev, path_get_y_prev, x,    y);
    
offset_next = (40 / path_get_length(path_index)) * path_movement; // find out the percentage value in front of object, bigger makes it slow donw before turn, looks more real
path_get_x_next = path_get_x(path_index, clamp(path_position + offset_next, 0, 1))
path_get_y_next = path_get_y(path_index, clamp(path_position + offset_next, 0, 1))
direction_next = point_direction(x, y, path_get_x_next, path_get_y_next);

direction_difference = abs(angle_difference(direction_next, direction_prev))
    
//calculate acceleration for gradual slow down/up depending of sharpness of the turn
if  (direction_difference > 5) { //sharper turn
    acceleration = -0.01 * global.game_speed_multiplier;
} else if (direction_difference > 3) { //normal turn
    acceleration = 0.00 * global.game_speed_multiplier;
} else { // <=3 or >0 //almost straight road
    acceleration = 0.01 * global.game_speed_multiplier;
}
    
//apply acceleration
var min_spd = max(min_speed, enemy_speed + acceleration); //so we don't slow down to 0
enemy_speed = min(min_spd, max_speed); //so we don't go faster than max speed
path_speed = enemy_speed * path_movement * global.game_speed_multiplier;
GML:
//DRAW-code to make object slow down when making turn on path, easier to tweak speeds when visualized points on paths
//draw next point
draw_set(c_red);
draw_rectangle(path_get_x_next, path_get_y_next, path_get_x_next+1, path_get_y_next+1, false);
//draw previous point
draw_set(c_orange);
draw_rectangle(path_get_x_prev, path_get_y_prev, path_get_x_prev+1, path_get_y_prev+1, false);
 
Top