How to get a portion of a vector that is aligned with another vector

Godot Version

4.2.1.stable

Question

Hello!

I’m currently trying to create a little 3D racing-type game with boost gameplay elements. I’ve got the racer’s base velocity stored as a Vector3, and any additional boosts as a separate Vector3, which are added together to move the CharacterBody3D.

However, I’ve run into a little math problem I’m not sure how to solve. When my racer’s base velocity is lower than its arbitrary “max speed”, I want the boost vector to be “transferred” into the base velocity until “max speed” is reached. The problem is, the boost vector can be pointing in a different direction than the normal base velocity vector. So I can’t just directly transfer over a portion of the boost vector, especially if the boost vector is perpendicular to the racer’s base velocity.

How can I figure out how much of the boost vector to transfer over when the vectors can point in different directions?

You are correct that because the vectors point in different directions that you can’t simply add them together or perform regular vector maths. Instead you need to get a representation of the length of each vector as a float, do simple scalar calculations on these, then reapply the length to a normalised version of the original vector.

You can just call additional_boosts.length() to get the length of the additional boosts vector. It will return as a float. With that it doesn’t matter which direction it faces.

To transfer over some portion of this length (aka vector “magnitude”) you have to also get the length of the base_velocity.length(). Then you can decide to add some of the additional_boosts length to this length value.

To convert those adjusted lengths back to a vectors, you need to first normalise the original vectors. base_velocity.normalized() then simply multiply this unit vector (which points in the same direction but has a length of 1) by the length you calculated. Voila, you’ve adjusted the length of your base_velocity vector. You probably want to also adjust the length of the additional_boost with the length you subtracted from it too.

p.s. The title of your question can also be answered in a different way. i.e. how much of direction A is also pointing in direction B. However, I interpreted the content of your question to be about the length/magnitude of these vectors, regardless of their relative directions.

Thank you for your assistance!! Unfortunately, I think your secondary interpretation of my question is more accurate to my question: what portion of a vector is pointing in the same direction as another vector.

I feel like I’m getting close with using cos(velocity_vector.angle_to(boost_vector))… This gives me a value between -1 (opposite direction) and 1 (same direction), and perhaps combining this with your method above will give me something that feels “right”. Do you think I’m on the right track?

Sorry for bad formatting, I’m on mobile

You want to use a dot product to perform a projection of one vector onto another.

You and @ijidau have both halfs of the equation.

Ahh, I was worried I’d gone down the wrong interpretation. Sorry about that.

I’ve not tested this code, but done from memory of something similar. Try something like this:

var magnitude = additional_boosts.dot(base_velocity.normalized())
var boost_to_add = base_velocity.normalized() * magnitude
base_velocity += boost_to_add

Don’t worry about it, I did some tinkering, and I found a solution that feels really smooth.

func _transfer_boost_to_velocity(_maxSpeed):
	var _vlength = velocity_current.length()
	var _blength = boost_current.length()
	var _diff = cos(velocity_current.angle_to(boost_current))
	
	var _bportion = _blength * _diff
	
	if _diff > 0 and _vlength < _maxSpeed: #boost is moving generally in same direction as velocity
		_bportion = min(_bportion, _maxSpeed - _vlength)
		_vlength += _bportion
		_blength -= _bportion
	elif _diff < 0:
		_bportion = min(_bportion, _vlength)
		_vlength += _bportion
		_blength += _bportion
	
	velocity_current = velocity_current.normalized() * _vlength
	boost_current = boost_current.normalized() * _blength

Perhaps dot() would accomplish something similar, but, I’ll be honest, dot() and cross() are being difficult for my brain to wrap itself around. I wish the documentation was a little more explanatory and offered examples of what dot() would give in different situations. Oh well. Thanks for your help, all!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.