Reputation: 23
I have a scene in godot where there is a missile at the origin of the plane and I have another scene where I have a static platform "hanging in the air", the platform has a Position2d as child object and my goal is to create the missile on the Position2d object and direct it to wherever the player is. I was able to instantiate the missile scene at runtime, but I don't understand how to direct it towards the player. At this point I have a doubt (as per the question) about the vectors: considering the point where the missile is instantiated on the platform (which is far from the origin of the plane), does the position vector of the missile start from the origin of the plane and end on the point where the missile is? Or does it start directly from the point of the missile and end up I don't know where? Can anyone give me some clarification on this?
Upvotes: 0
Views: 1151
Reputation: 40285
Side step the issue by working with global coordinates (global_position
and global_transform
).
Your vectors exist in a vector space. You should do your operation in the same vector space. The question is, in which vector space are your vectors?
While we are talking about the scene tree, the vector spaces are defined by the transform
of the nodes. So the position
of a node is respect to the origin of the parent node. In fact, the node exists in the vector space of the parent node, which may include rotation or scaling, for example.
Consequence of that, if you move a node, you also move all its children. If you rotate a node, you also rotate all its children, and so on.
You can also get transforms, and thus positions, relative to the origin of the scene tree. For that you use the global_transform
(and globa_position
). There are also helper methods to_local
and to_global
to convert between the two.
I have another scene where I have a static platform "hanging in the air", the platform has a Position2d as child object and my goal is to create the missile on the Position2d object and direct it to wherever the player is.
Since - I suppose - moving the platform should not move the missile. That is, the missile should move on its own, not attached to the platform. I'm going to suggest not making the missile a child of the platform. You can instance the missile and attach it to the scene tree root, for example. Or you may have a node dedicated for the purpose of holding the missiles.
Now, since you would be placing the missile as a child of a different node, let us work with global positions (and by extension with global transforms). Thus, ask the Position2D
for its global_position
(a.k.a global_transform.origin
), then tell the missile to set is global_position
to that:
missile.global_position = $Position2D.global_position
get_tree().get_root().add_child(missile)
By the way, if you are adding the missiles as children of the platform - which is ok as long as the platform does not move - you can still use global_position
for this purpose. However in that particular case using position
instead of global_position
has the same result. That is because the Position2D
and the missile would be siblings (have the platform as parent) and thus would be in the same vector space.
I was able to instantiate the missile scene at runtime, but I don't understand how to direct it towards the player
I strongly encourage having a script on the missile, where you can have a func
you call to aim it, and then you can work it out there. Note: I'm assuming this missile will not track the player. The signature is something like this:
func aim(target_position:Vector2) -> void:
pass
Then when you instance the missile, you can call aim
on it, passing the global_position
of the player:
missile.aim(player.global_position)
The position
of the player is relative to whatever the parent of the player is. And the missile, nor the platform are aware (and should not be aware) of what that is. So use global_position
instead. That is, since you as developer know what the parent node of the player is, you can hardcode that logic there. But then you would need to remember to change that if you decide to change where the player is in the scene tree. So just don't! Use global_position
.
In fact, let us rename the parameter:
func aim(target_global_position:Vector2) -> void:
pass
What do we need to do in that func
? We need to compute a direction. We can do that:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
_direction = global_position.direction_to(target_global_position)
Here we are figuring out the direction in global space (both vectors are in the same vector space, so we know this operation makes sense). Assuming there is no rotation or anything like that involved, this is ok. However, just to be sure, let us bring that to local space:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
_direction = to_local(global_position.direction_to(target_global_position))
By the way, just so you know, that is equivalent to this:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
_direction = global_transform.affice_inverse().xform(
global_position.direction_to(target_global_position)
)
And we might want to rotate the missile:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
_direction = to_local(global_position.direction_to(target_global_position))
rotation = _direction.angle()
Or we can do it like this:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
# …
rotation = get_angle_to(target_global_position)
Or like this:
var _direction:Vector2
func aim(target_global_position:Vector2) -> void:
# …
look_at(target_global_position)
Yes, both get_angle_to
and look_at
expect a global position.
Finally, you would want to move the missile. You can, for example, can use the direction to compute a velocity (multiplying the direction by the speed you want), and use that to move the missile.
Upvotes: 2