Page 1 of 1

Calculating maximum vehicle speed

Posted: Tue Jun 02, 2020 8:24 am
by Pi-C
Given a entity based on the "car" prototype, is there an easy way to calculate its maximum speed based on the data that can be read from entity an entity.prototype in the control stage? In the Wiki, the top speeds of vanilla cars are listed by terrain (which affects friction) and fuel. We have constants like weight, friction_force, consumption, and effectivity that are stored in car.prototype. We also can read consumption_modifier, effectivity_modifier, and friction_modifier that, I assume, are variable. But what do they mean? Is car.friction_modifier the same as TilePrototype.vehicle_friction_modifier, or would I have to read the tile under car.surface.position if I want to account for the terrain? What is the secret formula that was used to calculate the speeds given in that table on the Wiki? I can't seem to figure it out, so help would be appreciated. :-)

Re: Calculating maximum vehicle speed

Posted: Tue Jun 02, 2020 8:27 pm
by Rseding91
What's the use-case? Because unless you have a *really* good one my recommendation is to "just don't".

Re: Calculating maximum vehicle speed

Posted: Tue Jun 02, 2020 9:51 pm
by Pi-C
Use-case is Autodrive. It currently applies a limit of 100 to traveling speed. I've got a complaint that this would be too slow for a plane from the Aircrafts mod which could go close to 300. So, the idea was to let the traveling speed depend on the maximum speed possible with that prototype, and then I thought about accounting for terrain and fuel as well. Prototype data are stored along with the vehicle data, by the way, so I'd only have get the latest entity data for each calculation.

Re: Calculating maximum vehicle speed

Posted: Wed Jun 03, 2020 12:13 am
by valneq
If the game behaves anything like physics, you "only" need to calculate the velocity at which the deceleration from friction equals the acceleration from your fuel. I don't know how the individual modifyers affect these values in the game, so I cannot really help you … but I wish I could :-/

Re: Calculating maximum vehicle speed

Posted: Wed Jun 03, 2020 7:17 am
by darkfrei
Here is very soft limit, see viewtopic.php?p=309694#p309694

Re: Calculating maximum vehicle speed

Posted: Mon Jun 08, 2020 6:38 am
by Pi-C
Thanks!

While browsing the mod's discussion board, I've found this thread where somebody provided some code for calculating the maximum speed. This was posted several weeks before I even started to collaborate on Autodrive, that's why I didn't see it before. :-)

I adapted the code this way:

Code: Select all

-- Modded vehicles (e.g. the jet from "Aircraft") may have insane speeds, so we limit the top speed to a reasonable value
-- (anything faster will lead to strange quirks)
local SPEED_CAP = 300

  -- state{} contains the entity state.car and additional data related to that entity
  local vehicle = state.car			-- entity
  local p = vehicle.prototype		-- entity.prototype

  -- Setup defaults (to be replaced with real values later on, perhaps)
  local fuel_speed_modifier = 1
  local sticker_speed_modifiers = 1
  local sticker_friction_modifier = 1

  local tileUnderVehicle = vehicle.surface.get_tile(vehicle.position)
  -- vehicle_friction_modifier of each tile will be stored in a local table in the future so we don't have to poll prototype data each time
  local tile_friction_modifier = tileUnderVehicle.prototype.vehicle_friction_modifier

  -- raw_acceleration_eng_per_tick can be stored because all values used in the calculation are constant prototype data 
  if not state.raw_acceleration_eng_per_tick then
    state.raw_acceleration_eng_per_tick = (p.consumption * vehicle.consumption_modifier) * 
                                                                        (p.effectivity * vehicle.effectivity_modifier) * 
                                                                        p.burner_prototype.effectivity
  end

  -- Store constant values with vehicle so prototype data will have to be polled only once
  state.terrain_friction_modifier = state.terrain_friction_modifier or p.terrain_friction_modifier
  state.friction_force = state.friction_force or p.friction_force
  state.friction_modifier = state.friction_modifier or vehicle.friction_modifier
  state.weight = state.weight or p.weight

  -- This can't be stored because tile_friction_modifier and (in the future) sticker_*_modifiers will vary
local friction_modifier = (1 - state.friction_force *
                	                        (1 + state.terrain_friction_modifier * (tile_friction_modifier - 1) ) *
                                                 state.friction_modifier * sticker_friction_modifier
                                         )
local  acceleration_eng_per_tick = state.raw_acceleration_eng_per_tick * fuel_speed_modifier * sticker_speed_modifiers
lcoal  max_energy = acceleration_eng_per_tick * friction_modifier ^ 2 / (1-friction_modifier ^ 2)

local  max_speed_tiles_sec = math.sqrt(max_energy/0.5/state.weight)
local  max_speed_kph = max_speed_tiles_sec * 3.6

local max_speed = max(SPEED_CAP * -1,  min(SPEED_CAP, max_speed_kph))
Using this, I can determine a vehicle's maximum speed on the terrain it's currently driving at, and accelerate if the current speed is lower, brake if it's higher, or coast if it's about the same. Now I need to find out when I have to start braking if a waypoint (final destination or turn of direction) is near.

Until now, this was used:

Code: Select all

  local waypoint = state.path[1].position
  local range = distance(waypoint, car.position)

  -- Adjust speeds
    if range > 8 or rails then
      speed = 100
    elseif range > 4 then
      speed = 50
    end
[…]    
    if range < 0.5 then
      brake(state)
    end
The same speeds were applied to all vehicles, so using constant values for range kind of worked. Now I'll need to calculate range based on a variable driving speed. This should be possible using information from the old thread darkfrei has linked to. However, there's one complication: I need to find a suitable minimum speed that won't slow down the vehicle to a crawI (some mods introduce incredibly fast vehicles, others vehicles that are very strong but have a rather low maximum speed) if there are several short path segments in a row, so the distance between two waypoints is less than the distance where vehicles start to slow down (with the old code: range <= 4). Applying an arbitrary limit like

Code: Select all

speed_min = speed_max / x
may work with long, straight paths, but can result in an intolerably low traveling speed on a zigzag course. (Unfortunately, the pathing isn't optimal, so vehicles often make a detour although there would be a shorter straight path over better terrain. I haven't figured out yet how it works, so I'll have to make the best of the current situation.)
Any ideas how to deal with that? :-)