• 2D
  • Firing projectile at crosshair (Not mouse cursor)

Hi there I'm currently trying to learn Godot through remaking arcade/8&16-bit/classic era game mechanics, with much trial and error. The project I'm currently trying to make work is the shooting mechanics of Wild Guns (

) but I can't seem to get my bullet to fire towards my crosshair, it only fires to the right of its own spawn position. I assume the best way is to use a Raycast2d, which I'm not using currently, but even then I'm not sure how to set it's trajectory from the bullets spawn position to the crosshair centre. The crosshair, along with the player character, is controlled with WASD and is a child of the player and both have their own movement scripts. The bullet spawns from a Position2D which is named "Gun" and the crosshair has a centre point Position2D named "CrosshairCentre", I've tried a few things that I thought may change the bullet trajectory from the spawn but it either resulted in the bullets not spawning, firing to the right like before or just plain crashing.

Player script

extends KinematicBody2D

export (int) var speed = 200
var velocity = Vector2()
onready var bullet = preload("res://Bulit.tscn")
var b
onready var target = $CrossHair/CrosshairCentre

func shoot():
	if Input.is_action_just_pressed("fire"):
		b = bullet.instance()
		get_parent().add_child(b)
		b.global_position = $Gun.global_position
		
func move():
	velocity = Vector2()
	if Input.is_action_pressed("ui_right"):
		velocity.x += 1
	if Input.is_action_pressed("ui_left"):
		velocity.x -= 1
	if Input.is_action_pressed("fire"):
		speed = 0
	if Input.is_action_just_released("fire"):
		speed = 200
  
	velocity = velocity.normalized() * speed

func _physics_process(_delta):
	shoot()
	move()
	velocity = move_and_slide(velocity)

bullet script

extends RigidBody2D

var b_speed = 500

func _ready():
	apply_impulse(Vector2(), Vector2(b_speed, 0).rotated(rotation))
	scale = Vector2(.2, .2)

If anyone can help me or at least point me to somewhere that can I would very much appreciate it

EDIT: Fixed the formatting and updated some information.

  • i think the crosshair must have it own offset. if you set the crosshair like a child, it will follow the parent (player) offset.

    and maybe i would use a area2d instead rigidbody for the bullets, u dont need apply forces or gravitys here, only move and detect colisions.

    let u this for inspiration

    # PLAYER SCRIPT
    
    func _input(event):
    	if event.is_action_just_pressed("fire"):
    		shoot()
    
    func Shoot(): 
    	var spell = bullet.instance()
    	get_parent().add_child(spell)
    	spell.shoot(get_parent().get_node("Crosshair").global_position, $Gun.global_position)  # edit paths <--
    extends Area2D # BULLET
    
    var speed = 250
    var direction = Vector2()
    var pewpew = false
    
    func _process(delta):
    	if pewpew:
    		position += direction * speed * delta
    
    func shoot(crosshair_pos, gun_pos):
    	global_position = gun_pos
    	direction = (crosshair_pos - gun_pos).normalized()
    	rotation = direction.angle() # i think u dont need rotation here
    	pewpew = true
    
    func _on_Bullet_area_entered(area):
    	if area.is_in_group("Enemies"):
    		explode()
    	if area.is_in_group("Trains"):
    		anotherFunc()
    
    func explode(): 
    	speed = 0
    	$CollisionShape2D.set_deferred("disabled", true)
    	$AnimatedSprite.hide()
    	rotation = 0
    	$AudioExplo.play()
    	$AnimatedExplo.play() # in this case when animation finished, queue_free().  
    	# use a timer or some like that to queue_free and not accummulate hundreds of bullets in the limbo.

i think the crosshair must have it own offset. if you set the crosshair like a child, it will follow the parent (player) offset.

and maybe i would use a area2d instead rigidbody for the bullets, u dont need apply forces or gravitys here, only move and detect colisions.

let u this for inspiration

# PLAYER SCRIPT

func _input(event):
	if event.is_action_just_pressed("fire"):
		shoot()

func Shoot(): 
	var spell = bullet.instance()
	get_parent().add_child(spell)
	spell.shoot(get_parent().get_node("Crosshair").global_position, $Gun.global_position)  # edit paths <--
extends Area2D # BULLET

var speed = 250
var direction = Vector2()
var pewpew = false

func _process(delta):
	if pewpew:
		position += direction * speed * delta

func shoot(crosshair_pos, gun_pos):
	global_position = gun_pos
	direction = (crosshair_pos - gun_pos).normalized()
	rotation = direction.angle() # i think u dont need rotation here
	pewpew = true

func _on_Bullet_area_entered(area):
	if area.is_in_group("Enemies"):
		explode()
	if area.is_in_group("Trains"):
		anotherFunc()

func explode(): 
	speed = 0
	$CollisionShape2D.set_deferred("disabled", true)
	$AnimatedSprite.hide()
	rotation = 0
	$AudioExplo.play()
	$AnimatedExplo.play() # in this case when animation finished, queue_free().  
	# use a timer or some like that to queue_free and not accummulate hundreds of bullets in the limbo.

Thanks for the reply, I'll give it a try when I have some free time and update.

5 days later

Hey just updating to say that it seems to work, thankyou @Zelta

4 days later

I seem to be having an issue with bullets travelling through objects when they should clear, I know that this is due to the speed of the bullets but they do need to be fairly quick for this kind of game, plus the bullets kind of feel floaty. I'm thinking I may need to use a raycast instead would the process of aiming the raycast from a movable player to a movable crosshair be similar to this? I would assume I'd have to do something with the angle of the raycast? I do understand that I could just be missing something as I'm new to Godot/game dev in general.