So in Unity2D lecture 93, there’s a bug with the “FireContinuously coroutine” where pressing multiple fire buttons result in the player ship permanently firing their weapon. The lecture addresses this by simply removing any additional keybinds, but I don’t want to remove the extra keybinds for convenience purposes. Any alternatives to fixing this problem?
Here’s my current source code as of 7/27/2020, 5:50pm
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.AssetImporters;
using UnityEngine;
using Random = UnityEngine.Random;
public class PlayerScript : MonoBehaviour
{
//Configuration parameters
[SerializeField] float moveSpeed = 10f;
[SerializeField] GameObject shipWeapon;
[SerializeField] float fireRate = 0.1f;
[SerializeField] float projectileSpeed = 25f;
[SerializeField] float randomFactor = 1f;
[SerializeField] float padding = 0.1f;
//Debug parameters
[SerializeField] bool ToggleDebugMode = false;
[SerializeField] bool DebugPosition = false;
[SerializeField] bool DebugMoveTilt = false;
[SerializeField] bool DebugTestFire = false;
//Coroutines
Coroutine firingCoroutine;
//Variables
float xMin, xMax;
float yMin, yMax;
// Start is called before the first frame update
void Start()
{
RestrainMovement();
//StartCoroutine(PrintAndWait());
}
// Update is called once per frame
void Update()
{
MoveShip();
FireWeapon();
}
/*****
* FIRE CONTINUOUSLY
*
* This enables the weapon to fire continuously while the FireWeapon() button is held.
*
* This entire code is inside a while loop, to ensure it continuously operates while the FireWeapon() button is held.
*
* The ship fires the weapon when "Fire1" is pressed, via Edit->Project Settings->Input Manager.
* Currently it should be binded to
* -[z] & [j] on keyboard,
* -PS???
* -XBOX???
* -[ZR](Joystick Button 7) & [A](Joystick BUtton 2) on Nintendo Switch Pro.
*
* GameObject "laser" variable is declared, and creates a clone of whatever is attached in "shipWeapon" GameObject.
* transform.position means the laser will be created at the ship's location.
* Quarternion.identity simply tells the program to not rotate the laser.
* as GameObject ensures the objects spawns as a GameObject.
*
* laser.GetComponent<RigidBody2D>().velocity retrieves the value of velocity from RigidBody2D component within the laser GameObject.
* laser.GetComponent<RigidBody2D>().velocity is assigning a velocity or speed of the projectile upon being spawned.
*
* WARNING: There's a bug that lets you fire more than one weapon if multiple FireWeapon() buttons are pressed.
* Please fix if you can!
*****/
IEnumerator FireContinuously()
{
while (true)
{
GameObject laser = Instantiate(shipWeapon, transform.position, Quaternion.identity) as GameObject;
laser.GetComponent<Rigidbody2D>().velocity = new Vector2(projectileSpeed, Random.Range(-randomFactor, randomFactor));
yield return new WaitForSeconds(fireRate);
}
}
/*****
* PRINT AND WAIT
*
* Made as an introduction to StarCoroutine & IEnumerator. Can be ignored.
*****/
/*
IEnumerator PrintAndWait()
{
Debug.Log("Next message will be delayed!");
yield return new WaitForSeconds(3);
Debug.Log("This is delayed by 3 sec!");
}
*/
/*****
* RESTRAIN MOVEMENT
*
* Limit's the player's ship position to be in the game screen.
*
* Declares a Camera type variable, necessary to access ViewportToWorldPoint.
* The coordinate and position of the camera is as follows:
* -(0, 0): Bottom-left
* -(1, 0): Bottom-right
* -(0, 1): Top-left
* -(1, 1): Top-right
*
* "xMin, xMax, yMin, yMax," variables is used to establish boundary coordinates on the camera,
* then the camera's coordinates are converted via "gameCamera.ViewportToWorldPoint(new Vector3(x, y, z))"
* to standard object coordinates.
* Padding is in the equation to ensure the ship is semi-fully onscreen instead of half-screen.
* xMax has a max border of 0.67f to ensure players aren't killed by enemy ships/attacks offscreen to the right,
* and can see the enemy ship/attack coming.
*****/
private void RestrainMovement()
{
Camera gameCamera = Camera.main;
xMin = gameCamera.ViewportToWorldPoint(new Vector3(0, 0, 0)).x + padding;
xMax = gameCamera.ViewportToWorldPoint(new Vector3(0.67f, 0, 0)).x - padding;
yMin = gameCamera.ViewportToWorldPoint(new Vector3(0, 0, 0)).y + padding;
yMax = gameCamera.ViewportToWorldPoint(new Vector3(0, 1f, 0)).y - padding;
}
/*****
* MOVESHIP
*
* Instructs the game to move the playerShip, via Edit->Project Settings->Input Manager.
* By default, "Horizontal" should be binded to, "Left Arrow, Right Arrow, A, and D,"
* while "Vertical" should be binded to, "Up arrow, Down arrow, W, and D."
*
* Using [Input.GetAxis("String name");] is better than [Input.GetKey("String name" or KeyCode.(Keycode))]
* Because Input.GetAxis is compatible with controllers.
*
* Putting in "Time.deltaTime" ensures the player's ship moves at the same speed, regardless of the PC's framerate.
* Without it, everything in the game would move slower on weaker PCs, and faster on stronger PCs.
*
* Mathf.Clamp() is there to ensure the player's ship does not fly offscreen.
*****/
private void MoveShip()
{
//Declares and makes these variables equal to the "tilt rate" of the controller/keyboard.
var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
//newXPos & newYPos are declared as the current gameObject's position,
//plus the direction the player has pressed, or tilted on controller.
var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
//Assigns this gameObject's position to be equivalent to newXPos & newYPos.
transform.position = new Vector2(newXPos, newYPos);
//DEBUG
if (ToggleDebugMode)
{
if (DebugPosition)
{
//Returns the player ship's position.
Debug.Log(transform.position.x + ", " + transform.position.y);
}
if (DebugMoveTilt)
{
//Returns the tilt rate of the player's direcitonal input.
Debug.Log(deltaX + ", " + deltaY);
}
}
}
/*****
* FIRE WEAPON
*
* Shoots a laser beam.
*
* Refer to IEnumerator FireContinuously().
* Earlier a "Coroutine firingCoroutine" was declared. Firing Coroutine is assigned to the IEnumerator FireContinuously()
* So it can be easily turned off when the FireWeapon() button is lifted.
*
*
*
* BELOW IS PLANNED FEATURE FOR THIS METHOD.
*
* Shoots the currently equipped weapon.
*****/
private void FireWeapon()
{
if (Input.GetButtonDown("Fire1"))
{
firingCoroutine = StartCoroutine(FireContinuously());
if (DebugTestFire)
{
Debug.Log("Pew!");
}
}
if (Input.GetButtonUp("Fire1"))
{
StopCoroutine(firingCoroutine);
}
}
}