1. Hello Guest! It's with a heavy heart that we must announce the removal of the Legacy GMC Archive. If you wish to save anything from it, now's the time! Please see this topic for more information.
    Dismiss Notice

How to make a more accurate lap time? get_timer() LIMITATION?

Discussion in 'Programming' started by Genesys Generation, Nov 21, 2019.

  1. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    In the room there are 22 cars. All cars have a different speed.

    The cars are numbered from 1 to 22 with the help of the variable carNumber.

    CODE - obj_Car / Set car speed (Create Event):

    Code:
    velocity=10-((carNumber-1)*0.01);
    Here's how there is a difference in car placement near the end of the lap:

    631.png

    However, even with this difference, the times of many cars are repeated:

    632.png

    The detection of lap time looks like this.

    CODE - obj_Car / Time lap (Collision with obj_Finish):

    Code:
    other.orderLapTime[car]=get_timer()-other.discount;

    • Discount = this is the exact time when the room starts (cars already start running).

    CODE - obj_Finish / Set discount (Create Event):

    Code:
    discount=get_timer();
    The display is made with a modifier (multi, to simulate actual track times).

    CODE - obj_Finish / Draw time lap (Draw Event):

    Code:
    draw_text(1500,100+(20*(i)),string_format(orderLapTime[i]*obj_Seth.multi/1000000,1,3));
    Even taking the multiplication and increasing the number of decimal places, there are still many repeated times:

    633.png

    Some inconsistencies including. Cars with slower speeds marking faster times.

    I could slow down the base speed (10) to solve such a problem, but I already think in the long run. The races can't take so long. In addition I intend to give the player the option to set the speed with which the race takes place (a multiplier, more frames, etc).

    It could also increase the difference between the speeds (0.01 to 0.05), but I would like a general resolution, so that I can notice through the lap time, if only by one thousandth (0.001).

    EDIT 1 - Attempts made based on answers and comments from Bálint and TomTsagk:

    That is what I tried to do.

    CODE - obj_Car / lap time (Step Event):

    Code:
    unit+=velocity/60*0.001;
    Below the results...

    634.png

    Respective code:

    Code:
    draw_text(1500,100+(20*(i)),string_format(orderLapTime[i],1,3));

    635.png

    Respective code:

    Code:
    draw_text(1500,100+(20*(i)),string_format(orderLapTime[i],1,5));
    The speed difference between the cars is 0.01.
     
    Last edited: Nov 21, 2019
  2. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    TBH I can't imagine get_timer() being useful in this context (it's rare when it is useful), as it measures real time, not game frames, and so it will give unpredictable results. Generally you'd want to make your own timer like

    creation:
    timer = 0:

    step:
    timer++

    and timer is just your time. Divide by room_speed for seconds. Put the variable in a persistent room controller object, or in individual cars if they start at different times or something. Reset the timer by just setting it to 0 again

    Edit: The only way to increase accuracy beyond this is to measure the amount that they surpass the lap manually and calculate the time to subtract based on velocity.

    Example:

    finishTimeFrames = timer - passedDistance/velocity;
    finishTime = finishTimeFrames/room_speed;

    passedDistance/velocity will be a fraction of a frame. There's a few ways of calculating passedDistance, I'll leave that up to you. You will probably need to do a point_distance calculation based on the tip of the car sprite and the position and angle of the finish line.

    You can squeeze in extra accuracy by doubling room_speed and halving velocity, but that's kind of overkill, the above will give a much greater impact.

    Note: the repeats are caused because your cars are colliding with the finish line multiple frames until they are fully across.
     
    Last edited: Nov 21, 2019
  3. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    When the car reaches the finish line, it turns a boolean variable into a true.

    Since the time measurement is only made with the variable being false. The variable only becomes false again when touching an object that is made exclusively for this function.

    I tried to share the link from where I asked that same question, but the site doesn't allow it (to avoid spam).

    I already thought of solving the problem by slowing down the cars and increasing the number of frames, but with that I came across 2 problems:

    1. I want the race to run at various speeds, so there will always be a player who will run at full speed and the error mentioned above will happen.
    2. I want to launch the game also for mobile phones, many of them could not stand a game running at 120-240 steps.
    By setting the time counter on a separate object I achieved remarkable accuracy with 0.1 speed differences starting from 10.

    I think your idea with the distance traveled will work.

    How do I calculate the passedDistance?
     
  4. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    The easiest way I can think of, assuming your finish line is an actual sprite that is a line:

    1) change the sprite origin of the car to the nose of the car. Alternatively, subtract sprite_height/2 or sprite_width/2 from the car.x/car.y below
    2) if the finish line is horizontal, passedDistance = finishLine.y - car.y
    3) if the finish line is vertictal, passedDistance = car.x - finishLine.x

    It gets trickier if you want your finish line at an angle, and you'd have to either use some trig or length_dirx/length_diry functions. I can work out a solution if you need it, but thinking about it further, having the finish line be horizontal or vertical sounds like a normal restriction for a racing game.
     
  5. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    The finish line is a square.

    I managed to get a way of calculating the distance traveled by cars every second, I think by working a little on that I can turn that distance into lap time.

    Create Event:

    Code:
    distance=0;
    distanceSP=0;
    Enter Pressed Event (button for cars to start moving):

    Code:
    x1=x;
    y1=y;
    Step Event:

    Code:
    if(x1!=x || y1!=y){
       distance=distance_to_point(x1,y1);
    }
    
    if(obj_Finish.timer mod 60==0){
       distanceSP=distance;
       x1=x;
       y1=y;
    }
    At the time I was making this post, I made a change and the final distance calculation was like this:

    Code:
    if(x1!=x || y1!=y){
        distance+=distance_to_point(x1,y1);
    }
    
    if(obj_Finish.timer mod 60==0){
        distanceSP=distance;
        distance=0;
        x1=x;
        y1=y;
    }
    Do you think I can get anywhere with this?

    Even with minimal speed differences (0.001) I'm getting different results (close but different), it seems good to me.

    And thank you very much, your help is being valuable.
     
  6. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Edit: Ah nvm, I see what you're doing. That might work, but it's best to do this calculation for individual track segments, and once it passes the track segment, add it in full instead.

    As for the finish line being a square, I would make it's collision_mask an actual line, it's much more useful that way.
     
    Last edited: Nov 22, 2019
  7. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    I changed the collision box from the finish line to a line.

    Because of your help I found another way to calculate time.

    Using the function:

    Code:
    path_get_length
    With the length of the circuit (https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/paths/path information/path_get_length.html) and the speed it is possible to calculate the time correctly.

    Code:
    time=path_get_length/velocity
    But then a new problem arises. At very high speeds, because the finish line collision box is too thin, the collision is not detected.

    And more... it seems that the problem of this difference between the calculated time and the fixed position in the circuit happens because of the change in speed between the turns.

    The car at the end of the lap seems to make a leap (minimal, barely noticeable). This is because the speed change is made when the car collides with the finish line and not when the lap actually ends.

    I do not know if you can understand this last part, my English is terrible.
     
  8. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Well, if your cars are going so fast that it goes past the line, maybe using a square isn't that bad. You can fix the line issue by using collision_line backwards from your car tip based on your velocity instead of place_meeting with the finish line, but a bigger collision is just easier.

    Yeah I actually don't understand that last bit sorry T_T Why is there a speed change?
     
  9. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    The speed change occurs because cars make laps at different times. The tire wears out, the driver deconcentrates, the car gets lighter.

    It is random, and this change occurs when the car touches the finish line. Then the next lap is made at a new speed (or the same, if at randomization the speed is the same).

    If you want I pass you the code. Now I think the problem is in that position jump when the car touches the finish line. Because even though the finish line is at the beginning of the circuit, the car can touch it a little before or after.

    path_position = 0.998 or 0.001
     
  10. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    I think a gif explaining the issue would help, screentogif is great for making gifs.

    It sounds like you're having one of two issues:

    1) The finish line collision is happening earlier/later in the frame than when you want, causing it to seem to happen a frame too early/late. This is solved by handling the collision in the car using place_meeting in the appropriate place rather than using a collision event. IMO you should never use collision events

    2) The finish line collision doesn't line up with the circuit. In this case you may really want it to be a line and use collision_line as I said earlier. Alternatively, keep it a square, but make it invisible and have it so the beginning of the square is at the "line"

    If it's some other issue, I need gif or picture explaining the issue
     
    Last edited: Nov 23, 2019
  11. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    (I posted this before seeing your last answer. I had not updated the page.)

    I made no progress trying to avoid the jump when the car passes the finish line or the starting point of the circuit.

    I believe I will have to do the time based measurement. Since I couldn't make what happens on the track match the classification correctly.

    I believe this change in speed all around may be the cause of the problem.

    One solution I thought was to ridiculously increase the size of the circuit and display it several times smaller, because that way at high speeds cars would take a long time to complete laps. That way I wouldn't need to increase the frame rate of the game.
     
  12. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Hmmm.. What was wrong with the very original idea, with just making a simple timer, using room_speed, and for lap completion using the passedDistance/velocity idea? I feel like we're getting sidetracked here.

    I think I may have misinterpreted your problem, it sounded like you just wanted to see who won the race, but you want their positions during the race as well.

    If you need to get the placement of each car, one thing you could do is just make a very fine path, keep a "position" variable starting at 0 for each car. Then check every step if you're closest to the current position or the next coordinate on the path(using point_distance), and if you are, advance to the next position. And the cars are ordered by their position and if there's a tie, it's whoever had a shorter distance to the next position. You'd have to do some line intersection math if you wanted extra accuracy, that is determining the exact point your car would instersect the path if at a right angle to it. But you could also be lazy about this and just make your own line objects to do tests
     
    Last edited: Nov 24, 2019
  13. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    So my current problem is just in the order of cars not matching what is seen on the circuit.

    Basically I peg the time to the physical position in the circuit and it doesn't match 100%.

    I'll try to send you a gif.

    If you were just to know who plays first every lap on the finish line, it would be easy. But it also shows the lap time and the total time count (sum of laps).

    It turns out that as the laps pass, a car that has a total time less than another, appears behind in the circuit, when it should appear in front.
     
  14. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Hey, so I don't want to have this topic to drag on forever, so this technique I stated earlier

    "If you need to get the placement of each car, one thing you could do is just make a very fine path, keep a "position" variable starting at 0 for each car. Then check every step if you're closest to the current position or the next coordinate on the path(using point_distance), and if you are, advance to the next position. And the cars are ordered by their position and if there's a tie, it's whoever had a shorter distance to the next position.

    You'd have to do some line intersection math if you wanted extra accuracy, that is determining the exact point your car would instersect the path if at a right angle to it. But you could also be lazy about this and just make your own line objects to do tests"

    Basically is the solution for 100% accuracy for ranking during a race. Not many other ways will work, they will fail in subtle ways randomly. If you aren't trying this, I would suggest doing this instead. You will need to do that complicated math getting the right angle instersection with the path so side-by-side cars give the correct ordering, or make some colliders to do the work for you.
     
    Last edited: Nov 26, 2019
  15. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    Okay, so if this gives me the positions of each car on the track and also a lap time and total time that coincides with the positions on the track car, it will serve me as a solution.

    I remember doing something like that, but not with multiple objects, only with the finish line. It served me until the races started to get longer and the faster cars started to make the slowest laggards.


    I think you can understand that if I want to make only a comparison with the time of each car, or just a comparison with the physical position of each car in the circuit, I can, without problems.

    The problem is when I try to put the two together.

    I will do the things you have recommended to me, and I will give feedback on what I have achieved.
     
  16. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Sounds good. The specific solution I gave isn't easy, so if you're having an issue with it I can take a look at that.

    I just don't think it serves us to work on half-working solutions atm given the complexity of the problem: if 100% accuracy is what you want, it's best to start on a design that will give that at this point.
     
  17. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    With his idea of calculating the distance between the car and the finish line when the two collide, I got great accuracy in the difference in lap times.

    Code:
    velocity=10.001-(car*0.001);
    All lap times would result in 285, but by increasing the distance divided by 10, the times will be different.

    [​IMG] https://imgur.com/a/GMcuB7Z

    But once again, over the course of several laps there was a difference from what appeared on the circuit and leaderboard.

    I am almost sure that now the detection of lap time is very accurate, since it is done on the car step plus the distance from the car to the finish line.

    Collision of the car with the finish line:

    Code:
    distance=point_distance(x,y,other.x,other.y);
    lapTime=timer+distance/10;
    timer=0;
    Each lap I add to a variable the time of the last lap. So that in the leaderboard, who has the shortest total time (sum of all lap times) appears first and so on.

    Collision of the car with the finish line:

    Code:
    distance=point_distance(x,y,other.x,other.y);
    lapTime=timer+distance/10;
    timer=0;
    timeTotal+=lapTime;
     
    Last edited: Dec 3, 2019
  18. Catastrophe

    Catastrophe Member

    Joined:
    Sep 22, 2019
    Posts:
    222
    Well, unless I'm mistaken, what you want is actually

    lapTime=timer-distance/10;
    not
    lapTime=timer+distance/10;

    Because you're essentially giving a discount for passing the finish line earlier in the frame. Overshooting by a wider margin means they finished with less "time"

    But it sounded like you also cared about rank during the race? If that's not the case, then disregard my last message.
     
  19. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    If I make this code:

    Code:
    lapTime=timer-distance/10;
    The result is reversed, which makes no sense.
     
  20. Genesys Generation

    Genesys Generation Member

    Joined:
    Feb 4, 2018
    Posts:
    13
    Doing some tests by changing the position of the finish line to a different location from the circuit origin, I found that the jump occurs at the origin of the circuit every time the cars cross it, not because the car collides with the finish line.

    It seems that I have found (due to your help) a way to correctly detect lap time.

    I think my problem now is another. I'll take a look at everything you posted and see if I can improve anything. Anyway, thanks and success.
     
    Catastrophe likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice