- Home /
2D weapon switching
Im currently trying to create a 2D game where the player can swap between 3 different guns, all with there own sprites. But whenever i try and use my code it just automatically sets all my sprites to active. Any help with be useful, thanks! I have the a Weapon game object with my different weapons inside, with this script on it.
public int selectedWeapon = 0;
// Start is called before the first frame update
void Start()
{
SelectWeapon();
}
// Update is called once per frame
void Update()
{
int previousSelectedWeapon = selectedWeapon;
if (Input.GetAxis("Mouse ScrollWheel") > 0f)
{
if (selectedWeapon >= transform.childCount - 1)
selectedWeapon = 0;
else
selectedWeapon++;
}
if (Input.GetAxis("Mouse ScrollWheel") < 0f)
{
if (selectedWeapon <= transform.childCount - 1)
selectedWeapon = 0;
else
selectedWeapon--;
}
if (Input.GetKey(KeyCode.Alpha1))
{
selectedWeapon = 0;
}
if(Input.GetKey(KeyCode.Alpha2) && transform.childCount >= 2)
{
selectedWeapon = 1;
}
if(Input.GetKey(KeyCode.Alpha3) && transform.childCount >= 3)
{
selectedWeapon = 2;
}
if (previousSelectedWeapon != selectedWeapon)
SelectWeapon();
}
void SelectWeapon()
{
int i = 0;
foreach (Transform weapon in transform)
{
if (1 == selectedWeapon)
weapon.gameObject.SetActive(true);
else
weapon.gameObject.SetActive(false);
i++;
}
}
}
Answer by FeedMyKids1 · Sep 25, 2020 at 02:47 PM
Set up the weapon sprites as children of GameObjects. You'll turn off the gameobjects to turn of the weapons.
using UnityEngine;
public class EasyWeaponSwap : MonoBehaviour
{
[SerializeField] private KeyCode[] weaponKeyCodes =
{ KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4 };
[SerializeField] private GameObject[] weapons = null;//set in inspector
[SerializeField] private int currentWeapon = -1;
void Start()
{
if (weapons.Length > 0)
DeactivateAllWeapons();
else
throw new System.Exception("You didn't set the Weapons array in the gun script.");
currentWeapon = 0;
SelectWeapon(currentWeapon);
}
void Update()
{
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0)
{
if (scroll > 0)
ScrollWeaponUp();
else
ScrollWeaponDown();
}
for (int i = 0; i < weaponKeyCodes.Length; ++i)
if (Input.GetKeyDown(weaponKeyCodes[i]))
SelectWeapon(i);
}
private void DeactivateAllWeapons()
{
for (int i = 0; i < weapons.Length; ++i)
weapons[i].SetActive(false);
}
private void SelectWeapon(int weaponIndex)
{
weapons[currentWeapon].SetActive(false);
currentWeapon = weaponIndex;
weapons[currentWeapon].SetActive(true);
}
private void ScrollWeaponUp()
{
int nextWeapon;
if (currentWeapon == 0)
nextWeapon = weapons.Length - 1;
else
nextWeapon = currentWeapon + 1;
SelectWeapon(nextWeapon);
}
private void ScrollWeaponDown()
{
int nextWeapon;
if (currentWeapon == weapons.Length)
nextWeapon = 0;
else
nextWeapon = currentWeapon - 1;
SelectWeapon(nextWeapon);
}
}
Yes.
I was writing with an array of GameObjects (called weapons) in $$anonymous$$d.
You'd child your weapon sprites to the GameObjects.
I added the array and fixed all the compile errors by making "currentWeapon" a private int, but whenever i choose a new weapon, the other ones still stay? It just becomes all 3 of my guns on top of each other firing.
I just fixed the script above so that with a simple copy and past it will work.
You have KeyCodes set for 4 weapons.
You have to manually put the weapon gameobjects into the 'weapons' array.
$$anonymous$$ake sure that each weapon is its own GameObject and not a child of any other weapon.
I have my weapons as a child of my player game object, should i take them out and make them their own? (also have them in a "weapon" game object). I really appreciate the help, been stuck on this for a while now
Answer by BSR16 · Oct 05, 2020 at 12:44 PM
The solution I propose is to change the sprite of a single weapon game object instead of making the game objects active / deactivate.
[System.Serializable]
public class Weapon
{
public Sprite weaponSprite;
public int weaponId;
}
public class WeaponController : MonoBehaviour
{
// fills the list from the inspector by assigning id and sprite
public List<Weapon> weaponList;
// no need child game objects, assign in the inspector
public GameObject weaponGMO;
private SpriteRenderer weaponSpriteRenderer;
private int selectedWeaponId = 0;
private int currentWeaponId = 0;
public void Start()
{
weaponSpriteRenderer = weaponGMO.GetComponent<SpriteRenderer>();
SelectWeapon();
}
public void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0f){
selectedWeaponId++;
}
if (Input.GetAxis("Mouse ScrollWheel") < 0f){
selectedWeaponId--;
}
if (Input.GetKey(KeyCode.Alpha1)){
selectedWeaponId = 0;
}
if (Input.GetKey(KeyCode.Alpha2)){
selectedWeaponId = 1;
}
if (Input.GetKey(KeyCode.Alpha3)){
selectedWeaponId = 2;
}
if(currentWeaponId != selectedWeaponId){
SelectWeapon();
}
}
private void SelectWeapon()
{
// gets the corresponded Weapon instance from list according to the selectedWeaponId
Weapon selectedWeapon = weaponList.Find(x => x.weaponId == selectedWeaponId);
// if player press invalid button that does not correspond a weapon,
// the Find function will return null. Checks it.
if(selectedWeapon != null)
{
// taa-daa! changes the sprite of the weapon by selection
weaponSpriteRenderer.sprite = selectedWeapon.weaponSprite;
currentWeaponId = selectedWeaponId;
}
}
}
I think it's a little overcomplicated with the Linq function Finding the weapon in the list when we know what weapon is where (NumPad1 corresponds with weaponIndex 0).
Other than that, I think that the user will likely make use of the Component pattern and have Weapon instance data and behavior exist on the weapon gameobject, which makes it a better solution to enable and disable those gameobjects.
Also, I'm not completely sure, but depending on the sensitivity of the scrollwheel, scrolling like this would cause the weapons to change extremely rapidly and you have no clamp on 'selectedWeaponId'; so if I just keep scrolling up, weaponId would constantly increase instead of rolling back to zero once it reaches the end of the list length.
I understand the points you touched on, but what do you mean by the Component pattern? Did you mean the Composite pattern or something? Unfortunately, I understood that the problem was only with the sprite change. Information like that each weapon carries different scripts were not specified in the question. You are also right in the scrolling part. Thanks for your comment.
Sure,
Component pattern is what the Unity Engine uses for GameObjects in the scene.
You have the main GameObject (An instance with an ID) that has components attached to it (Transform if it's a 3D object and RectTransform if it's 2D).
Instead of using monolithic classes to control everything a GameObject does, you use the component pattern to add only the behavior and data needed for that type of GameObject.
As far as the sprite change and tagging on to the GameObject in Unity, if you create a sprite, it creates the GameObject the SpriteRenderer is attached to.
You can definitely do what you're talking about and have one SpriteRenderer component on a Parent object and swap out sprites depending on the weapon, but I thought that using "Find" to loop through all of the Weapon objects was unnecessary.
Definitely utbalegem could have a weapon class that includes a sprite for each weapon and just point to the current weapon instance and swap to the weapon sprite upon doing so.
Your answer
![](https://koobas.hobune.stream/wayback/20220613012529im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
How to show 2D image in User Defined Target in Unity Vuforia 0 Answers
How to animate topdown 2d water tiles? 1 Answer
How to make 2D aiming line? 0 Answers
Trigger 2D (another gameObject) 4 Answers