How to calculate the speed of a 3d node ?

Godot Version

v4.5.1

Question

I’m working on a VR game, and I’m having trouble calculating the speed of an object.

Without getting too much into the mechanics of the game I’m working on, let’s use a sword as an example.

The player holds the sword in their hand. When the sword collides with an enemy, damage should be dealt based on the force of the swing, which can be measured as the speed of let’s say, a node at the tip of the sword. If the player moves the sword slowly, no/minimal damage should be dealt to the enemy at the moment of collision, but a powerful, fast swing should deal a more significant damage.

In (my) theory, the speed at the moment of collision could be calculated by recording the position of the node in every frame, and in the frame, when the collision happens, the distance can be calculated from the previous position.

Here’s the code I tried (constantly printing out the speed)

func _ready() → void:
prevPositionX = testNode.global_position.x
prevPositionY = testNode.global_position.y
prevPositionZ = testNode.global_position.z

func _process(delta: float) → void:
distanceX = abs(testNode.global_position.x - prevPositionX)
distanceY = abs(testNode.global_position.y - prevPositionY)
distanceZ = abs(testNode.global_position.z - prevPositionZ)
speed = distanceX + distanceY + distanceZ
prevPositionX = testNode.global_position.x
prevPositionY = testNode.global_position.y
prevPositionZ = testNode.global_position.z
label_3d.text = str(speed)

This resulted in a constantly increasing number, with no relation to the speed of the node.

(Also, yes, I know what is a Vector3 and how to use it, I did it this way for testing purposes)

Then I asked ChatGPT for an answer, which was to include the time delta in the calculation:

func _ready() → void:
prevPosition = testNode.global_position

func _process(delta: float) → void:
var currentPosition = testNode.global_position
var distance = prevPosition.distance_to(currentPosition)
speed = distance / delta
prevPosition = currentPosition
label_3d.text = str(speed)

Which resulted in the exact same thing, except the number is increasing faster…

So, how do I do this properly ?

(P.S.: If it might matter: the entire playarea is in positive XYZ coordinates, as I had some trouble with calculations, when the coordinates were in the negative region)

How do you move testNode? Maybe its accelerating. It that case the speed would increase.

The testNode is a child of a VR controller node (a node added by the XRTools addon), and so it moves together with it.

Create a Vector3 called last_position, and a float called speed in the class. Every frame in _physics_process(), subtract the current global_position from last_position and then get the size of that Vector3 and assign it to speed. Then assign global_position to last_position. Then you can check speed anywhere and it will give you a relative speed measurement.

Also, don’t trust ChatGPT to code for you. It’s a random word generator. It is not intelligent and will make up code that doesn’t exist and doesn’t work.

Taking only one frame position difference ma be “to sensitive”. Calculate the speed this way for N last frames and average them.

1 Like

That’s fair. In which case I’d store the last 60 in a FILO stack so you have a second worth of data, and every frame pop off the last and add on the newest. Then when a collision happens, do the math with the stack getting the difference between the first and last item. That’ll give you relative speed over time.

1 Like