Legacy GM How calculate position in Top-Down racing game?

NightFrost

Member
You might want to detail your problem more. While player's position can be read from x and y variables, I'm pretty sure that's not what you're trying to ask.
 

NightFrost

Member
One alternative would be to use checkpoints, invisible collision-masked objects that stretch across the track. The problem with these of course is how they don't give perfectly real-time data, unless you spam a lot of them across the length of the track. Another way would be to calculate distance from start/finish line along the track. To make this simpler, project car positions to the centerline of the track first. Not sure how to proceed from there, it might be necessary to express the track mathematically to find out which car is furthest down its length. (As said, just the centerline really matters.)
 

Laurent57

Member
first, you class the players according to their presence in an area. The player in zone 6-7 will necessarily be more advanced than the player in the 2-3 zone. If several players are in the same zone, you differentiate them by the distance that separates them from the next key point.
I think you have to pair the zones, (2+3), (4+5), (6+7), etc..
 
Last edited:

NightFrost

Member
first, you class the players according to their presence in an area. The player in zone 6-7 will necessarily be more advanced than the player in the 2-3 zone. If several players are in the same zone, you differentiate them by the distance that separates them from the next key point.
I think you have to pair the zones, (2+3), (4+5), (6+7), etc..
The problem here will be to figure out the plane along which distances to next point are measured. As I mentioned above the problem can be simplified by projecting the positions, essentially turning the measured area into a line. This probably isn't too complicated on straight sections, but looks to be on curve sections where you are measuring progress along elliptical curves. Although, at least on the sample map provided, it should be possible to simply cheat and measure the curves as right angles turns.
 
Okay I see the picture you posted now. The really awkward part will be that weird little zig (or zag?) near the center of the map, and also the cross intersection. For the zig-zag it would probably be good enough to pretend that it is actually just a stright section. For the cross section, I think you will need to use checkpoints in order for the car to know whether it should count its horizontal or vertical position in that section. For the 90 degree turns, what you could do is measure the angle from the inside of the turn to a car, and then divide by 90 degrees, that would give you what proportion the car is through the turn.
 

chamaeleon

Member
Seems to me this is not a really a GameMaker specific problem, and you may have better luck finding appropriate resources on the Internet by searching. One result that you might come across is https://blogs.msdn.microsoft.com/shawnhar/2009/12/30/motogp-ai-coordinate-systems/. I think what you'll find is that there's no nice built-in function that will just make it work for you in GameMaker, you'll need to dig into math (non-GameMaker specific) and track representation in GameMaker (which conceptually is not GameMaker specific, you'd just implement it using whatever data structures makes sense for your code to operate on). If you cannot do it, you may want to take on something less ambitious that relates more to using what does exist in GameMaker for a different project until you feel comfortable dealing the required math and track representation and associated code. I think this is a problem that can be classified as somewhat hard, and you're unlikely to just get some code from someone here that just works.
 

grossik

Member
And what this?
http://imgur.com/mKWgvDm
Every red line moving with car. And then just each time collision:

Code:
var oth = instance_place(x,y,obj_car);
if(oth!=noone)
{
    if(creator.id == other.id){ } else {
            if(creator.position < oth.position){
                oth.position -= 1;
                creator.position += 1;
            }
            
            if(creator.position < oth.position){
                oth.position += 1;
                creator.position -= 1;
            }
    }
}
Somehow so probably. I don't know.
 

NightFrost

Member
I'm sorry @NightFrost i don't understand "to figure out the plane along which distances to next point are measured" :confused:
I was referring to the direction into which the distance measurement needs to be made. If you look at a group of cars without any context, it is not possible to say which one is leading. You might be able to make an educated guess from directions they are moving into, but that would be just that, a guess. You need to know the positioning of the track section; what is the starting point of that section, and where is the end point. From these you get the forward direction of the track segment, and by projecting car positions onto that line, you will know their racing order. (First vector would be from track section start point to track section end point, and the vector to project would be from track section start point to the car currently under scrutiny.) A projection would also tell you when a car has moved past the end of a section, so you can start tracking it against the position of next one.
 

Laurent57

Member
Hmm. Okay. But obviously the track must be defined before, and the key points also. The key points forming the shortest path. I have not tried and actually there are malfunctions. But do you have the formulas to make the projections? Maybe the best thing is to contact a firm that develops this kind of game. It must not be a state secret!
 
My first thought is that I think you will have to do the checkpoint system, as others have stated. Create some checkpoint objects that are lines (you may need to create various sizes and angles) and lay them across the track. When a car comes in contact with the line, it passes it's number into a variable held in the car object. Then you have another scoreboard object that reads in that variable from each car and compares to find the place order.

You may have to play with the spacing of the checkpoints (every 3-5 pixels?) and you may have to manually add via creation code for each object after you place in room what it's checkpoint number is. It will be manual work and fairly time consuming. Some logic will need to be built to deal with crossing the finish line to deal with laps (once you cross, add a multiplier to the checkpoint count value or something).

Over all it shouldn't be too intensive for performance, but as I said, it will be a slow process of setting up each level. This should work as even if the car goes backwards, it should pass back over previous checkpoints and get those numbers.
 
Last edited:

trentallain

Member
Hi.
I need help. I don't know how calculate position in my racing game.
Does anyone know?
Could try putting an object at each bend which creates a line between that and the next connecting object. Then as you pass each one, it calculates the distance you have traveled between the previous and the next one and then you just work out player's position based on the total distance covered using that method?
 

Desix

Member
I think trentallain's idea would work best for you. As you want a system that both helps calculate the car positions, and probably one which can also guide CPU cars around the track his idea is basically defining your track route in a simplified way via code with markers at each corner to join them up. There'd be a LOT of code involved with it however. And I get the impression you want a simple collision based method rather than a mathematical method.

Collision based methods will not work as reliably or be as useful for sure, keep that in mind.

With a maths based system the sector you are in could go on forever each side meaning you could never skip a lap, as the only way to increase a sector could be to pass it at the joint cross intersection.

Crude, but demonstrates well. Each car has a sector value (0-however many sectors you add). Sector edges [black] at the joints [blue] would be the angle between the 2 track angles [dark red]. You calculate the positions for each car in each sector relative to the track angle [dark red], and add it to the positions of cars in the previous sectors. You'll need some trickery to make the track loop correctly basically treating the first sector as one after the last sector. The cars will change their sector value when they cross one of the sector edges [black]. Sector 2 in the example is only a triangle because of how the edges combine. If you drove into the triangle corner it'd either put you in sector 1 or 3, but you could add a failsafe to treat this differently.


Well that's how I'd do it anyway.
 
Last edited:
I think what @Desix is proposing would work, but it will be highly intensive in programming terms. Doesn't mean you shouldn't attempt, but it will not be easy and I doubt you will find any usable tutorials out there. My method, while less technically impressive, should also work pretty flawlessly. You just need to manually go through each track and drop your checkpoint line objects where you want them, and assign each one a number.
 

grossik

Member
I think what @Desix is proposing would work, but it will be highly intensive in programming terms. Doesn't mean you shouldn't attempt, but it will not be easy and I doubt you will find any usable tutorials out there. My method, while less technically impressive, should also work pretty flawlessly. You just need to manually go through each track and drop your checkpoint line objects where you want them, and assign each one a number.
If I did it, I would need help, some example of code.
 
If I did it, I would need help, some example of code.
My method just involves lines (which would be objects) that have a value assigned to it (checkpoint_no = 1) that when you collide with (place_meeting) would set a variable (like race_position = other.checkpoint_no) in that car.

Those checkmark objects could be sprites with specific masks for precision collision checking or maybe you could come up with a method that draws a line (maybe THIS?) (instead of precision checking a sprite mask). But you would need to make an assortment of angles to accommodate all your turns and directions. Then when you place each object on the room over the track, you would add some creation code into it to assign that checkpoint_no variable.

Then you have scoreboard that accesses each car's race_position variable to do some calculations and then render out the position of each car as compared to the others.

If you need help beyond this, I'd recommend going through some of Shaun Spaulding's tutorials. They aren't geared around racing, but they all typically have quite a bit of info about positioning and collisions (which is the basis behind my idea...).
 
Last edited:

grossik

Member
My method just involves lines (which would be objects) that have a value assigned to it (checkpoint_no = 1) that when you collide with (place_meeting) would set a variable (like race_position = other.checkpoint_no) in that car.

Those checkmark objects could be sprites with specific masks for precision collision checking or maybe you could come up with a method that draws a line (maybe THIS?) (instead of precision checking a sprite mask). But you would need to make an assortment of angles to accommodate all your turns and directions. Then when you place each object on the room over the track, you would add some creation code into it to assign that checkpoint_no variable.

Then you have scoreboard that accesses each car's race_position variable to do some calculations and then render out the position of each car as compared to the others.

If you need help beyond this, I'd recommend going through some of Shaun Spaulding's tutorials. They aren't geared around racing, but they all typically have quite a bit of info about positioning and collisions (which is the basis behind my idea...).
And what is poorly in my way? Make line for all car and according to collision to find out if they overtook or not.
http://imgur.com/mKWgvDm

Code in car:
Code:
var ins = instance_create(x, y, obj_overtaking);
ins.creator = id;
And code in obj_overtaking (step code):
Code:
x = creator.x;
y = creator.y;

image_angle = creator.image_angle;

var oth = instance_place(x,y,obj_car);
if(oth!=noone)
{
    if(creator.id != other.id){
        if(creator.position < oth.position){
            oth.position += 1;
            creator.position -= 1;
        }
    }
}
Somehow this I imagined.
(sorry for my bad English)
 
And what is poorly in my way? Make line for all car and according to collision to find out if they overtook or not.
http://imgur.com/mKWgvDm

Code in car:
Code:
var ins = instance_create(x, y, obj_overtaking);
ins.creator = id;
And code in obj_overtaking (step code):
Code:
x = creator.x;
y = creator.y;

image_angle = creator.image_angle;

var oth = instance_place(x,y,obj_car);
if(oth!=noone)
{
    if(creator.id != other.id){
        if(creator.position < oth.position){
            oth.position += 1;
            creator.position -= 1;
        }
    }
}
Somehow this I imagined.
(sorry for my bad English)
I am not sure if you are saying you have a working solution or not...

Your method could maybe work too, though I am thinking there might be some issues with driving backwards?
 

grossik

Member
I am not sure if you are saying you have a working solution or not...

Your method could maybe work too, though I am thinking there might be some issues with driving backwards?
Maybe yes. But this is not important now. My code works but still adds and subtracts. So then there are numbers like -450 or 500... I need to change it only once.
 
Are they still in the correct order, even though the numbers are really big?

You probably want to clamp() to prevent numbers from exceeding 6 or being less than 1. You would use that when doing the adding and subtracting.

Also only allow the adding and subtracting happen once per collision, right now it is probably happening every step of their meeting. This is probably making it take big jumps in count as well.
 
Last edited:

grossik

Member
So now it looks like this.
Code:
            oth.position = clamp(oth.position+1, 1, 5);
            creator.position = clamp(creator.position-1, 1, 5);
Now just do it once in a collision.
 
Looks about right.

You will probably need to set a variable to 0 before the collision - check before math if 0, if yes - do math and set variable to 1.


This is psuedo-code... I am on phone.
Code:
collided = 0

if ( collision check ) {
    if ( collided == 0 ) {
        do math;
        collided = 1;
    } 
} else {
    collided = 0;
}
Then when collision is ended - change it back to 0.

This might get a bit weird though if a bunch of cars all are meeting around the same space... so it may not work. You may have to come up with another way of only adding/subtracting once.
 
Last edited:

grossik

Member
Looks about right.

You will probably need to set a variable to 0 before the collision - check before math if 0, if yes - do math and set variable to 1.


This is psuedo-code... I am on phone.
Code:
collided = 0

collision check {
    if ( collided == 0 ) {
        do math;
        collided = 1;
    }
}
Then when collision is ended - change it back to 0.

This might get a bit weird though if a bunch of cars all are meeting around the same space... so it may not work. You may have to come up with another way of only adding/subtracting once.
This does not work. I really don't know. :(
 

grossik

Member
The initial collided needs to be set in the create event.

And you didn't use my pseudo code, right?
Used..

In step
Code:
var oth = instance_place(x,y,obj_car);
if(oth!=noone)
{
    if(creator.id != other.id) then {     
        if(collided == 0) {
            if(creator.position > oth.position) then {     
                oth.position = clamp(oth.position-1, 1, 5);
                creator.position = clamp(creator.position+1, 1, 5);
            }

            collided = 1;
        }
    } else {
        collided = 0;
    }
}
and create:
Code:
collided = 0
 

grossik

Member
Sorry, I am at a bit of a loss.
This code:
Code:
var oth = instance_place(x,y,obj_car);
if(oth!=noone)
{
    if(creator.id != other.id) then {     
        if(collided == 0) {
            if(creator.position > oth.position) then {     
                oth.position = clamp(oth.position-1, 1, 5);
                creator.position = clamp(creator.position+1, 1, 5);
            }

            collided = 1;
        }
    } else {
        collided = 0;
    }
}
Does nothing. Position it's same.
 

grossik

Member
And I still have a problem with other cars. I need something better than a path. Somehow make a pathfinding, but for each car, they do not the same path.
 
Sorry, you may have to scrap my idea about clamping and the collision check. I think you are going to have nothing but trouble with trying to keep track of collisions like this with multiple cars all around each other. Another game dev here may have some better ideas to keep this all working as you have and improve like I was trying, but I am guessing it is going to be an uphill battle.

That said, If you go back to your original method, when you were ending up with huge numbers - were they still in the correct order? I mean, it may have been -450 and 500 (or whatever) - but, if they are still in the correct order, you may have still have something to work with. You would just have to do some math to compare all the car's values to each other and get their place.

I have a feeling they aren't in the correct order, but who knows.

If not - if the order is incorrect, you are sort of back to the drawing board in my opinion. I don't have much else advice if you want to continue with your plan of having the collision lines stay with the car. I and other people offered some other ideas, you may want to explore those.
 

grossik

Member
Sorry, you may have to scrap my idea about clamping and the collision check. I think you are going to have nothing but trouble with trying to keep track of collisions like this with multiple cars all around each other. Another game dev here may have some better ideas to keep this all working as you have and improve like I was trying, but I am guessing it is going to be an uphill battle.

That said, If you go back to your original method, when you were ending up with huge numbers - were they still in the correct order? I mean, it may have been -450 and 500 (or whatever) - but, if they are still in the correct order, you may have still have something to work with. You would just have to do some math to compare all the car's values to each other and get their place.

I have a feeling they aren't in the correct order, but who knows.

If not - if the order is incorrect, you are sort of back to the drawing board in my opinion. I don't have much else advice if you want to continue with your plan of having the collision lines stay with the car. I and other people offered some other ideas, you may want to explore those.
I will do it in a different way...
Now I have to make pathfinding, because path it's not what I imagine.
 

Laurent57

Member
I remain convinced that my idea of zone and distance just to the key points is not a bad idea.
The position in a priority list should be
number of the area * 1000 + distance to the key point
exemple:
player 1 : position = 10 * 1000 + 106 = 10106
player 2 : position = 10 * 1000 + 324 = 10324
player 3 : position = 11 * 1000 + 318 = 11318

set the priority of each player :
ds_priority_change(player_priority, "player_x", position);

then sort the name of the player with a loop using ds_priority_find_min
 
Last edited:

Laurent57

Member
Of course, my code must be adjusted with, for example:
If the number of the new zone is less than the number of the old zone then the number of the current zone is the number of the old zone,
in order to oblige to respect the direction of the circuit.
If one player comes from the zone 6 then the zone 12 becomes zone 5 and the key point is the opposite angle, etc.
 

grossik

Member
I remain convinced that my idea of zone and distance just to the key points is not a bad idea.
The position in a priority list should be
number of the area * 1000 + distance to the key point
exemple:
player 1 : position = 10 * 1000 + 106 = 10106
player 2 : position = 10 * 1000 + 324 = 10324
player 3 : position = 11 * 1000 + 318 = 11318

set the priority of each player :
ds_priority_change(player_priority, "player_x", position);

then sort the name of the player with a loop using ds_priority_find_min
Somehow like that?

 

Laurent57

Member
I think in this case you have too many polygons.
You must define your key points (always angles) that make up the shortest route with the right number of zones.
In my case the shortest path is A-B-C-D-E ... etc ...
 

HayManMarc

Member
I think I would have approached this by creating a path for the track and then checking the cars' positions relative to that path.
 

Yal

šŸ§ *penguin noises*
GMC Elder
In my racing engine, I do things the opposite way: the player's position is stored as path position (the racetracks are implemented using GM paths) at all times, and then I compute the x / y / z position from that. So movement needs a lot more maths, but you always have a fully accurate position value.
 
Top