0
$\begingroup$

I'm trying to measure the angle of a moving boom and put that moving angle number into a window on-screen. What needs to be done to constantly measure that angle? Can this information be used in a property? This is in BGE, without animation.

$\endgroup$
1
$\begingroup$

Assumptions

I assume you have two objects - Object A and Object B.

You need to define what axis of what object you want to measure. Remember each object has three axis (X, Y and Z).

Example

I also assume you want to measure between the local Y axis at Object A (forward vector = [0,1,0]) and local Z axis at Object B (up vector = [0,0,1]).

I assume you have not turned the objects at all. This means initially the angle between the two axis is 90° (when you measure this should be the result).

Vectors in Space

To compare vectors you need to ensure they are given within the same space. Typically you convert both into scene space.

First you need to convert the local axis vectors from local space to scene space.

worldVector = object.worldTransform * localVector

Example

Imagine your object at the origin without rotation. The local forward vector is (0,1,0) facing towards the scene's background. The vector in scene space (world) is (0,1,0) too.

Now turn the object by 180°. The local forward vector is still (0,1,0), but the object is now facing the scene's foreground. The vector in scene space is (0,-1,0).

Formulas

The concrete formula for both vectors is:

import mathutils

forwardVector = mathutils.Vector((0,1,0))
upVector = mathutils.Vector((0,0,1))

objectAForwardVector = objectA.worldTransform * forwardVector
objectBUpVector = objectB.worldTransform * upVector

Example:

Object A is turned by 180°. Object B remains unchanged at the origin.

The vectors will be:

objectAForwardVector == (0,-1,0) # turned by 180°
objectBUpVector == (0,0,1)

Compare Vectors

As both vectors are now given in scene space we can perform operations on it. You wanted to know the angle between them:

angle = objectAForwardVector.angle(objectBUpVector)

Be aware the angle is calculated in radians. You need to convert it:

import math

angleInDegrees = math.degrees(angle)

Example

The final result will be:

angleInDegrees == 90°

Now turn object B by 90° around x. The new objectBUpVector is (0,1,0).

math.degrees(mathutils.Vector((0,-1,0)).angle(mathutils.Vector((0,1,0)))) == 180°

Be aware there is no negative difference. The result is always between 0 and 180.

Snippet

Start with the default scene (one cube). Add a text object. To the text object add an always sensor with True Level Triggering enabled. Connect the sensor with a Python controller that executes this script:

Demo

import bge
import math
import mathutils

UP_VECTOR = mathutils.Vector((0,0,1))
FORWARD_VECTOR = mathutils.Vector((0,0,1))

scene = bge.logic.getCurrentScene()
objects = scene.objects

cube = objects["Cube"]
camera = objects["Camera"]

cubeForwardVector = cube.worldTransform * FORWARD_VECTOR
cameraUpVector = camera.worldTransform * UP_VECTOR #the camera looks against the upvector!

angle = math.degrees(cubeForwardVector.angle(cameraUpVector))


textObject = bge.logic.getCurrentController().owner
textObject.text = "Angle: {:.0f}°".format(angle)

Now apply any logic to the cube that turns the cube (does not matter how). When you run the game p the text will show you the angle between the cube's forward vector and the vector the camera is facing against. This means when the cube's y-face is facing the camera you get 0°.

$\endgroup$
1
  • $\begingroup$ EXTREMELY complete answer...Thanks for your continuing help! $\endgroup$
    – Tom
    Feb 6 '18 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.