How could I implement a reload system?

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

Hey there. So I’ve been searching and haven’t found a great answer for this questions.
Let’s say that in my game my character has 200 of total ammo which are divided in 10 rounds of 20 bullets, so if you shoot 20 times, you need to reload, and now you would have 9 rounds left.
How could I implement something like reloading having in mind the previous values?
Also, if I change the maximum limit of bullets in a round, let’s suppose that now it’s 9, then we could have an error, because the total amount of bullets is pair, while the limit of bullets in a round isn’t . How would you fix this?

Hi,
You’ve used the word rounds, when I think you mean magazines. As a round usually refers to a bullet.
For example, an AK-47, the standard magazine capacity is 30 rounds.

If I’m correct with that, could you re-write this line: Also, if I change the maximum limit of bullets in a round, let’s suppose that now it’s 9, then we could have an error, because the total amount of bullets is pair, while the limit of bullets in a round isn’t .
I don’t quite understand it.

deaton64 | 2020-07-13 15:25

:bust_in_silhouette: Reply From: deaton64

Hi,
I know you haven’t answered my question yet, but a simple ammo script could work like this:

extends Node2D

export var _magazines: int = 10 # how many magazines does the player have
export var _magazine_capacity: int = 20 # how many bullets in a magazine
var _current_magazine: int = 0 # track the bullets in the loaded magazine
var _have_ammo: bool = false # does the player have ammo?

func _ready() -> void:
	_reload() # load the gun for the first time


func _unhandled_input(event):
	# check for mouse down and shoot
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			if event.pressed:
				_shoot()


func _shoot() -> void:
	if _have_ammo: # only shoot if we have ammo
		_current_magazine -= 1 # take a bullet out of the magazine
		print("Bang!  Ammo left: ", _current_magazine)
		if _current_magazine < 1: # if we've used the last bullet, reload.
			_reload()
	else:
		print("out of ammo")


func _reload() -> void:
	if _magazines > 0: # if there are any magazines left, reload
		_have_ammo = true # we still have ammo
		_magazines -= 1 # but we have 1 less magazine
		_current_magazine = _magazine_capacity # reload the current magazine
		print("Reload - Magazines left ",  _magazines)
	else:
		_have_ammo = false # no more ammo

Hi! Im trying to add a timer to have like a cooldown to shoot before reloading. I dont find any place to use it whitout making reload impossible. I know that your post is ol, I will still apreciate help! Ty

Nicd5a | 2022-09-17 15:45

Hi,
I haven’t done any Godot for a while. I’m back now though on Godot 4.
Looking at the code I did, I went a bit overboard on underscores before variable names, as I thought that was best, as it makes them private. Now I’m not so sure.

Anyway, you need a bool to say if you can shoot or not. That needs to go in the shoot function. Set the bool so the player can’t shoot, and start the timer. When the timer runs out, set the bool so the player can shoot.

Like this (the timer is called shoot_delay:

extends Node2D

export var magazines: int = 4 # how many magazines does the player have
export var magazine_capacity: int = 4 # how many bullets in a magazine
var current_magazine: int = 0 # track the bullets in the loaded magazine
var have_ammo: bool = false # does the player have ammo?
var can_shoot: bool = true # can the player shoot

func _ready() -> void:
	reload() # load the gun for the first time


func _unhandled_input(event):
	# check for mouse down and shoot
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			if event.pressed:
				shoot()


func shoot() -> void:
	if have_ammo and can_shoot: # only shoot if we have ammo
		current_magazine -= 1 # take a bullet out of the magazine
		print("Bang!  Ammo left: ", current_magazine)
		can_shoot = false # don't let the player shoot until the timer runs out
		$"shoot_delay".start() # start the timer
		if current_magazine < 1: # if we've used the last bullet, reload.
			reload()
	else:
		if !have_ammo:
			print("out of ammo")
		elif !can_shoot:
			print("Waiting to shoot")


func reload() -> void:
	if magazines > 0: # if there are any magazines left, reload
		have_ammo = true # we still have ammo
		can_shoot = true # must be able to shoot after reloading
		magazines -= 1 # but we have 1 less magazine
		current_magazine = magazine_capacity # reload the current magazine
		print("Reload - Magazines left ",  magazines)
	else:
		have_ammo = false # no more ammo


func _on_shoot_delay_timeout() -> void:
	can_shoot = true

deaton64 | 2022-09-17 22:07

thanks mate, ill first try to make my code cleaner

extends KinematicBody

var damage = 10
const MAX_CAM_SHAKE = 0.3

export var _magazines: int = 3 # how many magazines does the player have
export var _magazine_capacity: int = 25 # how many bullets in a magazine
var _current_magazine: int = 15 # track the bullets in the loaded magazine
var _have_ammo: bool = true # does the player have ammo?

var speed = 10
var h_acceleration = 6
var air_acceleration = 1
var normal_acceleration = 6
var gravity = 20
var jump = 10
var full_contact = false
var reloadxd = false

var mouse_sensitivity = 0.06

var direction = Vector3()
var h_velocity = Vector3()
var movement = Vector3()
var gravity_vec = Vector3()

onready var head = $Head
onready var ground_check = $GroundCheck
onready var anim_player = $AnimationPlayer
onready var camera = $Head/Camera
onready var raycast = $Head/Camera/RayCast
onready var timer = $Timer
onready var timer2 = $Timer2

func _process(delta):
	$Control/RichTextLabel.text = str(_current_magazine)
	$Control/RichTextLabel2.text = str(_magazines)

func _ready() -> void:
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	_reload()
	
func _reload() -> void:
	if _magazines > 0: # if there are any magazines left, reload
		_have_ammo = true # we still have ammo
		_magazines -= 1 # but we have 1 less magazine
		_current_magazine = _magazine_capacity # reload the current magazine
		print("Reload - Magazines left ",  _magazines)
	else:
		_have_ammo = false # no more ammo

func _input(event):
	if event is InputEventMouseMotion:
		rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))
		head.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity))
		head.rotation.x = clamp(head.rotation.x, deg2rad(-89), deg2rad(89))
		
func fire():
	if Input.is_action_pressed("fire") and timer.is_stopped() and _have_ammo:
		if not anim_player.is_playing():
			camera.translation = lerp(camera.translation, 
					Vector3(rand_range(MAX_CAM_SHAKE, -MAX_CAM_SHAKE), 
					rand_range(MAX_CAM_SHAKE, -MAX_CAM_SHAKE), 0), 0.5)
			if raycast.is_colliding():
				var target = raycast.get_collider()
				if target.is_in_group("Enemy"):
					target.health -= damage
					anim_player.play("Assault Fire")
			if _have_ammo: # only shoot if we have ammo
				_current_magazine -= 1 # take a bullet out of the magazine
				print("Bang!  Ammo left: ", _current_magazine)
		if _current_magazine < 1: # if we've used the last bullet, reload.
			_reload()
			
			camera.translation = lerp(camera.translation, 
					Vector3(rand_range(MAX_CAM_SHAKE, -MAX_CAM_SHAKE), 
					rand_range(MAX_CAM_SHAKE, -MAX_CAM_SHAKE), 0), 0.5)
			if raycast.is_colliding():
				var target = raycast.get_collider()
				if target.is_in_group("Enemy"):
					target.health -= damage
		anim_player.play("Assault Fire")
		
	else:
		camera.translation = Vector3()
		anim_player.stop()
		
func _physics_process(delta):
	
	fire()
	
	direction = Vector3()
	
	full_contact = ground_check.is_colliding()
	
	if not is_on_floor():
		gravity_vec += Vector3.DOWN * gravity * delta
		h_acceleration = air_acceleration
	elif is_on_floor() and full_contact:
		gravity_vec = -get_floor_normal() * gravity
		h_acceleration = normal_acceleration
	else:
		gravity_vec = -get_floor_normal()
		h_acceleration = normal_acceleration
		
	if Input.is_action_just_pressed("jump") and (is_on_floor() or ground_check.is_colliding()):
		gravity_vec = Vector3.UP * jump
	
	if Input.is_action_pressed("move_forward"):
		direction -= transform.basis.z
	elif Input.is_action_pressed("move_backward"):
		direction += transform.basis.z
	if Input.is_action_pressed("move_left"):
		direction -= transform.basis.x
	elif Input.is_action_pressed("move_right"):
		direction += transform.basis.x
	
	direction = direction.normalized()
	h_velocity = h_velocity.linear_interpolate(direction * speed, h_acceleration * delta)
	movement.z = h_velocity.z + gravity_vec.z
	movement.x = h_velocity.x + gravity_vec.x
	movement.y = gravity_vec.y
	
	move_and_slide(movement, Vector3.UP)

Nicd5a | 2022-09-19 03:12