I have the following function to manage the reloading process of my player's gun in my game. I call the function from an AmmoCheck function and it runs, however the if statement is never run because the input doesn't get detected. The line:
Debug.Log("Reload function check");
will print to the console, but nothing further.
I have made sure the Input is set up under Edit>Project Settings>Input, and it is set to the r button. (Proof - http://i.imgur.com/u2aVNpU.png )
The function:
void gunReload()
{
Debug.Log("Reload function check");
if (Input.GetButtonDown("Reload")) {
Debug.Log("Reloading");
if(changeWeapon.currentGun == changeWeapon.gunPistol) {
aReload.SetActive(false);
// Incrementing the aClipPistolCurrent value by 1 so the current clip "should" progress one along? idk
aClipPistolCurrent += 1;
}
if(changeWeapon.currentGun == changeWeapon.gunAssault) {
aReload.SetActive(false);
// Incrementing the aClipPistolCurrent value by 1 so the current clip "should" progress one along? idk
aClipAssaultCurrent += 1;
}
}
}
Function calling gunReload();
gunAmmoCheck() is being called inside of Update()
void gunAmmoCheck()
{
if(changeWeapon.currentGun == changeWeapon.gunPistol && aClipPistol[aClipPistolCurrent] > 0) {
gunFire ();
// Reducing the ammo of the current clip by 1.
// ClipPistol is being used (say array, why array
aClipPistol[aClipPistolCurrent] -= 1;
}
if(changeWeapon.currentGun == changeWeapon.gunAssault && aClipAssault[aClipAssaultCurrent] > 0) {
gunFire ();
// Reducing the ammo of the current clip by 1.
// ClipPistol is being used (say array, why array
aClipAssault[aClipAssaultCurrent] -= 1;
}
if(aClipPistol[aClipPistolCurrent] == 0)
{
Debug.Log ("Reload");
// Activating the reload notification on the interface
aReload.SetActive(true);
gunReload();
}
if(aClipAssault[aClipAssaultCurrent] == 0)
{
Debug.Log ("Reload");
// Activating the reload notification on the interface
aReload.SetActive(true);
noAmmo = true;
gunReload();
}
}
I'm at a loss here, since all of my other inputs work flawlessly. Any help would be greatly appreciated.
I just tested this and it worked. I am starting to think that the problem is where you are calling the function from. Not sure yet but
Lets find the problem slowly. Can you comment out those things in your function and have only
void gunReload ()
{
//Debug.Log ("Reload function check");
if (Input.GetButtonDown ("Reload")) {
Debug.Log ("Reloading");
}
}
in your code. Then call gunReload () from the Update and tell me if it works.
It would also be good to pose the function you are calling gunReload () from.
Related
I have a joystick display picture for my game. Currently, when the player touches the screen the image disappears and when the player is not touching the screen, it reappears. I wrote that using an if else statement.
if (indicator.inputIndicator.x != 0)
{
joystick.SetActive(false);
}
else
{
joystick.SetActive(true);
}
The problem is, I want the image to reappear after some time like 2 seconds. I want to delay the "else", but I do not want to use a coroutine. I want "else" to work after 2 seconds since the player takes his hand off the screen but I couldn't figure out how to do it. any help will be great.
Setting a timer is a pretty common problem you have to solve in Unity. One basic approach is to have a variable that you add Time.deltaTime every update. That way you can tell how long it has been since some condition was met.
Every Update iteration that meets the condition, add Time.deltaTime to the variable. If at some point the condition fails, reset the variable to 0. Then you can just base your joystick.SetActive() call on the value of your variable.
For example, your script might become:
float thresholdTimeToShowPrompt = 2;
// By starting at the threshold, the image is hidden at the start until a touch
float timeSincePlayerTouch = 2;
void Update()
{
// Rather than calling SetActive directly, just update the timer
if (indicator.inputIndicator.x != 0)
{
timeSincePlayerTouch = 0;
}
else
{
timeSincePlayerTouch += Time.deltaTime;
}
// Now we can base visibility on the time since the last user touch
bool shouldShowIcon = timeSincePlayerTouch >= thresholdTimeToShowPrompt;
// Only call SetActive when needed, in case of overhead
if (shouldShowIcon && !joystick.activeSelf)
{
joystick.SetActive(true);
}
else if (!shouldShowIcon && joystick.activeSelf)
{
joystick.SetActive(false);
}
}
I have written a function on a script that activates when the player loses all his lives. That calls a CoRoutine in a script attached to my main character that makes a simple death animation and then moves to the game over screen. Debug.Log shows that the function calls, and when I use non-CoRoutine functions attached to the main character, those functions call to. However, the CoRoutine itself never calls, not even showing the log of it ever activating? Does anyone know what is up?
Code included below:
if (GameObject.Find("Heart 1") == null)
{
Debug.Log("Naw");
player.DeathAnimation(20);
Debug.Log("still not working");
}
public IEnumerator DeathAnimation(int i)
{
int k = i;
Debug.Log("Numerator works");
transform.Rotate(Vector3.forward * 9);
yield return new WaitForSeconds(.08f);
k--;
Debug.Log(k);
if (k <= 0)
{
SceneManager.LoadScene("Game Over");
yield break;
}
StartCoroutine(DeathAnimation(k));
}
There doesn’t seem to be a reason to make this a recursive coroutine. I’d suggest removing the recursion which might also solve the issue you’re having or at least make it simpler to identify.
if (GameObject.Find("Heart 1") == null)
{
Debug.Log("Hmm");
StartCoroutine( player.DeathAnimation(20) );
Debug.Log("maybe working");
}
…
public IEnumerator DeathAnimation(int i)
{
Debug.Log("Numerator works");
for( ; i>0; i-- ) {
transform.Rotate(Vector3.forward * 9);
yield return new WaitForSeconds(.08f);
Debug.Log(i);
}
SceneManager.LoadScene("Game Over");
}
I'm pretty new to coding, been learning for the past year and I'm currently working on an assignment for school and i can't figure out this bit of code for the love of my life.
I have an item that when the player interacts with it, executes this:
void Update ()
{
if (isPlayerNear && Input.GetKeyDown(KeyCode.E) && Avatar.strenghtAttribute >= 2f)
{
levelUp.LevelUp();
Destroy(gameObject);
}
My level up function is basically this:
public void LevelUp()
{
playerLevelText.text = ("You have gained a level!");
strenghtAttribute++;
intellectAttribute++;
playerLevel++;
}
I'm trying to figure out how to make playerLevelText.Text appear on the screen but only appear for a few seconds and I can't figure out how to make that work. Would anyone be kind enough to give me a hand?
You could either set the text to be blank, or enable/disable the text object. I'd recommend using a coroutine for this.
void Update ()
{
if (isPlayerNear && Input.GetKeyDown(KeyCode.E) && Avatar.strenghtAttribute >= 2f)
{
levelUp.InitializeLevelUp());
Destroy(gameObject);
}
Since you are destroying the gameobject calling the coroutine, the coroutine will stop. A workaround is to call a normal function in your other script, which then calls the coroutine, so execution stays within the one script (there might be a cleaner way to do this).
public void InitializeLevelUp()
{
StartCoroutine(LevelUp());
}
public IEnumerator LevelUp()
{
playerLevelText.text = ("You have gained a level!");
strenghtAttribute++;
intellectAttribute++;
playerLevel++;
yield return new WaitForSeconds(2f);
playerLevelText.text = "";
//alternatively, set the text object inactive
}
I have met a strange problem when using Coroutine in Unity. Before modification, my code is as the following:
IEnumerator Destory()
{
yield return new WaitForSeconds(destoryDelay);
yield return StartCoroutine(Timer.Start(0.5f, false, gameManager.EnableBtnSummon));
GameObject.Destroy(this.gameObject);
}
Time.Start() is an utility written by myself and used for delay invoke.
public static IEnumerator Start(float duration, bool repeat, Action callback)
{
do
{
yield return new WaitForSeconds(duration);
if (callback != null)
callback();
} while (repeat);
}
Because Time.Start() includes WaitForSeconds(), so I decided to modify above code as the following:
IEnumerator Destory()
{
//yield return new WaitForSeconds(destoryDelay);
yield return StartCoroutine(Timer.Start(destoryDelay+0.5f, false, gameManager.EnableBtnSummon));
GameObject.Destroy(this.gameObject);
}
Unfortunately, console throw an error:
ArgumentException: Value does not fall within the expected range.
gameManager.EnableBtnSummon is just an Action processing game logic. After debug, i make sure that error occurred before this function run. But i will show it for more clues.
public void EnableBtnSummon()
{
//will not reach this!
print("Enable Button Summon");
//if detecting monster, change relative sprite of monster medal
if (currentMonsterIndex != -1)
{
Image captureMonsterSprite = monsterMedalList.transform.GetChild(currentMonsterIndex).GetComponent<Image>();
captureMonsterSprite.sprite = mosnterExplicitMedalList[currentMonsterIndex];
Image gameOverMonsterSprite = gameOverMonsterList.transform.GetChild(currentMonsterIndex).GetComponent<Image>();
gameOverMonsterSprite.sprite = mosnterExplicitMedalList[currentMonsterIndex];
currentMonsterIndex = -1;
captureMonsterCount++;
}
if (captureMonsterCount == monsterIndexDictionary.Count) return;
var summonAnimator = btnSummon.GetComponent<Animator>();
summonAnimator.SetBool("isSearch", false);
btnSummon.enabled = true;
btnExit.enabled = true;
fogParticleSystem.Play();
}
I cannot understand it, could someone tell me what happens? thx...
The exception:
ArgumentException: Value does not fall within the expected range.
is happening on this line of code:
yield return StartCoroutine(MoveTowards.Start(destoryDelay + 0.5f, false, gameManager.EnableBtnSummon));
This has nothing to do with StartCoroutine as the title of the question says. The source of the problem is the MoveTowards.Start coroutine function. The third parameter(Action callback) that is passed into it is the issue.
The issue is that you are passing null to the third parameter of the MoveTowards.Start function. Since you are passing gameManager.EnableBtnSummon to that third parameter, this means that the gameManager variable is null.
You can verify this by adding Debug.Log(gameManager) before that line of code. The output should be "null" in the Console tab.
FIX:
Initialize the gameManager variable:
Name the GameObject your GameManager script is attached to "ManagerObj" then use the simple code below to initialize the gameManager variable.
GameManager gameManager;
void Awake()
{
gameManager = GameObject.Find("ManagerObj").GetComponent<GameManager>();
}
Note:
Rename your Start function to something else as there is already Unity built in function named "Start" and "Awake". You need to change the name to something else but this is not the problem.
Currently I'm simply trying to change the sprites candle from unlit to lit when the player has 'picked up' both the candle and the matches and the candle will 'go out' after a certain amount of time. However, when the space bar is pressed the transition from unlit to lit isn't occurring, even though the debug log is returning true when it should. I'm posting here to get some guidance as I have spent most of the day looking online and literally have no idea how to proceed.
Basically the images I am trying to transition between are two different images which are in the sprites folder under assets.
This is what I've got so far.
//the two sprites transition
public Sprite unlitCandle;
public Sprite litCandle;
private SpriteRenderer spriteRenderer;
bool pickUpMatches = false;
bool pickUpCandle = false;
float timeRemaining =5;
bool candleLit = false;
// Use this for initialization
void Start () {
spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite == null)
spriteRenderer.sprite = unlitCandle;
}
// Update is called once per frame
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.CompareTag("Matches"))
{
collision.gameObject.SetActive(false);
pickUpMatches = true;
}
if (collision.gameObject.CompareTag("UnlitCandle"))
{
collision.gameObject.SetActive(true);
pickUpCandle = true;
}
}
public void CandleTimer()
{
if (candleLit == true)
{
timeRemaining = 5;
timeRemaining -= Time.deltaTime;
if (timeRemaining <= 0)
{
candleLit = false;
spriteRenderer.sprite = unlitCandle;
}
}
}
public void ChangeSprite()
{
if (spriteRenderer.sprite == unlitCandle)
{
spriteRenderer.sprite = litCandle;
}
}
void Update () {
if (pickUpCandle == true && pickUpMatches == true)
{
//Debug.Log(candleLit);
if (Input.GetKey(KeyCode.Space) && !candleLit)
{
CandleTimer();
ChangeSprite();
Debug.Log(timeRemaining);
candleLit = true;
//Debug.Log(candleLit);
}
}
}
}
Try comparing with a method like equals() instead of == in
spriteRenderer.sprite == unlitCandle
Because right now you are just comparing references and not the objects.
At least I think thats the problem.
There are a few possible issues with your code. First, you are calling changeSprite at the top of Update, which means that it is unconditionally being called every frame. Therefore, after a single frame of your candle being unlit, it will immediately change its sprite to litCandle.
I assume that the reason you are calling changeSprite every frame is in order to process the timer if you have a lit candle already. Really, you should move the code to process the timer (your whole second if statement in changeSprite) to a separate function and name it something like processCandleTimer. Call that at the top of Update and save the changeSprite method to only be called on the keypress.
Lastly, the issue that I suspect is giving you the most trouble is that you aren't resetting your timer, timeRemaining. The first time you light the candle the timer will go down to 0 after the 5 seconds pass. Every time changeSprite is run after that, you will change the sprite to litCandle in the first if statement and then immediately change it back to unlitCandle because the timer is 0 in the second. To remedy this, you need to add a line like timeRemaining = 5.0f; when the key is hit.