Letting the game decide whether to use GetButton or GetButtonDown (C#)

I’m working on a weapon system for my game. I want some of the weapons (assault rifles) to be able to shoot continuously as you hold the button (hence, GetButton), and some of them (maybe some pistols or sniper rifles, or melee weapons) to only be used once on button press (hence, GetButtonDown).

While I can just write that all in each of the weapon scripts, it would be nice to have my UserInput in one place, so if I decide to switch the button or something, I would only need to do it once.

There are a few valid ways to address this. By the time I encountered this need, I already had a customized way of processing input, and so could lean on old code. The basic idea is to inject a layer of abstraction between input collection and how it’s made use of.

If you don’t have an input manager to help with complex input logic, you should consider writing one. Then you can do stuff like:

Expose Control objects in your input manager which you can edit in the inspector, then loop over them during Update() and call Process() on them. Make the manager a singleton for easy access.

// a control object:
[System.Serializable]
public class Control {
 public string axisName;
 [HideInInspector]
 public bool isDown;
 [HideInInspector]
 public bool wasDown;
 [HideInInspector]
 public float timeHeld;

 public bool OnUp {
   get { return (wasDown && !isDown); }
 }

 public bool OnDown {
  get { return (!wasDown && isDown); }
 }

 // etc, this can have other helpful fields or properties
 // including ways to respect analog axes as well as buttons

 public void Process() {  
  bool inputNow = Input.GetButton( axisName );
  wasDown = isDown;
  isDown = inputNow;
  if (inputNow) timeHeld += Time.unscaledDeltaTime;
   else timeHeld = 0;
 }
}

// in your input manager...
public Control TriggerControl; // give it the name "Fire1" in inspector

void Update() {
 triggerControl.Process();
}


// then, throughout your project, you can call them like,
if (InputManager.I.TriggerControl.OnDown) DoSomething();
if (InputManager.I.JumpControl.IsHeld) DoSomethingElse();

This is a very flexible (and admittedly complicated) answer to your question. The trick is, your gun shouldn’t care what kind of input it receives. It can expose an Interface like IGun which has an enum ActionType argument. ActionTypes can be SemiAutomatic, FullyAutomatic, ChargeAndRelease, etc…

When the gun processes input, it behaves according to its ActionType. A gun with (ActionType.SemiAutomatic) would fire (TriggerControl.OnDown). An (ActionType.FullyAuomatic) would fire in intervals you specify as long as (TriggerControl.isDown).