Community Forum

Vehicle Speed

Forum Overview >> Scripting

CategoryScripting
Created23.08.2018 20:36


Lukas Kruse (Unknown) 23.08.2018 20:36
Hi,
is there a way to get the speed (kph) of the vehicle currently driven by the player into a variable (Edit: in a LUA script Mod)?

I can't find anything with google and can't get GetLastSpeed from the Vehicle Class working, if that is the right function for me.

Bilbo Beutlin (BBeutlin) 23.08.2018 22:55
You mean a system variable which you can use in console command? No way.

You can only use XML files for data exchange. That means you have to write a custom LUA code which exports the desired FS variables to XML file where you can read it by an external program.

Lukas Kruse (Unknown) 24.08.2018 14:54
No, sorry for not mentioning it, i mean in a LUA script

Bilbo Beutlin (BBeutlin) 24.08.2018 16:20
ah - ok.
See lua docs -> Vehicles -> Vehicle .. as well as in specs like Motorized, Drivable, etc.
To get the speed "vehicle:getLastSpeed()" is used. For usage see code examples in cited LUAs.
'last' speed always because the speed is calculated as dl/dt (last covered distance divided by time).

Lukas Kruse (Unknown) 24.08.2018 17:23
Every time the function is called i get following error:
Error: Running LUA method 'draw'.
dataS/scripts/vehicles/Vehicle.lua(3824) : attempt to perform arithmetic on field 'lastSpeed' (a nil value)

This is the function i use:
function Test:draw()
local speed = tostring(0);
speed = tostring(Vehicle:getLastSpeed())
print(speed)
setTextColor(1, 1, 1, 1)
renderText(0.8, 0.25, 0.05, asciiToUtf8(speed .. " KM/H"))
end

Thank you in advance for your help ;)

Bilbo Beutlin (BBeutlin) 25.08.2018 00:52
Your function call "Vehicle:getLastSpeed()" is wrong.
You didn't examine the given examples, did you? Perhaps read a tutorial "LUA for rookies". ;)

You must call either by the 'self' construct "self:getLastSpeed()" - or if you have for example the vehicle 'vhcl', you call "vhcl:getLastSpeed()".

Gtx | Andy (GtX_Andy) 25.08.2018 03:30
Hey Lukas,

This is what you will need.

---------------------------------------------------------------------------------
function Test:draw()
-- Do you only want to 'render' when the engine is running??
if self.isMotorStarted then
-- We use 'math.max' so that we do not get a negative value.
local speed = math.max(0, self:getLastSpeed());
local measuringUnit = "KPH";

-- Get the correct 'measuringUnit' as set by the user.
if g_gameSettings:getValue("useMiles") then
measuringUnit = "MPH";
end;

-- Using 'g_i18n:getSpeed' will return the speed in MPH or KPH depending on the user setting.
local speedToDisplay = string.format("%1d - %s", g_i18n:getSpeed(speed), measuringUnit);

-- Unless you want the text bold then always make sure it is corrected in case another mod or Base Game has executed first in the stream
setTextBold(false);

-- Same as above with Colour
setTextColor(1, 1, 1, 1);

-- Keep in mind that rendering text without using 'getNormalizedScreenValues' and getting 'uiScale' first can mean that the text will be in different places on the
-- screen if other users have wide screens or different resolutions ;-)
renderText(0.8, 0.25, 0.05, speedToDisplay);
end;
end;
-------------------------------------------------------------------------------------------------------------

I have made some notes for you so you can see why I did each step.

Regards,
GtX

Lukas Kruse (Unknown) 25.08.2018 14:00
@BBeutlin
I tried both variants but none of them worked...

@GtX_LSMC
I copied your code but nothing happend ingame, so i commented out the "if self.isMotorStarted then"-part and added "print(speedToDisplay)" over renderText, but it only gave me the same error as before in the console log:

Error: Running LUA method 'draw'.
D:/lukas/Documents/My Games/FarmingSimulator2017/mods/Test/Test.lua:22: attempt to call method 'getLastSpeed' (a nil value)

I think the game doesn't connect the current vehicle with the "self" somehow.

Thanks for your awesome help so far!

Bilbo Beutlin (BBeutlin) 26.08.2018 01:11
To use "getLastSpeed()" it must be executed on a valid vehicle (table).
Your mentioned error indicates that it wasn't a valid vehicle.

With the "self:" construct you can only work from 'inside' the vehicle functions. Else you must at first get the 'pointer' to a vehicle and store it eg. in "vhcl". Then you can call "vhcl:getLastSpeed()". If it is drivable, you can read directly in the table "vhcl.lastSpeed".

Sorry - but I'm afraid your knowledge about LUA programming and FS scripting needs an update. ;)
Make it like all other scripters have begun - study the code in the script docs here and in the scripts of other people.

Gtx | Andy (GtX_Andy) 26.08.2018 02:23
Are you executing the code as part of a vehicle specialization?

Or are you just running the code when the game starts?

Is this a custom vehicle that will have the script running on it or are you trying to make this global for all motorised vehicles?

I did the above code on my laptop so I had not tested it. However I checked it in game today and it works for me.
So we need to work out how you are trying to execute it.

Lukas Kruse (Unknown) 26.08.2018 09:45
The code is executed when the game starts and should be global for all motorised vehicles.

My goal is to control a speedometer from an old car. The controlling of the speedometer itself isn't a problem for me. I only need to get the speed variable of the currently driven vehicle somehow.

Gtx | Andy (GtX_Andy) 26.08.2018 10:00
Then you either need to create your own specialization and then inject that into all 'drivable' vehicles or you could append / overwrite the Drivable:draw() function.

Executing the script at the start in the way you are doing it will not work as the game has no idea what you want it to do ;-)

Now when you say "operate speedometer from an old car" do you mean as an overlay on the screen or an animation in the vehicle itself?


Bilbo Beutlin (BBeutlin) 26.08.2018 12:05
From 'outside' a vehicle you can use this:
------------------
local vhcl = g_currentMission.controlledVehicle;
if vhcl ~= nil then
local mySpeed = vhcl.lastSpeed;

-- here comes your own code

end;
------------------
Take care: 'v.lastSpeed' is a raw value [length units / sec.] which you have to convert for display.
There is also a variable 'v.lastSpeedReal' which is directly calculated as 'v.lastMovedDistance/dt'.
However 'v.lastSpeed' is rounded and better for display reasons.
Read more in the docs.

If you want to implement an own display, it is more suitable to use a custom spec. which you add to all Drivable (as suggested).

Bilbo Beutlin (BBeutlin) 26.08.2018 14:24
btw:
You say, you want to implement a tachometer for your 'old car'.
Why at all do you want to write a custom LUA if you can easily use the given XML features in your vehicle.xml?
Simply copy a suitable display graphics from another car - or design your own. Then use the standard XML entries for animation.

Lukas Kruse (Unknown) 26.08.2018 14:48
With speedometer i mean a real-life speedometer from a real car controlled by an arduino.

I successfully appended my function to driveable.draw and everything worked but everytime drivable.draw was called i got this error in the log:

Error: Running LUA method 'draw'.
dataS/scripts/BaseMission.lua(2278) : attempt to call method 'draw' (a nil value)

It's basically no problem for me, i can see no problem in the game, but i think it's not the best solution when the log is spammed full with this...

This is my code:

function Test:drivabledraw()
if self.isMotorStarted then
local speed = math.max(0, math.floor(self:getLastSpeed()));
renderText(0.5, 0.5, 0.05, tostring(speed))
end;
end;

function Test:loadMap(name)
local drivable = SpecializationUtil.getSpecialization("drivable")
if drivable ~= nil then
drivable.draw = Utils.appendedFunction(drivable.draw, AnalogDash.drivabledraw)
end
end

Gtx | Andy (GtX_Andy) 26.08.2018 15:24
It would be best to create a new specialization and insert it into all 'drivable' vehicles.

Here is an example.

https://workupload.com/file/3gpHrK5u

Now you mention that you are going to send this data outside the game. If this is the case I am sure you understand that you will also need to code this program in C# or similar as FS/LS17 does not have support for software such as simHub at this stage.

You would also not use the 'draw()' function as this is only used when rendering to the screen as shown in my example.

You would need to send the data using the 'update(dt)' function

But actually taking the data from the game is a whole new level and it is something I have worked with in the past but I would not have the time to go into this amount of depth.. All the same the above link should get you started. ;-)

Cheers,
GtX

Lukas Kruse (Unknown) 26.08.2018 15:50
Awesome, works exactly like i wanted!

Thank you so much!

Bilbo Beutlin (BBeutlin) 26.08.2018 17:44
A word to your intention with external speedometer:
The FS LUA engine works in a 'sandbox' and even elementary LUA I/O operations on system level are not allowed. They are simply not implemented in the FS LUA engine.
To send datas from FS to external programs, there's at current merely the way with XML files. You'll need to code an "update" or "updateTick" function which writes the variable(s) into XML file which can be read by external program.
Also you should implement a 'timer' which doesn't write in all update cycles. Each 1/10 sec. should be sufficient. A massive XML traffic can slowdown the game as well as the external program if it must wait all XML write access.

Håvard Gjøsund (Unknown) 31.08.2018 21:13
Hi Lukas
would you mind sharing your work? i'm also looking for an external speedometer, but my knowledge of lua scripting is at a minimum. Arduino i can handle.

Thanks =)

-H


Note: Log in to post. Create a new account here.