I'm a new user to Unity3D and need a hand.
I have some code which I want to be activated when the UI image is pressed and to end once the press has been released. The game is going to run on both Android and IOS so needs to be supported by both platforms.
Here is my code:
public class RPB : MonoBehaviour {
public Transform LoadingBar;
public Transform TextIndicator;
[SerializeField] private float currentAmount;
[SerializeField] private float speed;
[SerializeField] private float numSec;
// Update is called once per frame
void Update () {
if (currentAmount < 100) {
currentAmount += speed * Time.deltaTime;
} else if (currentAmount > 100){
currentAmount = 0;
numSec += 1;
}
LoadingBar.GetComponent<Image>().fillAmount = currentAmount /100;
TextIndicator.GetComponent<Text> ().text = ((int)numSec).ToString () + "s";
}
}
How would I be able to do this?
Thank you
In regards to your issue with the touch screen, I would recommend using Unity's UI button system. It works very well with both Android and iOS platforms. I recommend watching these videos to understand how to write a function that the interface will call for you: https://unity3d.com/learn/tutorials/topics/user-interface-ui/ui-button
On another note, running GetComponent<>() every frame is incredibly taxing on a mobile system.
I recommend the following change:
using UnityEngine;
using UnityEngine.UI;
public class RPB : MonoBehaviour {
public Image LoadingBar;
public Text TextIndicator;
// other variables redacted //
void Start () {
LoadingBar = GetComponent<Image>();
TextIndicator = GetComponent<Text>();
}
void Update () {
// other functions redacted //
LoadingBar.fillAmount = currentAmount / 100;
TextIndicator.text = ((int)numSec).ToString () + "s";
}
public void TouchFunction() {
// Do the thing here. //
}
}
I have some code which I want to be activated when the UI image is
pressed and to end once the press has been released
I would have have advised you to use the Button component too but it doesn't have click down and up events. It only has onClick event which means you can only detect when a there is a Button click not when pressed and released.
This can be done with the Image component. Implement IPointerDownHandler and IPointerUpHandler then override the OnPointerDown and OnPointerUp functions. These functions will be called when there is a mouse click and release on your Image. Attach the script to the Image and that should do the job assuming that the current code you have is logically correct.
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class YourScript : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public Transform LoadingBar;
public Transform TextIndicator;
[SerializeField]
private float currentAmount;
[SerializeField]
private float speed;
[SerializeField]
private float numSec;
bool isPressed = false;
public void OnPointerDown(PointerEventData eventData)
{
// someCode();
Debug.Log("Mouse Down");
isPressed = true;
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Mouse Up");
isPressed = false;
}
void Update()
{
if (isPressed)
{
someCode();
}
}
void someCode()
{
if (currentAmount < 100)
{
currentAmount += speed * Time.deltaTime;
}
else if (currentAmount > 100)
{
currentAmount = 0;
numSec += 1;
}
LoadingBar.GetComponent<Image>().fillAmount = currentAmount / 100;
TextIndicator.GetComponent<Text>().text = ((int)numSec).ToString() + "s";
}
}
Related
Been trying for a while now and I just need to make it so I can zoom in and out using the camera's FOV.
When I try this nothing happens.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cameraZoom : MonoBehaviour
{
private Camera cameraFreeWalk;
public float zoomSpeed = 20f;
public float minZoomFOV = 10f;
public void ZoomIn()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
}
}
(1) Since there is nothing calling the ZoomIn() function, nothing will happen. You should move the Input-check into the Update() method since it is called by Unity in every frame, and you can then call the ZoomIn() function when the mouse-wheel is turned up.
private void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ZoomIn();
}
}
public void ZoomIn()
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
(2) You need to set the cameraFreeWalk field. You can either make it visible in the editor by adding the attribute "SerializeField", and then in the editor drag the Camera into the exposed field...
[SerializeField]
private Camera cameraFreeWalk;
... or you can collect the Camera component automatically. In this example, we tell Unity that there must be a Camera component on the same game object and we collect a reference to it in the Awake() method. If you want to be extra careful, check that you really have got a reference by doing an Assert() check. A bit redundant because of the RequiredComponent attribute, but I like to check all fields I am working with.
[RequireComponent(typeof(Camera))]
public class cameraZoom : MonoBehaviour
{
....
private void Awake()
{
cameraFreeWalk = GetComponent<Camera>();
Assert.IsNotNull(cameraFreeWalk);
}
(3) Finally, to be sure that the script works, you should also in the Awake() method, check that someone hasn't changed the camera to Orthographic - since then FOV will not be used. Personally, I like the Assert() method as you can see...
Assert.IsFalse(cameraFreeWalk.orthographic, "There isn't a FOV on an orthographic camera.");
The complete solution would then be something like this...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
[RequireComponent(typeof(Camera))]
public class cameraZoom : MonoBehaviour
{
[SerializeField]
private Camera cameraFreeWalk;
public float zoomSpeed = 20f;
public float minZoomFOV = 10f;
public float maxZoomFOV = 160f;
private void Awake()
{
cameraFreeWalk = GetComponent<Camera>();
Assert.IsNotNull(cameraFreeWalk);
Assert.IsFalse(cameraFreeWalk.orthographic, "There isn't a FOV on an orthographic camera.");
}
private void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ZoomIn();
}
else if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
ZoomOut();
}
}
public void ZoomIn()
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
public void ZoomOut()
{
cameraFreeWalk.fieldOfView += zoomSpeed;
if (cameraFreeWalk.fieldOfView > maxZoomFOV)
{
cameraFreeWalk.fieldOfView = maxZoomFOV;
}
}
}
I hope you all are doing well. I have been following a Unity tutorial for a rhythm game and I have found this bug that I could not get past. Essentially, my OnTriggerExit2D is getting called too early. I'll include a picture in the conclusion of this post. I have tried logging the game object and it seems that all of my button objects suffer the same fate. I have included a link of the tutorial that I have been following in the conclusion. Any help towards figuring this out would be helpful.
Tutorial Link: https://www.youtube.com/watch?v=PMfhS-kEvc0&ab_channel=gamesplusjames
What my game looks like, the missed shows up when I've hit it.
Debug Output
GameManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public AudioSource theMusic;
public bool startPlaying;
public BeatScroller theBS;
public static GameManager instance;
public int currentScore;
public int scorePerNote = 100;
public int scorePerGoodNote = 125;
public int scorePerPerfectNote = 150;
public int currentMultiplier;
public int multiplierTracker;
public int [] multiplierTresholds;
public Text scoreText;
public Text multiText;
// Start is called before the first frame update
void Start()
{
instance = this;
scoreText.text = "Score: 0";
multiText.text = "Multiplier: x1";
currentMultiplier = 1;
}
// Update is called once per frame
void Update()
{
if(!startPlaying){
if(Input.anyKeyDown){
startPlaying = true;
theBS.hasStarted = true;
theMusic.Play();
}
}
}
public void NoteHit(){
Debug.Log("Note Hit On Time");
if(currentMultiplier-1 < multiplierTresholds.Length){
multiplierTracker++;
if(multiplierTresholds[currentMultiplier-1] <= multiplierTracker){
multiplierTracker = 0;
currentMultiplier++;
}
}
multiText.text = "Multiplier: x"+currentMultiplier;
//currentScore += scorePerNote * currentMultiplier;
scoreText.text = "Score: "+currentScore;
}
public void NormalHit(){
currentScore += scorePerNote * currentMultiplier;
NoteHit();
}
public void GoodHit(){
currentScore += scorePerGoodNote * currentMultiplier;
NoteHit();
}
public void PerfectHit(){
currentScore += scorePerPerfectNote * currentMultiplier;
NoteHit();
}
public void NoteMissed(){
Debug.Log("MISSED!");
multiText.text = "Multiplier: x1";
}
}
BeatScroller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BeatScroller : MonoBehaviour
{
public float beatTempo;
public bool hasStarted;
// Start is called before the first frame update
void Start()
{
beatTempo = beatTempo / 60f;
}
// Update is called once per frame
void Update()
{
if(!hasStarted){
}else{
transform.position -= new Vector3(0f, beatTempo*Time.deltaTime, 0f);
}
}
}
ButtonController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ButtonController : MonoBehaviour
{
// Start is called before the first frame update
private SpriteRenderer theSR;
public Sprite defaultImage;
public Sprite pressedImage;
public KeyCode keyToPress;
void Start()
{
theSR = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(keyToPress))
{
theSR.sprite = pressedImage;
}
if(Input.GetKeyUp(keyToPress))
{
theSR.sprite = defaultImage;
}
}
}
noteObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class noteObject : MonoBehaviour
{
public bool canBePressed;
public KeyCode KeyToPress;
public GameObject hitEffect, goodEffect, perfectEffect, missedEffect;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyToPress))
{
if(canBePressed)
{
gameObject.SetActive(false);
if(Mathf.Abs(transform.position.y) > 0.25){
GameManager.instance.NormalHit();
Debug.Log("Normal Hit!");
Instantiate(hitEffect,transform.position, hitEffect.transform.rotation);
}else if(Mathf.Abs(transform.position.y) > 0.05f){
GameManager.instance.GoodHit();
Debug.Log("Good Hit!!");
Instantiate(goodEffect,transform.position, goodEffect.transform.rotation);
}else{
GameManager.instance.PerfectHit();
Debug.Log("PERFECT HIT!!!");
Instantiate(perfectEffect,transform.position, perfectEffect.transform.rotation);
}
}
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Activator")
{
canBePressed = true;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if(other.tag == "Activator")
{
Debug.Log("Exited collider on game object: "+ other.gameObject.name);
canBePressed = false;
GameManager.instance.NoteMissed();
Instantiate(missedEffect,transform.position, missedEffect.transform.rotation);
}
}
}
EffectObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EffectObject : MonoBehaviour
{
public float lifeTime = 1f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Destroy(gameObject, lifeTime);
}
}
Hmm ... You say that OnTriggerExit2D is called to early? I assume it's called when the elements are still inside one another? If that's the case I guess your bounding boxes don't have the right size, or the right shape. I see arrows, do they have a rectangular bounding box or a polygon one that follows their shape? Are all your bounding boxes the right size?
I figured out what was wrong thanks to AdrAs's comment.
Turns out I had to check the y position of my arrow and collider were well enough below the height of my button box collider. In addition to that, I reshaped my colliders. I found that this code did the trick for me. Thank You All For the Nudges in the right direction.
noteObject -> new OnTriggerExit2D
private void OnTriggerExit2D(Collider2D other)
{
if(other.tag == "Activator" && transform.position.y < -0.32)
{
Debug.Log("Exited collider on game object: "+ other.gameObject.name);
canBePressed = false;
GameManager.instance.NoteMissed();
Instantiate(missedEffect,transform.position, missedEffect.transform.rotation);
}
}
In my script whenever you click a "Button" it adds 1 to your score. When you miss the button 10 times total it loads a new scene and you lose the game. When you click the button it resets the total back to 0. The problem im having is that if you miss the button 9 times and then click it on the 10th time it still counts to 10 and it loads the new screen and you lose.
What it should be doing is resetting it back to 0 and you can continue to play.
loseObject sets the amount to 0 when the game begins and when the button is pressed.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(AudioSource))]
public class ButtonReposition : MonoBehaviour
{
public Button prefab;
public GameObject loseObject;
private int count;
public Text countText;
// Use this for initialization
void Start()
{
count = 0;
SetCountText();
float x = Random.Range(325f, -600f);
float y = Random.Range(250f, -450f);
Debug.Log(x + "," + y);
prefab.GetComponent<RectTransform>().anchoredPosition = new Vector2(x, y);
loseObject.GetComponent<Lose>().amount = 0;
}
public void Move()
{
float x = Random.Range(325f, -600f);
float y = Random.Range(250f, -450f);
Debug.Log(prefab.transform.position.x + "," + prefab.transform.position.y);
prefab.GetComponent<RectTransform>().anchoredPosition = new Vector2(x, y);
loseObject.GetComponent<Lose>().amount = 0;
count = count + 1;
SetCountText();
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
}
}
And on get mouse button down it adds 1 to the total and loads the next scene.
using UnityEngine.Audio;
using UnityEngine.UI;
public class Lose : MonoBehaviour
{
public GameObject Button;
public GameObject Target;
public GameObject loseObject;
public int amount;
public ButtonReposition script;
public void ChangeScene(int changeTheScene)
{
SceneManager.LoadScene(changeTheScene);
}
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
amount += 1;
Debug.Log(amount);
if (amount == 10)
{
SceneManager.LoadScene(2);
Destroy(Button);
}
}
}
}
In other to get this right, you have to find a way to determine when the moue button is down and Button is clicked. You are not doing that now. What you are doing now is checking when left mouse Button is clicked with if (Input.GetMouseButtonDown(0)).
This is one of the cases, where using the Image component is better than using the Button component. Unless you really need the Button component here, the Image component should be used.
This can be done with IPointerDownHandler, IPointerUpHandler interface with their OnPointerDown and OnPointerUp functions.
Disable your ButtonReposition script for now. Use the script below and see if that's doing what you expected. If everything is fine you can then enable your ButtonReposition script and remove the unnecessary stuff inside it.
Attach the ButtonDetector to your Image Component:
public class ButtonDetector : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public bool clicked = false;
public void OnPointerDown(PointerEventData eventData)
{
clicked = true;
//Debug.Log("Pointer Down!");
}
public void OnPointerUp(PointerEventData eventData)
{
//Reset
clicked = false;
// Debug.Log("Pointer Up!");
}
// Use this for initialization
void Start()
{
}
}
Your new Lose script:
public class Lose : MonoBehaviour
{
public GameObject Button;
public GameObject Target;
public GameObject loseObject;
public int missedAmount = 0;
public int clickedAmount = 0;
const int MISSED_MAX_AMOUNT = 10;
//public ButtonReposition script;
public void ChangeScene(int changeTheScene)
{
SceneManager.LoadScene(changeTheScene);
}
private ButtonDetector buttonImage;
void Start()
{
GameObject obj = GameObject.Find("ButtonImage");
buttonImage = obj.GetComponent<ButtonDetector>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (buttonImage.clicked)
{
Debug.Log("Mouse Clicked on Button!");
clickedAmount++;
//Reset missedAmount to 0
missedAmount = 0;
}
else
{
Debug.LogWarning("Mouse Click on SOMETHING ELSE");
missedAmount++;
}
if (missedAmount == 10)
{
Debug.LogWarning("GameOver!");
Debug.LogWarning("Missed 10 times in a row!");
SceneManager.LoadScene(2);
//Destroy(buttonImage.gameObject);
}
}
}
}
I think the easiest fix for you would be to make sure your loseObject script executes after your first script. You can do that with the script execution order. If you go to Edit -> Project Settings -> Script Execution Order you can add your loseObject script and draw it below "Default". Then your other script will execute first and set the amount to 0 as you would expect. However, after it gets set to 0, loseObject will still increment by one, so what you actually want to do is set amount to -1.
So I have 3 same images, but with different colors which I want to cycle in my menu. They are only with different hue/saturations and I want them to slowly reduce their alpha 1 by 1 so that the one behind pops up and then restart the cycle.
I'm trying to set a public image and reduce it's alpha, but it's not smooth.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Fading : MonoBehaviour {
public Image image;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
//image.CrossFadeAlpha(50, 5, false);
image.GetComponent<CanvasRenderer>().SetAlpha(0.1f);
image.CrossFadeAlpha(10f, 4f, false);
}
}
CrossFadeAlpha should only be called to start the image fade transition, via a button press or similar, as the method works similar to a Coroutine, example (on mouse button press);
public class ImageFade : MonoBehaviour
{
[SerializeField]
private Image m_img;
[SerializeField]
private float m_fadeDuration;
[SerializeField]
private bool m_ignoreTimeScale;
public void Update()
{
if (Input.GetMouseButtonDown(0))
m_img.CrossFadeAlpha(0f, m_fadeDuration, m_ignoreTimeScale);
if (Input.GetMouseButtonDown(1))
m_img.CrossFadeAlpha(1f, m_fadeDuration, m_ignoreTimeScale);
}
}
However if you would prefer to control this functionality manually, you have to take a longer approach. Below you can see that every time the mouse is pressed, the fade multiplier is negated, making it always 1 or -1. This value is then multiplied by the fraction of time needed for this update (before being added to the current alpha value);
Time.deltaTime / m_fadeDuration
As well as this, the boolean m_requiresUpdate, makes sure to avoid unnecessary updates, setting itself to false after the fade is complete.
public class ImageFade : MonoBehaviour
{
[SerializeField]
private Image m_img;
[SerializeField]
private float m_fadeDuration;
[SerializeField]
private bool m_ignoreTimeScale;
private int m_fadeMultiplier;
private float m_alpha;
private bool m_requiresUpdate;
public void Start()
{
m_fadeMultiplier = 1;
m_alpha = 1f;
}
public void Update()
{
//Toggle subtracting/adding
if (Input.GetMouseButtonDown(0))
{
m_fadeMultiplier = -m_fadeMultiplier;
m_requiresUpdate = true;
}
//Update
if (m_requiresUpdate)
{
//Fade
m_alpha = Mathf.Clamp(m_alpha + (m_fadeMultiplier * (Time.deltaTime / m_fadeDuration)), 0f, 1f);
m_img.canvasRenderer.SetAlpha(m_alpha);
//Finished fading
if (m_alpha == 0f || m_alpha == 1f)
m_requiresUpdate = false;
}
}
}
Hope this ties everything together nicely for you.
My project is a military fps and i'm having some problems with animations.
I have 3 different weapons, 1 animator controller for each one and every weapon has a "enter" and "leave" animation. Like CS, COD, etc...
I need to know when my "leave" animation ends to disable the gameobject, enable the other one and play the "enter" animation.
I tryed to do this: http://answers.unity3d.com/questions/362629/how-can-i-check-if-an-animation-is-being-played-or.html but without sucess.
I'll leave here a print of the animator controller, the hierarchy and the script, if u need more details, just need to say.
Animator controller of the weapon number 1
All transitions to "Sair" (leave animation) have a trigger (AK47_sair) and the transition to "Extit" state have a trigger ("AK47_SairControlador")
On my code, when i press 2 (change to weapon number 2) i want to do the transition.
This is the hierarchy, my script is attached to "Jogador".
With my actual code, it disable tha AK47 gameobject when the leave animation still playing.
using UnityEngine;
using System.Collections;
public class FirstPerson : MonoBehaviour {
public float speed;
public float normalSpeed = 5.0f;
public float slowSpeed = 2.5f;
public float crchSpeed = 2.5f;
private Transform tr;
private float dist; // distance to ground
public float mouseSensitivity = 5.0f;
public float verticalRotation = 0.0f;
public float updownRange = 60.0f;
private float verticalSpeed = 0.0f;
public float jumpSpeed = 5.0f;
CharacterController player;
private GameObject AK47;
private GameObject Faca;
public float shootingRate = 0.15f;
public float shootCooldown;
private bool agachado = false;
public float camOriginalPositionY;
public float camCrouchPositionY;
private Animator controladorAnimacaoAK;
private Animator controladorAnimacaoFaca;
public CapsuleCollider playerCollider;
public Camera CameraPrincipal;
public int ArmaSelecionada;
public int UltimaArma;
void Start () {
player = GetComponent<CharacterController>();
shootCooldown = 0;
controladorAnimacaoAK = player.GetComponentInChildren<Animator>();
playerCollider = gameObject.GetComponent<CapsuleCollider> ();
CameraPrincipal = Camera.main;
ArmaSelecionada = 1;
AK47 = CameraPrincipal.transform.FindChild ("ak47_final_animado").gameObject;
}
void Update () {
if (Input.GetKeyDown (KeyCode.Alpha2) || Input.GetKeyDown(KeyCode.Keypad2)) {
UltimaArma = ArmaSelecionada;
ArmaSelecionada = 2;
if(UltimaArma == 1) {
controladorAnimacaoAK.SetTrigger("AK47_Sair");
controladorAnimacaoAK.SetTrigger("AK47_SairControlador");
AK47.SetActive (false);
}
}
if (Input.GetKeyDown (KeyCode.Alpha1)) {
UltimaArma = ArmaSelecionada;
ArmaSelecionada = 1;
// controladorAnimacaoAK.SetTrigger ("AK47_Entrar");
}
if (ArmaSelecionada == 1) {
// diz ao controlador da anim se o player esta a movimentar-se ou nao
controladorAnimacaoAK.SetFloat ("AK47_Deslocacao", player.velocity.magnitude);
//Debug.Log (player.velocity.magnitude);
// dispatar tiros
PlayerShoot PlayerShootScript = player.GetComponent<PlayerShoot> ();
if (shootCooldown > 0) {
shootCooldown -= Time.deltaTime;
}
if (Input.GetButton ("Fire1")) {
if (shootCooldown <= 0) {
shootCooldown = shootingRate;
PlayerShootScript.FireShoot ();
// animaƧao
controladorAnimacaoAK.SetBool ("AK47_Disparar", true);
}
} else {
// animaƧao
controladorAnimacaoAK.SetBool ("AK47_Disparar", false);
}
if (Input.GetKeyDown (KeyCode.R)) {
controladorAnimacaoAK.SetTrigger ("AK47_rec");
}
}
}
}
In Unity 5 you've got this new thing which is Animation State Machine Behavior : State Machine Behaviours
You can use it to specify behavior when the Animation Controller enters or leave specific states.
For exemple here I've got my door which have an Open and Close state, and let's say that I want to play a sound when the door is opening.
Here I clicked Opening, then Add Behaviour and set a random name for the test (Behavior Test in my case)
Then I just need to implement the function void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) to play a sound at the first frame the animation is running.
[SerializeField]
AudioClip open_sound;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.GetComponent<AudioSource>().clip = open_sound;
animator.GetComponent<AudioSource>().Play();
}
In your case, you would want to implement a behavior in the state Disparar which implements the function OnStateExit([...]) and handle the weapon change.
To go a bit further I don't think you should handle the weapon change directly in the animation state, but maybe your script could send an event catched by a Game Controller that will actually handle the change of weapon.