Weapon Swap Script

Hi there!
Right now I’ve got a Script that consists mainly of an Array in which I plan to store all my Weapons.
What I’m trying to do is to let the player swap between all weapons in the Array, just by pressing LeftShift.

I managed to get the code working by myself until the very moment in which Weapons are forced to " switch back"… like: I’m at the end of the Array, when Shift is pressed again it’s time to go back to the start.

For some reasons, the code you kindly wrote me doesn’t get the job done either.

I’m now posting you my script, maybe the problem is inherent to logic itself… I’ll restate what I’d like to do: write a script that handles all weapons in one array, gives the player the chance to swap between them ( later this will be done by power ups) and also gets the current weapon’s stats and use them when pushed to shoot.
Now that makes sense to me, but maybe it’s not program-minded… or maybe I’m just stupid, who knows? maybe you know it!

using UnityEngine;
using System.Collections;

public class WeaponManager : MonoBehaviour {

	public float hitDamage; // The Damage we want do deal with it
	public float fireRate; // The Speed at wich we shoot
	public float projectileSpeed; // This is the Speed of the bullet
	public GameObject currentWeapon; // Let's see.
	public float nextFire = 0.0f;// The delay till the next shot once fireRate is added.
	
	public GameObject [] weaponsArray = new GameObject[2];// This is our Array to store all the things. At the time I'm writing, I've got only 2 weapons as test.
	// I'll use Instructor and not code to specify what GameObject is element zero, one and so on...
	private int currentWeaponIndex = 0; // THIS INT IS NEEDED to keep track of the current weapon we are on it.
	
	
	
	// Use this for initialization
	void Start () {
		
		currentWeapon = weaponsArray[currentWeaponIndex]; // The weapon with which you start. Linking it with currentWeaponIndex let's us change it dinamically!
	
	}
	
	// Update is called once per frame
	void Update () {
		
		//Cheap Projectile Speed variable
		//currentWeapon.transform.Translate(Vector3.right * projectileSpeed * Time.deltaTime, Space.World); // it's working only if you attach this to the weapon itself. Maybe it's the same for Shooting...
		
		//Swap Weapon, just for testing sake
		if (Input.GetKeyDown(KeyCode.LeftShift)){
			
			currentWeaponIndex ++; // i.e. add 1 to our integer. Lets us swap between every element of our Array.
			
			if (currentWeaponIndex >= weaponsArray.Length){ // If we are trying to swap to an integer that is not in our Array, i.e. an integer outside our number's lenght.
				
				currentWeaponIndex = 0; // Current weapon index goes back to zero, we " loop".
				currentWeapon = weaponsArray[currentWeaponIndex]; // your weapon equals to the one that your index says... i.e. zero right now.
				
			}
			
		}
		
		//Shoot Sample
		if (Input.GetKeyDown(KeyCode.Space) && Time.time > nextFire){
			
			nextFire = Time.time + fireRate;
			currentWeapon.transform.position = new Vector3(PlayerV31.x, PlayerV31.y, PlayerV31.z);
			Instantiate(currentWeapon);		
		}
	}
}

P.S.: at this time, instantiate works but it doesn’t get the fire rate of the current weapon ( I know I haven’t said him to do so but fact is I’m a bit confused on how to say it) AND the weapon swap doesn’t work.

Thanks a lot for your time!

why are you setting the current weapon inside your if statement?

if (currentWeaponIndex >= weaponsArray.Length){  
  currentWeaponIndex = 0;
  currentWeapon = weaponsArray[currentWeaponIndex];
}

This should be:

if (currentWeaponIndex >= weaponsArray.Length)
   currentWeaponIndex = 0;

currentWeapon = weaponsArray[currentWeaponIndex];

Again, as I mentioned before, it would be better if you used the mod operator instead of all those checks, like:

if (Input.GetKeyDown(KeyCode.LeftShift)){
   currentWeaponIndex = (currentWeaponIndex + 1) % weaponsArray.Length; 
   currentWeapon = weaponsArray[currentWeaponIndex];
}

This will insure that the index will remain with the bounds of the array. And when the index reaches the (array.len-1), index+1 == array.len, so array.len % array.len == 0 and you get back to the beginning of the array.

A numeric example: you have 2 weapons, so arr.len = 2, at first you start with 0 for your current index (I’ll refer to as index). when you press shift:

index = (index+1) % arr.len = (0+1) % 2 = 1 % 2 = 1;

press shift again:

index = (index+1) % arr.len = (1+1) % 2 = 2 % 2 = 0;

I would wrap this up in a method, SeekWeapons(SeekDirection dir) - here:

public enum SeekDirection { Forward, Backward }

public void SeekWeapons(SeekDirection dir) // this will also let you go backwards should you desire
{
  if (dir == SeekDirection.Forward) 
     currentWeaponIndex = (currentWeaponIndex + 1) % weaponsArray.Length;
  else {
     currentWeaponIndex--;
     if (currentWeaponIndex < 0)
        currentWeaponIndex = weaponsArray.Length-1;
  }
  currentWeapon = weaponsArray[currentWeaponIndex];
}

You might also need to instantly switch to a weapon (by pressing numbers or something), let’s keep it simple and use the keyboard numbers, if you had 2 weapons, only num 1 and 2 will be used, if you have 5, num 1, 2, 3, 4, 5, etc…

public void SwitchWeaponTo(int n)
{
   n = Mathf.Clamp(n, 0, weaponsArray.Length-1); // this will make sure that n won't go above how many weapons you have, nor below 0
                             // Clamp works like this, if n > arr.len-1 -> return arr.len-1, if n < 0 -> return 0, else return n. See the docs for it if you don't know it

   currentWeapon = weaponsArray[n];
}

Now, in your Update:

void Update()
{
   // code...
   if (Input.GetKeyDown(KeyCode.1)
   {
       currentWeaponIndex = 0;
   }
   else if (Input.GetKeyDown(KeyCode.2)
   {
       currentWeaponIndex = 1;
   }
   else if ... etc

   SwitchWeaponTo(currentWeaponIndex);
   // code...
}

Couple of notes:

  1. You might get some compile errors if
    you copy-paste my code, adjust it
    accordingly to your needs (I prefer
    you take ideas, and not just
    copy-paste code)

  2. This whole system that you’re using
    isn’t gonna serve you well in the
    long run when your game gets
    complicated, for a better
    inventory/weapons design please see
    this link.

  3. An array might not serve you very
    well if you want to Add/Remove
    weapons, so you might consider using
    a List instead.

  4. Your politeness forced me to write
    you an answer, keep it up and good
    luck :slight_smile:

Let me know if you get stuck somewhere, or if there was something you didn’t understand. And as always, if an answer solves your problem please tick it as correct.

I would suggest doing this using a generic list rather than an array, since an array can’t be resized easily. I’ve included a solution using your array which is fixed length and then a second using a list.

ARRAY EXAMPLE:

using UnityEngine;
using System.Collections;

public class WeaponManager : MonoBehaviour
{

	public GameObject currentWeapon;

	public GameObject[] weaponsArray = new GameObject[2];

	// An int to track which index item we
	// are assigning as the weapon
	private int currentWeaponIndex = 0;

	// Use this for initialization
	void Start()
	{
		// The weapon with which you start.
		currentWeapon = weaponsArray[currentWeaponIndex];
	}

	// Update is called once per frame
	void Update()
	{

		//Swap Weapon, just for testing sake
		if (Input.GetKeyDown(KeyCode.LeftShift))
		{
			currentWeaponIndex++;

			if (currentWeaponIndex >= weaponsArray.Length)
				currentWeaponIndex = 0;

			currentWeapon = weaponsArray[currentWeaponIndex];
		}
	}
}

LIST BASED SYSTEM:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class WeaponManagerList : MonoBehaviour
{

	public GameObject currentWeapon;

	// List to hold all our weapons
	public List<GameObject> weaponsList = new List<GameObject>();
	// An int to track which index item we
	// are assigning as the weapon
	private int currentWeaponIndex = 0;

	// Use this for initialization
	void Start()
	{
		// The weapon with which you start.
		currentWeapon = weaponsList[currentWeaponIndex];
	}

	// Update is called once per frame
	void Update()
	{

		//Swap Weapon, just for testing sake
		if (Input.GetKeyDown(KeyCode.LeftShift))
		{
			currentWeaponIndex++;

			if (currentWeaponIndex >= weaponsList.Count)
				currentWeaponIndex = 0;

			currentWeapon = weaponsList[currentWeaponIndex];
		}
	}

	public void AddNewWeapons(GameObject newWeapon)
	{
		weaponsList.Add(newWeapon);
	}

	public void RemoveWeapon(GameObject weapon)
	{
		if (weaponsList.Contains(weapon))
			weaponsList.Remove(weapon);
	}
}

Since I use Lists a lot, I included a little snippet that will allow you to add a weapon or remove a weapon from the list.