How would I code a projectile to fire towards the mouse?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By BCritchfield

Hello! It’s my first time posting in this forum, so sorry if I muck anything up.

I’ve recently started learning GDScript about a month ago, and aside from GameMaker 2’s language, its the first language I’ve really gone in depth to try and learn.

While there are very few tutorial channels out there, but those that make videos are very dedicated, however I haven’t found a tutorial video for specifically what I’d like to do:

Conceptually it’s fairly simple, I’ve created a character and a gun sprite and have coded the gun sprite to face towards the mouse at all times. What I want to do now is make it so that when you click the mouse button, it fires a bullet towards wherever the mouse is.

For whatever reason… I just cannot figure this out. Any help, however simple, would be hugely appreciated. Thank you.

Rather than look for a tutorial that shows exactly what you want to do, you should strive to understand the concepts - then you can make anything you need.

Firing a bullet towards the mouse can be broken down into two (and a half) pieces:

  1. Find the direction vector from the gun to the mouse.
  2. Instance a bullet.
    2a) Point the bullet in the given direction and let it go.

It’s hard to answer your question because you may actually be asking multiple questions.
It seems like you’ve done #1 since you can point the gun towards the mouse. For #2, have you made a bullet scene? If so, how have you set it up? With a properly set up bullet, #2a should be as easy as passing it the direction from #1.

There’s some example code in the docs here for one approach to the problem:
Instancing with signals — Godot Engine (latest) documentation in English

kidscancode | 2019-12-02 02:55

Hi! Thank you very much for replying. I didn’t expect such a quick response, especially from such a big Godot channel.

Thanks a ton for the link to the instancing example. I followed it, and seem to keep getting the following error: Invalid get index “velocity”. The game freezes and won’t let me interact with it when this happens… it only happens when I press the mouse button to fire the bullet. Any suggestions as to why I can’t access the velocity value?

BCritchfield | 2019-12-02 03:50

Did you define a velocity variable in your bullet’s script?

kidscancode | 2019-12-02 04:37

Hello again, I did define a velocity variable. I followed the code exactly, and the current issue is that instead of the bullets firing towards my mouse, they simply appear at my cursors location.

Here is my player code:

extends Sprite

signal shoot(bullet, direction, location)

var Bullet = preload("res://Bullet.tscn")

func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
            emit_signal("shoot", Bullet, rotation, position)

func _process(delta):
    look_at(get_global_mouse_position())

func _on_Sprite_shoot(bullet, direction, location):
    var b = Bullet.instance()
    add_child(b)
    b.rotation = direction
    b.position = location
    b.velocity = b.velocity.rotated(direction)

And in the bullet:

extends Area2D

var velocity = Vector2.ZERO

func _physics_process(delta):
    position += velocity * delta

Really sorry for all the questions, thank you for the help!

BCritchfield | 2019-12-02 16:57

In that example, the “shoot” signal was supposed to be connected to your “Main” scene, which is where the _on_Sprite_shoot() should be. Your code is making the bullet the child of the player, so its position isn’t going to be at the player, but offset by whatever position is at the time.

You don’t have to use a signal. You can just do get_tree().get_root().add_child(b). But you want the bullet’s global_position to be placed at the players position.

kidscancode | 2019-12-02 19:49

Thanks again, my mistake on that one. It is now creating the bullet at the players location, but the bullet just sits there.

My code is the same except the “Shoot” signal is in my main scene node:

extends Node

var Bullet = preload(“res://Bullet.tscn”)

func _on_Player_shoot(bullet, direction, location):
var b = Bullet.instance()
add_child(b)
b.rotation = direction
b.position = location
b.velocity = b.velocity.rotated(direction)

I’m sure it seems like I’m floundering around with something simple, but I appreciate the help

BCritchfield | 2019-12-02 21:51

:bust_in_silhouette: Reply From: lightspot21

Welcome! I’m also a former GM:S user :slight_smile:

Is this your bullet code?

extends Area2D

var velocity = Vector2.ZERO

func _physics_process(delta):
    position += velocity * delta

Notice the velocity vector. It’s set to zero and never updated (delta times the zero vector equals the zero vector) so the bullets stay still. Change it so that the velocity is being updated (also consider using normalize() and a separate constant for frame-independent animation. Something like this:

var direction: Vector2
var speed: int = 10

func _process(delta):
    position += direction.normalize()  * speed * delta

Also, that’s a bit unrelated, but I noticed you use look_at(get_global_mouse_position()) to get your mouse’s position. There is a cleaner way to do this, which needs a bit of a readup about the Input workflow on Mouse and input coordinates — Godot Engine (3.1) documentation in English, and especially on the part regarding InputEventMouseMotion.

Good luck!