Reputation: 11
So I am making a VR game and what I want to do is, as soon as I press the trigger on the joystick the "sword" gets activated and can stay activated for 1 second, after that it has a cooldown of 1 second also in which it cannot get activated, and then it resets. I thought it would be simple but I can't for the life of me make it work.
Here's the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
public class Sword : MonoBehaviour
{
public SteamVR_Action_Boolean ActivateSword;
public SteamVR_Input_Sources handType;
private bool IsSwordActivated = false;
private bool canSwordGetActivated = true;
private bool cooldownStart = false;
public Material activatedSword;
public Material defaultSword;
public float timeStamp;
public float timer = 0;
public float cooldown = 2;
void Start()
{
ActivateSword.AddOnStateDownListener(TriggerDown, handType);
ActivateSword.AddOnStateUpListener(TriggerUp, handType);
timeStamp = Time.time;
}
public void TriggerUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
Debug.Log("Trigger is up");
IsSwordActivated = false;
this.GetComponent<MeshRenderer>().material = defaultSword;
}
public void TriggerDown(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
if (canSwordGetActivated == true)
{
Debug.Log("Trigger is down");
IsSwordActivated = true;
cooldownStart = true;
this.GetComponent<MeshRenderer>().material = activatedSword;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
if (IsSwordActivated == true)
{
Destroy(collision.gameObject);
}
}
}
private void Update()
{
//if (timeStamp <= Time.time)
//{
// if (IsSwordActivated == true)
// {
// timeStamp += 2;
// canSwordGetActivated = false;
// Debug.Log("test");
// }
//}
if (cooldownStart == true)
{
timer += Time.deltaTime;
cooldown -= Time.deltaTime;
if (timer >= 1f)
{
this.GetComponent<MeshRenderer>().material = defaultSword;
IsSwordActivated = false;
timer = 0;
}
if (timer == 0)
{
canSwordGetActivated = false;
}
if (cooldown <= 1f)
{
canSwordGetActivated = false;
}
if (cooldown <= 0)
{
cooldown = 2f;
canSwordGetActivated = true;
cooldownStart = false;
}
}
}
}
Upvotes: 0
Views: 71
Reputation: 13624
One simple way of doing this would be a coroutine:
class Sword {
private bool isCoolingDown;
public void Swing() {
if (isCoolingDown) {
Debug.Log("Sorry, cooling down right now");
return;
}
StartCoroutine(DoSwingSword());
}
private IEnumerator DoSwingSword() {
isCoolingDown = true;
yield return new WaitForSeconds(1);
isCoolingDown = false;
}
}
This will use a bool
to track if you are in cooled down state and automatically reset this bool
after one second, without you having to track Time.deltaTime
. You can then wrap the rest of your logic around this bool
.
Upvotes: 0
Reputation: 90629
You should not use Update
but a Coroutine for that. Especially the "cooldown" should run independently from the "timer".
// Not needed
//private bool cooldownStart = false;
//public float timer = 0;
// reference this already via the Inspector if possible
[SerializeField] private MeshRenderer _meshRenderer;
[SerializeField] private float cooldownTime = 1;
[SerializeField] private float maxEnabledTime = 1;
// Otherwise get it only ONCE on runtime
private void Awake()
{
if(!_meshRenderer) _meshRenderer = GetComponent<MeshRenderer>();
}
public void TriggerUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
Debug.Log("Trigger is up");
// stop the timeout
StopAllCoroutines();
// disable sword and start cooldown
StartCoroutine(SwordCooldown());
}
public void TriggerDown(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
if(IsSwordActivated) return;
if (!canSwordGetActivated) return;
Debug.Log("Trigger is down");
// start timeout
StartCoroutine(SwordEnabledTimer());
}
///<summary>
/// Disables sword and Runs cooldown before sword can be enabled again
///<summary>
private IEnumerator SwordCooldown()
{
canSwordGetActivated = false;
IsSwordActivated = false;
_meshRenderer.material = defaultSword;
yield return new WaitForSeconds(cooldownTime);
canSwordGetActivated = true;
}
///<summary>
/// Disables the sword and jumps to cooldown after it was enabled for too long
///<summary>
private IEnumerator SwordEnabledTimer()
{
canSwordGetActivated = false;
yield return new WaitForSeconds(maxEnabledTime);
StartCoroutine(SwordCooldown());
}
See WaitForSeconds
Sideeffect/Advantage:
Coroutines are often better read- and maintainable and more flexible then polling states in Update
!
For example You can now very simple extend both routines and add a progress display for both like e.g.
private IEnumerator SwordCooldown()
{
canSwordGetActivated = false;
IsSwordActivated = false;
_meshRenderer.material = defaultSword;
var timePassed = 0f;
while(timePassed < cooldownTime)
{
var cooldownProgress = timePassed / cooldownTime;
// do something with the cooldownProgress value 0-1
timePassed += Mathf.Min(Time.deltaTime, cooldownTime - timePassed);
yield return null;
}
canSwordGetActivated = true;
}
Upvotes: 2