Problems with area2d, on_body_entered, shooting

Godot Version

Godot Engine 4.3 stable

Question

I have a problem with collisions. I am begginer and i tried looking for reason but project and code logic seems good to me so i will try to shorten project:
For practice i started working on shooter game. I used shooting mechanic from some youtube video and it looks like this:

extends CharacterBody2D
@export var playerammo = false
@onready var main = get_tree().get_root().get_node("Main")
@onready var projectile = load("res://Bullet.tscn") #Bullet, i will put its code after this
const bulletpath = preload("res://Bullet.tscn") #bullet also.. but not sure about its use
@export var speed: float = 500
@export var accel: float = 50
var Amunicja = 0
var MaxAmmo = 30
var reload = false
@onready var rtl = $"../CanvasLayer/RichTextLabel"
var rng = RandomNumberGenerator.new()
@onready var tr = $"../CanvasLayer/TextureRect"
@export var is_player: bool = true #for some other script

func _process(delta):
	#follow cursor
	look_at(get_global_mouse_position())
	#reload/shoot     reload was made by me but it seems to be working
	if reload == false:
		if Input.is_action_just_released("strzal"):
			if Amunicja > 0:
				Shoot()
			else:
				if MaxAmmo > 0:
					reload = true
					asp2.play()
	
	if Global.plusAmmo > 0:  #bullet pickup, maybe a bit stupid but thats how i saw it in my head.
		MaxAmmo = MaxAmmo + Global.plusAmmo
		Global.plusAmmo = 0
		rtl.text = "Amunicja: " + str(Amunicja) + "/" + str(MaxAmmo)

func _physics_process(delta):  # translated:  ...get_vector(left,right,up,down)
	var direction: Vector2 = Input.get_vector("W lewo", "W prawo", "W gore", "W dol")
	velocity.x = move_toward(velocity.x, speed * direction.x, accel)
	velocity.y = move_toward(velocity.y, speed * direction.y, accel)
	move_and_slide()

func Shoot():
	var instance = projectile.instantiate()

# Ustawienia przesunięcia
var offset_distance = 40  # Odległość od postaci, dostosuj do swojej gry
var offset = Vector2(cos(rotation), sin(rotation)) * offset_distance

# Setting position with offset
instance.dir = rotation + deg_to_rad(90)   #Invalid set index 'dir' (on base: 'CharacterBody2D') with value of type 'float'.
instance.spawnPos = global_position + offset
instance.spawnRot = rotation + deg_to_rad(90)
Amunicja -= 1
main.add_child(instance)
asp1.play()
rtl.text = "Amunicja: " + str(Amunicja) + "/" + str(MaxAmmo)

func _on_audio_stream_player_2_finished():
	reload = false
	Amunicja += 6
	MaxAmmo -= 6
	rtl.text = "Amunicja: " + str(Amunicja) + "/" + str(MaxAmmo)

Here is Bullet:

extends CharacterBody2D
var dir : float
var spawnPos : Vector2
var spawnRot : float
@export var speed = 1000
@export var playerammo = true

func _ready():
	global_position = spawnPos
	global_rotation = spawnRot

func _physics_process(delta):
	velocity = Vector2(0, -speed).rotated(dir)
	move_and_slide()
  1. And there are a few problems. On position 0,0 is area2d detecting Bullets (destroyable object) but area triggers every time i click shoot button. I set up print to see it.

  2. If i shoot bullet at any object and it will miss, and fly forever. Sometimes(not always idk why) (the area2d that is supposed to detect bullet, print message and delete bullet) bullet passes through not triggering anything. Area2D uses on_body_entered, then checks name of the bullet and if its name is correct and then does rest of code. I tried checking layers and masks and all are good. i also have on project tileset(if that changes anything) as background. If any more information or code is needed, text and i will send it, cuz i want to learn godot and this is wall i hit.

  1. To delete a bullet when its been flying to long you can add a timer to the bullet scene:
    Bullet.gd
func _ready():
    global_position = spawnPos
    global_rotation = spawnRot
    
    await get_tree().create_timer(10).timeout
    queue_free()

This code will delete the bullet after 10 seconds have passed since its been spawned

  1. checking for the name is not a good solution, since siblings in the scene tree cant have the same name, which leads to the second bullet being spawned to have a differenct custom name.
    A solution would be to give the bullet a class_name and check for it:
    Bullet.gd
class_name Bullet extends CharacterBody2D

And in your body_entered-method:

func _on_body_entered(body):
    if body is Bullet:
        # put your bullet entered code here
2 Likes

I ended up placing the collision code in the rocket:

	if body.is_in_group("tanks"):
		global.score += 10
		tank_anim.play("bang")
		await get_tree().create_timer(0.2).timeout
		body.queue_free()
		queue_free()

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