Hello, I am new to unity (and only have some experience in scripting) and I am stuck. I am trying to make a interval firing system where you fire a right weapon and then a left one. (Script below) Currently, the left weapon line renderer stays active whenever the timer for dual wield ends and the right weapon can not fire. I currently have two scripts interacting with each other to solve some other issues. I am very confused so any advice would be much appreciated. Thank you!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CardFiring : MonoBehaviour
{
/* TO DO
* Shots are being left in the air and never updated
* Left Weapon line always active
*/
public int gunDamage = 1;
public float fireRate = .5f;
public float weaponRange = 50f;
public Transform gunEndRight;
public Transform gunEndLeft;
public Camera fpsCam;
private WaitForSeconds shotDuration = new WaitForSeconds(.20f);
//private AudioSource gunAudio;
private LineRenderer laserLineRight;
private LineRenderer laserLineLeft;
private float nextFire;
private int layerMask = 10;
private bool rightWeaponFiring = true;
private bool justShot = false;
void Start()
{
laserLineRight = gunEndRight.GetComponent<LineRenderer>();
laserLineLeft = gunEndLeft.GetComponent<LineRenderer>();
//gunAudio = GetComponent<AudioSource>();
gameObject.layer = 8;
}
void Update() // Make it to where each line is fired at seperate times, so right shoots then left shoots .5 seconds later (Ex.)
{
if (ClassCard.cooldownQReadyGet() && justShot)
{
justShot = false;
rightWeaponFiring = !rightWeaponFiring;
}
if (Input.GetButtonDown("Fire1") && Time.time > nextFire && ClassCard.cooldownQReadyGet()) // Check if dualWeilding
{
nextFire = Time.time + fireRate;
justShot = true;
StartCoroutine(ShotEffect());
Vector3 rayOrigin = fpsCam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
laserLineRight.SetPosition(0, gunEndRight.position);
laserLineLeft.SetPosition(0, gunEndLeft.position);
if (Physics.Raycast(rayOrigin, fpsCam.transform.forward, out hit, weaponRange, ~layerMask))
{
laserLineRight.SetPosition(1, hit.point);
laserLineLeft.SetPosition(1, hit.point);
}
else
{
laserLineRight.SetPosition(1, rayOrigin + (fpsCam.transform.forward * weaponRange));
laserLineLeft.SetPosition(1, rayOrigin + (fpsCam.transform.forward * weaponRange));
}
}
if (Input.GetButtonDown("Fire1") && Time.time > nextFire)
{
justShot = true;
nextFire = Time.time + fireRate;
StartCoroutine(ShotEffect());
Vector3 rayOrigin = fpsCam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
laserLineRight.SetPosition(0, gunEndRight.position);
if (Physics.Raycast(rayOrigin, fpsCam.transform.forward, out hit, weaponRange, ~layerMask))
{
laserLineRight.SetPosition(1, hit.point);
}
else
{
laserLineRight.SetPosition(1, rayOrigin + (fpsCam.transform.forward * weaponRange));
}
}
}
private IEnumerator ShotEffect()
{
//gunAudio.Play();
if (rightWeaponFiring)
{
laserLineRight.enabled = true;
yield return shotDuration;
laserLineRight.enabled = false;
}
else
{
laserLineLeft.enabled = true;
yield return shotDuration;
laserLineRight.enabled = false;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClassCard : MonoBehaviour {
public int cooldownQ = 10;
public GameObject secondaryCard;
[HideInInspector]
public static bool cooldownQReady = true;
void Start ()
{
secondaryCard.SetActive(false);
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown("q") && cooldownQReady)
{
StartCoroutine(cooldownQTracker(cooldownQ));
}
}
public static bool cooldownQReadyGet()
{
return !cooldownQReady; // Has to be opposite, cant figure out how to do it any other way
}
public IEnumerator cooldownQTracker (int cooldownQ) // Implement double shot (share code with CardFiring script)
{
cooldownQReady = false;
secondaryCard.SetActive(true);
yield return new WaitForSeconds(cooldownQ);
secondaryCard.SetActive(false);
cooldownQReady = true;
}
}
Using a coroutine for a cooldown timer is almost ALWAYS the wrong approach. It’s simply not suited well to the problem.
This is a vastly simpler approach:
Cooldown timers, gun bullet intervals, shot spacing, rate of fire:
GunHeat (gunheat) spawning shooting rate of fire:
When tracking down complex multi-part bugs like this, what is often happening in these cases is one of the following:
the code you think is executing is not actually executing at all
the code is executing far EARLIER or LATER than you think
the code is executing far LESS OFTEN than you think
the code is executing far MORE OFTEN than you think
the code is executing on another GameObject than you think it is
To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.
Doing this should help you answer these types of questions:
is this code even running? which parts are running? how often does it run? what order does it run in?
what are the values of the variables involved? Are they initialized? Are the values reasonable?
are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)
Knowing this information will help you reason about the behavior you are seeing.
You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene
You could also just display various important quantities in UI Text elements to watch them change as you play the game.
If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.
Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:
You’re welcome! I’m sure you are fine… because Unity is used by such a wide range of people, there are demo videos of a bazillion different ways of doing things.
I’m not saying you CAN’T make a cooldown timer with a coroutine, I’m just saying it’s not the SIMPLEST way… and I like simple.
The reason I like simple is that I don’t like to confuse myself.
I wish coroutines were a criminally obscure feature, and any such knowledge considered an arcane magick written in some Unitynomicon. Alas.
I find them really good if one wants to hack a delay, make a simple tween, or do something clever with the frames, but whoever popularized a tutorial where they’re used for the game logic or instantiation should be co-routinely fired into the Sun.
It’s a common thing for junior programmers (especially those unaware of their juniority) to learn about the existence of a new hammer and now every problem they meet is a nail.
Coroutines are one example, but I’ve seen far more damage done with events in terms of turning a nice straightforward codebase into a spaghetti soup of incomprehensible un-debuggable genericized crap.