# In Unity C#, how can I change weapon a few frames later?

I have this Input code to change weapon:

if (d_left)
{
if (!p_d_left)
{
states.inventoryManager.ChangeWeaponToNextWeapon(true);
p_d_left = true;
}
}
if (d_right)
{
if (!p_d_right)
{
states.inventoryManager.ChangeWeaponToNextWeapon(false);
p_d_right = true;
}


And in the InventoryManager I have the weapon changed by this:

public void ChangeWeaponToNextWeapon(bool isLeft)
{
if (isLeft)
{
if (l_index < r_l_weapons.Count - 1)
l_index++;
else
l_index = 0;
EquipWeapon(r_l_weapons[l_index], true);
}
else
{
if (r_index < r_r_weapons.Count - 1)
r_index++;
else
r_index = 0;

EquipWeapon(r_r_weapons[r_index]);
}

states.actionManager.UpdateActionsOneHanded();
}


Then equip the weapon along with animation and other stuff :

public void EquipWeapon(RuntimeWeapon w, bool isLeft = false)
{
if (isLeft)
{
if (leftHandWeapon != null)
{
leftHandWeapon.weaponModel.SetActive(false);
}

leftHandWeapon = w;
}
else
{
if (rightHandWeapon != null)
{
rightHandWeapon.weaponModel.SetActive(false);
}

rightHandWeapon = w;
}

string targetIdle = w.instance.oh_idle;
targetIdle += (isLeft) ? "_l" : "_r";
states.anim.SetBool(StaticStrings.mirror, isLeft);
states.anim.Play(StaticStrings.changeWeapon);
states.anim.Play(targetIdle);

UI.Slot uiSlot = UI.Slot.singleton;
(isLeft) ?
UI.QSlotType.lh : UI.QSlotType.rh, w.instance.icon);

w.weaponModel.SetActive(true);
}


But the problem is the weapon changes immediately after pressing the button. How can I switch my weapon a few frames later while playing the animation?

• Have you explored using Coroutines? They're the usual go-to for spacing behaviour across several frames in Unity. – DMGregory Jan 12 at 4:33

I assume you don't really need to postpone the weapon change for some frames. Instead, you need to postpone the change until some condition is met. If this is a right assumption, then simply use a coroutine to check the condition and do the change accordingly. E.g. if you want to change the weapon when all the animations ended, here is you coroutine function:

IEnumerator WaitAndChangeWeapon(Animation anim, String targetIdle,
UI.Slot uiSlot, UI.QSlotType slotType, RuntimeWeapon w) {
// Wait till the animations complete.
while (anim.IsPlaying(StaticStrings.changeWeapon) || anim.IsPlaying(targetIdle)) {
yield return null;  // Skip this frame.
}

// Update the weapon.
w.weaponModel.SetActive(true);
}


Now, in your EquipWeapon method instead of updating the slot and activating the model, simply do:

// Given your module is a descendant of MonoBehaviour.
StartCoroutine(WaitAndChangeWeapon(states.anim, targetIdle, UI.Slot.singleton,
(isLeft) ? UI.QSlotType.lh : UI.QSlotType.rh, w));


There are caveats, though. Since the execution is delayed, the state of the objects can change at the moment of the animations end. You will need to handle it to ensure the game doesn't crash if, for example, the owner of inventory is killed before the animation ends :)

• Wouldn't it be better to use a callback function that runs after the animation finishes? – Garret Gang Jan 13 at 17:22
• Thanks for the answer reply :) What about using : Invoke("target method", delay value) I don't really know – Young Gilgamesh Jan 14 at 12:26
• As a mentioned in the reply, it all depends on what you actually need. In my opinion running actions with a simple delay doesn't make sense in this situation, but if you see it's ok for your game, then use it. However, even in this case I'd use a couroutine :) – real4x Jan 14 at 18:43