0 votes

I wish for a RigidBody2D node to move to the mouse position. This is for the purpose of a fired projectile. The current code is contained below.

extends RigidBody2D

export (int) var PROJECTILE_SPEED

func _ready():
    pass

func primary_fire():
    var mouse_position = get_viewport().get_mouse_position()
    var projectile_direction = (get_parent().position - mouse_position).normalized()
    position = projectile_direction * PROJECTILE_SPEED

Currently the projectile appears at a position on the screen unrelating to the mouse position. Is there some issue with global vs local positions? Also it just appears rather than 'moves'. How would I induce a motion controlled by a velocity.

P.S. I'm using 3.0

Thanks in advance.

in Engine by (35 points)

3 Answers

+2 votes
Best answer

Here is the only thing you need to shoot your RigidBody at the mouse:

# projectile.gd
extends RigidBody2D

export var speed = 100.0

func shoot_at_mouse(start_pos):
    self.global_position = start_pos
    var direction = (get_global_mouse_position() - start_pos).normalized()
    self.linear_velocity = direction * speed

And for example, you would shoot it like this:

# shooter.gd
extends Sprite

func _input(event):
    if event is InputEventMouseButton:
        if event.pressed:
            var projectile = preload("res://projectile.tscn").instance()
            get_parent().add_child(projectile)
            projectile.shoot_at_mouse(self.global_position)

Also if you want to get rid of gravity you can set gravity scale to zero in your RigidBody.

by (28,731 points)
selected by

Thanks for the response. I will implement it tomorrow and hopefully understand it all a bit better.

Thankyou. This worked exactly as intended.

Why does the linear.velocity parameter require a self prefix?

The self prefix is optional, I added it to make it clear that this is a property of the node itself.

What is the purpose of placing startpos inside the shootat_mouse function brackets?

Also, how would I ensure the sprite for the projectile has the same rotation as the shooter sprite?

I assign start_pos in the shoot_at_mouse function but you could also do that in shooter.gd. You could even do everything in shooter.gd, depends if you like this or not in terms of code organization.

To orient the projectile you can use look_at:

func shoot_at_mouse(start_pos):
    var target_pos = get_global_mouse_position()
    self.global_position = start_pos
    self.look_at(target_pos)
    var direction = (target_pos - start_pos).normalized()
    self.linear_velocity = direction * speed
0 votes

I think it's because you get mouse position from viewport which is more like global position not relative to node.
but you get relative position of parent get_parent().position

try it with global position on both

var mouse_position = get_global_mouse_position()
var projectile_direction = (get_parent().global_position - mouse_position).normalized()
by (9,736 points)

Thanks for your response. The global addition doesn't make a difference. I changed:

position = projectile_direction * PROJECTILE_SPEED

to

position -= projectile_direction * PROJECTILE_SPEED

And that moved it in the correct direction of the mouse but only for the duration the LMB was held down and it would subsequently move beyond the mouse if held longer.

My aim is for it to travel in that direction on it's own after one press to collide with either an enemy or exit the screen.

0 votes

according to your question and comments on the other answer you want to be able to "shoot" the projectile but in your code you provide a new position to the projectile only when the primary_fire is active, you need to "animate" the movement or set a Velocity(im not used to working with rigidbodies so im not sure about the variable) so it will keep on moving and not just change the position once(or multiple time depending on the time the function is active) and you need it to have some sort of a function or a way to determine if it collided with something or if it flew off of the screen... i would recommend using an Area2D/3D and use the physics process to move the projectile along a line while setting the velocity in a 2d/3d vector in the _ready() function so you could just add the velocity times delta to get the new position... after setting the movement you can connect the method in the Area nodes of body_enter or something else it got there and check if the body is:
a) a player/ enemy
b) whatever you want it to collide with
and add a check if the position is way off screen by comparing it...

good luck with that anyway but sounds to me that you got really messed up in there

by (1,196 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.