Too Many bullets (How do I slow it down?)

Godot Version

Godot 4

Question

I want my player to throw snowballs (bullets) as long as they are moving. That’s working.

But there are so many snowballs. How do I slow it down to 2 snowballs a second?

Currently, I’m trying to instance the snowball after some time has passed, but that doesn’t seem to have any affect.

extends Sprite2D

@export var speed : float = 350

@export var joystick_left : VirtualJoystick

@export var snowball : PackedScene

var move_vector := Vector2.ZERO
var screen_size


#get window size so we can use it later to stop player at window edge.
func _ready():
	screen_size = get_viewport_rect().size

#movement
func _process(delta):
	# Movement using the joystick output:
	if joystick_left and joystick_left.is_pressed:
		position += joystick_left.output * speed * delta
		position = position.clamp(Vector2.ZERO, screen_size)
		rotation = joystick_left.output.angle()
		
		#throw snowballs
		var sb = snowball.instantiate()
		sb.global_position = $SnowballSpawn.global_position
		sb.rotation_degrees = rotation_degrees
		
		#slow down the throwing
		var count = 1
		var cooldown = 1
		
		if count < cooldown:
			count += delta * 0.0005
		else:
			get_tree().root.add_child(sb)
			count = 0

You could use a global variable t to record the last time you create a bullet, and every “_process()” add delta to it, for example, only t > 0.5s you will create and add_child a bullet.

let me try code it without opening godot, try this:

var is_throwing:bool=false
var allow_throw:bool=false
var cooldown=0
const RELOAD_TIME=0.5


#movement
func _process(delta):
	# Movement using the joystick output:
	if joystick_left and joystick_left.is_pressed:
		if not allow_throw:
			allow_throw=true
			cooldown=RELOAD_TIME
		position += joystick_left.output * speed * delta
		position = position.clamp(Vector2.ZERO, screen_size)
		rotation = joystick_left.output.angle()

	elif joystick_left and joystick_left.is_released:
		if allow_throw:
			allow_throw=false
			cooldown=0

	if allow_throw:
		cooldown-=delta
		if cooldown>0:
			if not is_throwing:
				is_throwing=true
				#throw snowballs
				var sb = snowball.instantiate()
				sb.global_position = $SnowballSpawn.global_position
				sb.rotation_degrees = rotation_degrees
				get_tree().root.add_child(sb)
		elif cooldown<=0:
			cooldown=RELOAD_TIME
			is_throwing=false

The Timer node is very useful for this sort of behaviour. You can add one which emits a signal every 2 seconds. Start the timer when the player is moving, and stop it when they are not. Connect a throw_snowball function to the timer’s timeout signal.

For example:

func _ready() -> void:
  $Timer.timeout.connect(throw_snowball)

func _process(delta: float) -> void:
  ...
  if is_moving:
    $Timer.start()
  else:
    $Timer.stop()

func throw_snowball() -> void:
  var sb = snowball.instantiate()
  sb.global_position = $SnowballSpawn.global_position
  sb.rotation_degrees = rotation_degrees
  get_tree().root.add_child(sb)

Also because the joystick is an input, try use func _input(event): instead. dont put input event on _process (best practices).

This pretty much worked.
I just had to change

elif joystick_left and joystick_left.is_released:
		if allow_throw:
			allow_throw=false
			cooldown=0

to

	elif allow_throw:
		allow_throw=false
		cooldown=0

Thank you!

1 Like

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