Python, help with velocity vector and force

Hello,

I would like to do this with python:

  • Get velocity vector of an object, and the speed.
  • Apply an force in the opposite direction of the velocity vector, depending on the speed and a constant k.

  • Apply the same force along the local x axis of the object.

Hi martin.hedin,

When I was studying your request I was wondering how you would be able to apply force on the local x axis when that force is calculated from the object’s speed (and velocity vector). Are we talking about falling objects here?

(I am actually talking about an helicopter :smiley: )

Basically we are talking about object that is moving arbitrarily.

I want two things:

  1. The unit vector of the movement, so that I can use this vector to apply a force (which would be in the opposite direction)

  2. The speed of the object, which would be the resulting linear velocity derived from the velocity vector. I would then use that value to apply a force to simulate drag. The combination of a force in the opposite direction of the velocity vector, and the same force in the direction of the forward direction of the object will simulate drag and change of direction. When you point the object away from its velocity vector the speed will slow down and the direction of the velocity vector will be changed by the resulting force, until the velocity vector and the orientation of the object line up, and the forces are cancelled out, and the speed is constant.

I am trying to figure out the code myself, and when I do I will post it here :wink:

I know I would be something like:

object.getLinearVelocity -> unitvector, speed

force = speed*k (k is an arbitrary constant)

object.applyForce((force*-1*unitvector), false) #false for global
object.applyForce((force*1,0,0), true) #true for local

I am not sure at the moment how to handle the result from getLinearVelocity.

To calculate the vector and speed I think this works:

from math import pow, sqrt

def getVecSpeed(own):
    vel = own.worldLinearVelocity
    speed = pow(vel.x,2) + pow(vel.y,2) + pow(vel.z,2)
    return vel.normalized(), sqrt(speed)

def main(cont):
    own = cont.owner
    vec, speed = getVecSpeed(own)

I could not get your code to work as it was but in the end I did this:

import bge
from math import pow, sqrt
from mathutils import Vector

def main():
    cont = bge.logic.getCurrentController()
    player = cont.owner
        
    vel = player.getLinearVelocity(False)
        
    powxyz = pow(vel.x,2) + pow(vel.y,2) + pow(vel.z,2)
    speed = sqrt(powxyz)
    
    k=1
    force = k*speed
    
    vecx = Vector((1,0,0))
    
    player.applyForce(k*-vel, False)
    player.applyForce(force*vecx, True)

main()

Thank you for your help!! :yes:

What this script basically does is to produce drag when the object is not coincident with the velocity vector. So in a sense it is a way of rotating the velocity vector, but with reduction of its magnitud.

Is there any way of rotating a velocity vector without reducing the speed? The rotation would be defined by the direction of the object, when it is not coincident with the velocity vector.

Hi, I have a question. Is applyTorque() broken? I can’t get it to work.

from bge import logic, events
from mathutils import Vector

moveSpeed = 10.0
turnSpeed = 0.1
gravity = 20

logic.setGravity([0, 0, gravity])

def getKeyMouse(own):
    key = logic.keyboard.events
    active = logic.KX_INPUT_ACTIVE
    up = key[events.UPARROWKEY] is active
    down = key[events.DOWNARROWKEY] is active
    forward = (key[events.WKEY] or key[events.ZKEY]) is active
    backward = key[events.SKEY] is active
    upDown = up - down
    forwardBackward = forward - backward
    return forwardBackward, upDown
        
def getVelSpeed(own):
    vel = own.worldLinearVelocity
    return vel, vel.magnitude

def getTranslation(own):
    mass = own.mass
    vel, speed = getVelSpeed(own)
    forwardBackward, upDown = getKeyMouse(own)
    force = forwardBackward * moveSpeed * mass + speed
    localMove = Vector((0, force, -gravity * mass))
    worldMove = -speed * vel
    turn = Vector((upDown * turnSpeed, 0, 0))
    return localMove, worldMove, turn

def translate(own, localMove, worldMove, turn):
    own.applyForce(localMove, True)
    own.applyForce(worldMove, False)
    own.localAngularVelocity = turn

def main(cont):
    own = cont.owner
    localMove, worldMove, turn = getTranslation(own)
    translate(own, localMove, worldMove, turn)

Changed the code to what I think you were aiming at. I replaced AKEY and DKEY with UPARROWKEY and DOWNARROWKEY.

I think I misunderstood what you were trying to do. But I noticed that multiplying -vel with speed is slowing it down. If you would just applyForce(-vel, False).

Check the documentation next time.
Vectors live in mathutils, and have a length (or magnitude, it’s the same) attribute.

I’m sorry, agoose77, I don’t understand what you are trying to say. Could you explain, please?

Edit: I think you mean you could use this attribute to calculate the speed?
Edit2: I’m sorry about that, martin.hedin, and thanks, agoose77!

I am not sure what this is supposed demonstrate? Did you try it in Blender? First of all the gravity is positive so you fall upwards, and then no keyes on the keyboard nor mouse respond. Could you give a short instruction what to do, and what result to expect?

I will try to ask more clearly;

How do you rotate a velocity vector without changing its magnitude?

The idea would be that the orientation of the object, when not coincident with the velocity vector, would make the velocity vector slowly line up with the orientation. (slowly = not instantaneously, but according to settings)

@Raco, I did not understand your code, nor did it work in Blender, but I am not sure if I set it up ok, please read above. http://blenderartists.org/forum/images/smilies/sago/eyebrowlift2.gif

You rotate a vector by multiplying it by the correct 3x3 rotation matrix. Check out the methods for
Matrix.Rotation(…). That creates a matrix that will rotate your vector and leave the length the same.


import math
from mathutils import Vector, Matrix

vec = Vector( (1, 0, 0, 0) )
rot = Matrix.Rotation(math.pi/2, 4, 'Z')

print(rot * vec)

That will take a vector point down the X axis (1, 0, 0) and rotate it 90 degrees around the Z axis so
it is pointing down the Y axis (0, 1, 0)

I’m sorry about the confusion. I just have an Always Sensor attached to a Python Controller, with Script Type set to Module: “Test.main”. I tried to find out what you were trying to achieve, but I’m still not sure about it. I posted it just for the purpose of testing. But maybe that wasn’t really necessary. Here’s the blend just to be sure. I hope I wasn’t wasting your time with this. I’m sure the info kastoria wrote will be more useful to you.

Attachments

Helicopter00.blend (80.2 KB)

Thank you for the help! I will look into your code a bit further, until then you can check out my little helicopter/airplane hybrid prototype.

I think these might be of help to you.

[TABLE=“width: 100%”]

alignAxisToVect(vect, axis, factor)

[/TABLE]
Aligns any of the game object’s axis along the given vector.
Parameters:

  • vect (3d vector.) - a vector to align the axis.
  • axis (integer.) - The axis you want to align
    [LIST]
  • 0: X axis
  • 1: Y axis
  • 2: Z axis (default)
  • factor (float) - Only rotate a feaction of the distance to the target vector (0.0 - 1.0)
    [/LIST]

[TABLE=“width: 100%”]

getAxisVect(vect)

[/TABLE]
Returns the axis vector rotates by the objects worldspace orientation. This is the equivalent if multiplying the vector by the orientation matrix.
Parameters:

  • vect (3d vector.) - a vector to align the axis.

Returns: 3d vector.The vector in relation to the objects rotation.

Thank you, this will be great for simulating forces when you are not pointing the aircraft in the direction it is going!