How would you go about creating a weapon pickup system?

Hi! Im building a top down twin stick shooter and I’m gonna have multiple kinds of weapons. Let’s say I want a pistol, machine gun, rocket launcher, and a shotgun. All have different bullets, mag sizes and are either automatic or not.
I can think of a couple of ways to do this, but right now I am trying the following way:

  1. I have a pickupScript attached to the player,which has a list of colliding pick ups and a function to return the first object in that list.
  2. I have a player Movement script which runs that function to get the weapon to hold.
  3. I have a weapon script attached to the weapon with a shoot function and a reference to the script in my player movement script, which is called when I press the right trigger.

Now I do think this strategy will work, but I do have a couple of problems with it. First of all, it just feels wrong, a large tangle of references and scripts. Second, what if I wanted to add a medkit? It wouldn’t have a shoot function and my system won’t work.

There’s other ways I could do this but I’m wondering what you all would do it. Thanks in advance!

More abstraction.

Make a Pickable-Script and a PlayerPickup-Script.
Pickable looks for any kind of Pickups - you can do this with OverlapSphereNonAlloc (cause, performance matters as you call it every frame) combined with TryGetComponent (again, performance - TryGetComponent won’t allocate garbage if the script is not found).
To make this work, you have to place your Pickup-Script on an Object with a Collider, if you want your Collider to be a Child of the Pickup-GameObject (where the Pickable Component is placed) - you can make a workaround with an interface and an extra component - but lets keep it simple here.

The PlayerPickup-Script looks for Pickables - if one is found, he passes the Object to everyone who subscribed.
Subscription? Yes. The most flexible Way to do this, is to use System.Action<>.
So your PlayerPickup Script has the following Method:

List<Action<Pickable>> subscribers = new List<Action<Pickable>>;

public void RegisterPickupCallback(Action<Pickable> action){
subscribers.Add(action);
}

Your PlayerWeaponController, PlayerHealth, PlayerInventory Components can then subscribe by calling the Method, example:

public class PlayerHealth : MonoBehaviour
{
int _playerHealth = 100;

void Start()
{
PlayerPickup pp = GetComponent<PlayerPickup>();
pp.RegisterPickupCallback(OnPickup);
}

void OnPickup(Pickable pickable)
{
if(pickable.TryGetComponent(out Medikit medikit)){
_playerHealth += medikit.healAmount;
}
}
}

Once this is set up, you just have to call all the Actions once you find a pickup and destroy the pickup.

public class PlayerPickup : MonoBehaviour
{
List<Action<Pickable>> subscribers = [URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] List<Action<Pickable>>;

public void RegisterPickupCallback(Action<Pickable> action){
subscribers.Add(action)
}

void Update(){
// search for pickups as described earlier, then call the method below
}

// Once you found a pickup in your UpdateLoop with OverlapSphereNonAlloc
void OnPickupFound(Pickable pickable){
foreach(Action<Pickable> action in subscribers){
action?.Invoke(pickable);
}
}
}

And of course whatever you do with your pickable depends on the subscriber - you can also pack things together, so you pickup a weapon and during picking it up, you get healed or get ammo or whatever.

You can easily add functionality to your Pickups as well as to your Player (in terms of what he does with the pickup).
Once written, you won’t have to touch the PlayerPickup or Pickable Component ever again as all the extending functionality happens outside of these scripts (by adding new components to the gameObjects).