Separate the gun from the player

Godot Version

4.3

Question

hi huys I hope you have a great day well I have problem with the gun I added a sprite2d that is gun and in front of ut i added some marker 2d and I said whenever I press the shoot from selected marker you should shoot the bullet i added the timer so after some specific time can shoot and it worked but I've heard that it's better that you don't write the code for gun inside the player.gd and I should make a main gun that other guns extends from it for switching. so I was wondering how can I separate the gun code from the player code cuase I gave scene to the gun and chose the character body 2d to it but somehow it wasn't a great idea I would be happy if you could help me and oh my game is( topdown 2d ) thanks

It is difficult to answer the question precisely when I don’t know how you want the gun to function.

However, assuming you have a situation where you can equip different guns that have different damage this is one direction to set it up.

Player →
MainGun

#player script

func _physics_process(delta):
If Input.is_action_pressed("shoot"):
# if guns have a variable shoot speed add
If $MainGun.is_ready:
$MainGun.shoot(facing_direction) #pass parameters necessary

#maingun script

var is_ready = true
var fire = false
var dir_of_fire : Vector2

func _physics_process():
If fire:
Is_ready = false
fire = false
start_timer()
# how are you handling bullet or attack, is it instant or does it travel? 
# you can instantiate a bullet scene here
# pass the damage of equiped gun

func equip_gun():
#this is where you would handle swapping guns

func shoot(dir):
dir_of_fire = dir
fire = true

func start_timer():
#timer func to reset fire cd

Without knowing what you want to accomplish it is hard to be more precise, I also am not on my computer, so it is more difficult to answer with lots of code typed on my phone.

1 Like

The code inside the player is something like this
Func process
If input.action is pressed(shoot) and can fire and globals.amount _bullet>0:
Marker_node= $posgun.children()
Selceted marker= markernode[randi()%markernode.size()]
Can fire=false
Timer.start

Func timer
Can fire =true
My code is something like this I tried to separate my gun from my player script and and the first thing I did was chose character body 2d for gun but somehow I found that is wrong and recently I made a box that gave you random items like health or bullet I tried to use that box for my gun that whenever I shoot at it gave a different gun and whenever I go the area of that gun Replace it with the gun that I have in my player’s hand thanks for your help I think I know what to do right now

From just an architecture point of view, it would be just taking all the gun code, putting it in a separate .gd file and including it where you need it. However typically all the fighting mechanics are in its own code. Made in a way that makes changes and extending it easy. You typically want things as separated as possible. Any script should only be doing 1 thing and nothing more. Other classes designed to make different systems work together.

Ultimately how is up to you as it will depend on your current code and your vision for the game you are making.

Here is an example of a quick thing I made, where a character has 8 way movement, and he can shoot a bullet every 1.5 seconds #This is easy to change.

It is set up like this

Player ->
     Sprite2D
     CollisionShape2D
     MainGun : Node2D
          BulletHolder : Node
          Timer : Timer

An extra instantiated scene called bullet

extends CharacterBody2D # Player Scene

const SPEED : int = 200
# used for bullet direction to = player facing direction
var player_dir : Vector2 = Vector2.RIGHT

func _physics_process(_delta: float) -> void:
	
	var direction = Input.get_vector("west","east","north","south")
	
	# This gives you smooth movement in any direction
	if direction:
		player_dir = direction
		velocity = SPEED * direction
	else:
		velocity = Vector2.ZERO

	move_and_slide()
	
	# This is by mouse click, but that isn't important
	if Input.is_action_just_pressed("interact") and $MainGun.bullet_ready: 
		$MainGun.shoot(player_dir)
extends Node2D # MainGun scene
# controls fire cooldown
var bullet_ready : bool = true
var bullet_tscn = preload("res://bullet.tscn")
# used for letting physics know when it can fire
var fire := false
var player_dir : Vector2
# reference to node to instantiate bullets so they don't move with the players transform
@onready var bullet_holder = $BulletHolder
# handles instantiating bullets and giving them the var they need to fire
func _physics_process(delta: float) -> void:
	if fire:
		fire = false
		var bullet_ins = bullet_tscn.instantiate()
		bullet_holder.add_child(bullet_ins)
		bullet_ins.set_start_pos(global_position)
		bullet_ins.fire_dir = player_dir
# starts the fire sequence as well as initiating timer for reseting bullet_ready
func shoot(dir):
	player_dir = dir
	fire = true
	bullet_ready = false
	start_timer(1.5)

func start_timer(time):
	$Timer.start(time)
	
func _on_timer_timeout():
	bullet_ready = true
extends Sprite2D # Bullet Scene, 
#preferable to change this to a physics body for collision detection


const BULLET_SPEED: int = 1200

# Gets fire direction from player
var fire_dir: Vector2

# Sets position to be at the players position
func set_start_pos(pos:Vector2) -> void:
	global_position = pos

# Moves the bullet in direction of player
func _physics_process(delta: float) -> void:
	global_position += fire_dir * BULLET_SPEED * delta

This is credit to another user who had a question related to firing bullets in the direction the player was traveling. So, that is why I pretty much already had this typed up to help him with his question.

You are amazing I hope you make your own company and god gave you everything you want you are a life-saver it’s just I’m beginner at coding and I was stuck in this problem near 4 days so I’m so happy that you helped me thanks

No worries man, so many people have helped me learn how to code, so when I can help I try to. In general like jason was saying. If you have a mechanism in your game you want to create the responses of those within their own code.

For an example, in my game I have an inventory system. The player script doesn’t actually really do anything to interact with it.

I have an inventory UI and the items. The items pick themselves up once they detect the player in their collision zone and place them in the UI inventory, now the inventory handles moving the items around. If I want to put armor on my character, and place that armor in an equipment slot, now the UI equipment sends a signal to the player that tells the player the info he needs. Example: armor, damage, ect…

1 Like