How to work out object speed in game?

Hi all,

This sounds really silly but how do you work out how fast an object is moving? I want to make an on screen indicator (a bar) that shows the thrust and speed of a vehicle.

At the minute I have an animated IPO that shrinks/ extends a cube when the accelerator is pressed, but how do I synchronize that to a motion actuator (in this case a servo) so it shows something meaningful?

Cheers

Paul

This is only possible via Python.

KX_GameObject.getLinearVelocity(local=0)

You will get a the speed along the three axis.
Now calculate the length of of the resulting vector and you get the speed:


speed = Vector(gameObject.getLinearVelocity()).magnitude

I think in 2.5x you already get a Vector.

I hope it helps
Monster

Iā€™m starting to learn Python so bear with me:

KX_GameObject.getLinearVelocity(local=0)

what do I do with this part? I assume the local=0 is a Boolean, with local =1 giving local speed (which I need?).

ā€˜Speedā€™ is the variable, and is the product of ā€˜Vector(gameObject.getLinearVelocity()).magnitudeā€™?

What does the .magnitude part do, and how do I specify the forward axis (e.g. -Y or +X)? Is this specified in the .getLinearVelocity() brackets like .getLinearVelocity(x)?

Once I have the speed variable I can then use that to animate the IPO?

Iā€™m sorry for being a bit thick, I really want to get my head around Python.

Cheers

Paul

Speed.py:


try:
  from Mathutils import Vector
except ImportError:
  from mathutils import Vector
 
def speedToValue(cont):
  if not onePositive(cont):
    return
 
  own = cont.owner
  speedVector = Vector(own.getLinearVelocity())
  speed = speedVector.magnitude
 
  for actuator in cont.actuators:
    try:
      actuator.value = str(speed)
    except AttributeError:
      continue
    cont.activate(actuator)
 
def onePositive(cont):
  for sensor in cont.sensors:
    if sensor.positive:
      return True
  return False

use a sensor of your choice (e.g. an Always sensor)
connected to
a Python controller in Module Mode: Speed.speedToValue
connected to any number of actuators

  • if it is an Property actuator the value field will be filled with the speed and the actuator will be activated. The property actuator will copy the new value to the configured property (dependent on the mode). All other actuators will be ignored.

Example:

Property (any type): Speed

Always sensor TRUE Pulse
ā€”> Python Module: Speed.speedToValue
-------> Property actuator Mode: Assign Prop: Speed Value: empty
if you switch on proeprty debug, you can see the speed in the debup overlay ;).

I hope it helps
Monster

1 Like

Nice! Thanks for taking the time to write that! A couple of questions though:

I get an error ā€˜import error- no module called speedā€™. I am not that familiar with module mode: I have created an external text file with a .py extension and copied your script into it, is that how it works?

Also, the numbers that get created (the velocity), what units are they in, are they meters/sec? And, do the various methods of motion (dloc/linear/servo etc) result in the same speed output (i.e. same units)?

Many thanks!

Paul

Cheers

Paul

if you create the text file in the blender text editor, and call it ā€œspeed.pyā€ lowercase, it will work.

Still no joy, am I making a schoolboy error somewhere?

Also, I managed to kludge a script together that displays the speed (not so advanced as yours though!). When the speed is displayed it just continues to increase. The only way to cap the speed is to use linear velocity. Heres the code:


import GameLogic

controller = GameLogic.getCurrentController()
object = controller.owner

Xspeed, Yspeed, Zspeed = object.getLinearVelocity(False)

linSum = Xspeed 

xValue = linSum

#print (linSum)

object['speed'] = xValue

Thanks for the help!

Paul

Attachments

speed.blend (434 KB)

Nearly right ;).

You run scripts by entering the filename
You canā€™t run modules, but you call members/functions of the module. So you write the moduleName.functionName.

In this case when you called your file speed.py:

Module: speed.speedToValue

without the () as you would do when calling from Python code.

If you have another filename than use this name without the .py part. If it has no .py it canā€™t be recognised as module.

The BGE does something like this for you already:


import moduleName
moduleName.functionName( currentController )

it is BU/s

because 1 BU = 1 meter you can assume it is m/s.

yes.

You could do it by yourself, by storing the position of the object. At the next tick you calculate the difference between the new position and the old one. Than you divide this by the time since you stored the last position.

But it is much easier to use getLinearVelocity().

BTW.
your script calculates a part of the speed which is projected on the X axis. This is not necessarily the right speed as the object might move up/down or left/right. These motion will be ignored when you look at one axis only. But in certain situations this can be the value that you want. Especially if you want to see negative speed.

The speed value is the length of the velocity vector.
The length of a vector is sqrt(x^2+y^2+z^2) which is already provided by vector.magnitude ;).

I hope it helps
Monster

Thanks again Monster- you explained it really well, and I got it working! As far as my script, it did calculate x,y and z but I started playing with it and see what makes things tick, as I want to make a script that sets the linear velocity on the (local) x-axis to a certain speed, but keeping the speed on other (local) axises.

And I still get the infinite acelleration problem- if I set the motion acuator the speed will go up. The only way round it is to use linV. Any tips on this?

Many (many!) thanks

Paul