Unity inactive object destroyed - unity3d

So after my player hits 0 HP, the player object (in my case a rocket ship) is set to false and the Game Over UI is set to true. Then the player has two options: either to restart or resume the game. Only resuming the game plays an ad, but after the ad is done playing the game doesn't continue and I get the error saying "The object of type 'GameObject'(The Game Over UI) has been destroyed but you are still trying to access it". Now I know that this happens when I specifically destroy an object, but not when I set the object to inactive.
Game Over function
private void GameOver()
{
Time.timeScale = 0f;
GameOverUI.SetActive(true);
finalScore.text = score.ToString() + " Meters";
PlayerPrefs.SetFloat("Score", 0);
totalCash.text = PlayerPrefs.GetFloat("Cash", 0).ToString() + " Cash";
highScoreTracker.text = PlayerPrefs.GetFloat("HighScore", 0).ToString() + " Meters";
}
Resume function called from Ads Manager after ad is played
public void ResumeGame()
{
GameOverUI.SetActive(false);
this.gameObject.SetActive(true);
PlayerPrefs.SetFloat("Score", score);
Time.timeScale = 1.0f;
}
Ads Manager function
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
if (activeScene == "InitialEarth" || activeScene == "Earth" || activeScene == "Space" && showResult == ShowResult.Finished)
{
player.ResumeGame();
timesWatched++;
if (timesWatched >= 2)
{
adButton.interactable = false;
}
}
}
The error is pointing to the lines "GameOverUI.SetActive(false)" and "player.ResumeGame()".
I've tried keeping the player object active when its game over but same error. I have a similar function, like my Pause UI, where it's inactive initially and with a button click, its set to active and then inactive again and that works fine.
I'm not sure what's wrong or where to look. Is there another way to deactivate and active object? Why would an inactive object give a destroyed error, since its still in the game hierarchy? Any help or pointers would be much appreciated. If more info is needed, please let me know. Thanks.

Related

After pause menu score doesn't work anymore

does anyone know how to fix this? In my unity game when I go to pause menu and then continue playing, my scoreboard stops updating. I have two scoreboards, one in game and one in pause menu. The one in pause menu works well and updates but the one in game freezes after once visited in pause menu.
Here is my pausecodes and codes to add money (score):
public void PauseGame()
{
Time.timeScale = 0;
}
public void UnPauseGame()
{
Time.timeScale = 1;
}
}
if (collision.gameObject.tag == "Respawn") // When player lifts fish up
{
Destroy(this.gameObject);
// TODO: Player gets money (points) when this happens
textManager.instance.AddMoney();
Debug.Log("Add money");
}
public class textManager : MonoBehaviour
{
public static textManager instance;
public Text moneyText;
public int money;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
Data data = SaveSystem.LoadData();
money = data.balance;
moneyText.text = "Balance: " + money.ToString() + " $";
}
public void AddMoney()
{
money = money + 10;
moneyText.text = "Balance: " + money.ToString() + " $";
SaveSystem.SaveData(this);
}
public int findMoney()
{
return money;
}
}
Please ask more info if needed.
I have tried to delete the one scoreboard in pause menu and after that the in-game pause menu started working right, but I would like to have still that other scoreboard too.
if (collision.gameObject.tag == "Respawn") // When player lifts fish up
{
// TODO: Player gets money (points) when this happens
textManager.instance.AddMoney();
Debug.Log("Add money");
Destroy(this.gameObject);
}
As I said this is the fix for what you posted as for the pause unpause problem you have to post the actual code where you do the pause unpause behavior so can people help you out my friend. As for what you posted what you've been doing is destroying the script just before excuting the call to textManager.instance.AddMoney(); and this will never run in the order you set in your code.
The scope of a static field is global, this means there can only be one.
Your textManager (side note: a classes first letter has to be upper case) is certainly attached to multiple GameObjects, once to the object displaying the score in the scene UI and once to a UI element in the pause menu.
As soon as you pause your game the first time, the TextManager attached to the object in the pause menu will run Awake() and the instance (please capitalise your properties as well) will be overriden and the reference to the ingame TextManager gets discarded.
The sloppy fix is re-initializing the ingame TextManager when you unpause the game, assigning it to be the Instance again. I'd not recommend doing that though.
The better solution is to implement an event on the player that gets triggered when the score changes and making the player instance a Singleton object since there will be only one player in all circumstances.
The UI elements displaying the score can then subscribe to this event in OnEnable() and unsubscribe in OnDisable() (do not forget to unsubscribe from events).
Addendum: You should not destroy your object before all code has been executed. Your code will still work because of how things are managed on the C++ layer of Unity, but it is definitely bad practice.

Cant get my player to jump /get detached from a rope

I Have a player which gets childed to a game object when it walks up to a trigger now I want the player's parent to become null again after space is pressed because I'm trying to make a rope system, and it's required for the player to be able to de-attach from the rope
This is the script that's supposed to attach/detach the player from the rope
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttachToRope : MonoBehaviour
{
public GameObject objectToParentTo;
public GameObject objectWithSwingScript;
// Start is called before the first frame update
private void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Rope")
{
transform.parent = objectToParentTo.transform;
objectWithSwingScript.GetComponent<playerscript>().enabled = true;
GetComponent<PlayerController>().enabled = false;
GetComponent<CharacterController>().enabled = false;
GetComponent<Swinging>().enabled = false;
}
}
private void OnTriggerStay(Collider collider)
{
if (Input.GetButtonDown("Jump"))
{
transform.parent = null;
objectWithSwingScript.GetComponent<playerscript>().enabled = false;
GetComponent<PlayerController>().enabled = true;
GetComponent<CharacterController>().enabled = true;
GetComponent<Swinging>().enabled = true;
Debug.Log("Deattached");
}
}
}
What happens when the player enters the trigger is that the scripts that make the player move get disabled and then it gets chilled to the last section of the rope now in ontriggerstay i want it to check if space is pressed and re-enable all the scripts that are required for the player to move (which does not work) but since nothing in there works i tried to debug.log but even that does not work so if anyone knows how to fix this please help me
From the OnTriggerStay documentation: The function is on the physics timer so it won't necessarily run every frame.
Functions on the physics timer (e.g. FixedUpdate()) don't play nicely with Input.GetButtonDown because they don't run every frame. Instead, they run on a fixed timestep, 0.02 seconds by default.
The solution is to put calls to Input.GetButtonDown into Update(). For instance, in this example you could have a boolean member variable isJumpPushed and set it to true in Update() when the jump button is pushed and the player is attached, and then check that value in OnTriggerStay.
--
A note about debugging:
I tried to debug.log but even that does not work
If your Debug.Log isn't showing a log in the console, that still tells you something important. It tells you that code path isn't getting called. That's an important clue for you to figure out what's really going on. To further narrow down the problem, you could move the Debug.Log statement outside the if statement. This would show that it's Input.GetButtonDown that isn't returning true when you think it is.

Keeping variable from changing on another scene load

I'm new to unity and i'm trying to load scenes based on items collected.
Problem is that the counter is not counting my acquired items.
I'm using OnTriggerEnter2D() to trigger the event; Below is the snippet:
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
collectionNumber += 1;
Destroy(gameObject);
if (collectionNumber == 1)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(0).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(0).gameObject.SetActive(true);
}
else if (collectionNumber == 2)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(1).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(1).gameObject.SetActive(true);
}
else if (collectionNumber == 3)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(2).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(2).gameObject.SetActive(true);
}
else
{
Debug.LogWarning("All Items Collected !!");
}
cN.text = "Collection Number " + collectionNumber.ToString();
}
}
Whenever a new scene is loaded this script is loaded because it is on my quest item. And for every scene there is a quest item. So what I want to do is basically keep track of my collectionNumber, but it resets to 0.
Any help is much appreciated :)
First method:
Don't allow your object to be destroyed on scene load
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
public static void DontDestroyOnLoad(Object target);
Above code will prevent destroying your GameObject and its components from getting destroyed when loading a new scene, thus your script values
Second Method:
Write out your only value into a player pref
https://docs.unity3d.com/ScriptReference/PlayerPrefs.html
// How to save the value
PlayerPrefs.SetInt("CollectionNumber", collectionNumber);
// How to get that value
collectionNumber = PlayerPrefs.GetInt("CollectionNumber", 0);
Third method:
Implement a saving mechanism:
In your case i would not suggest this

How to transfer a VR button ownership using Photon2?

I am currently working on a project and I want to use several buttons in my multiplayer game.
Unfortunately the button can only be pushed locally and it's not synced over the network.
For some reasons the game doesn't trigger the script that should transfer the ownership to the player
I don't really know what's going on and why this isn't triggered ...
I already tried to ad photon tranform views on the moving part and the button itself but without results
private void OnTriggerEnter(Collider other)
{
if(other.name == "LHand" || other.name == "RHand")
{
ChangeOwnership(other);
}
print("trigger entered but not a hand");
}
public void ChangeOwnership(Collider col)
{
if (GetComponent<PhotonView>().Owner != col.GetComponent<PhotonView>().Owner)
{
GetComponent<PhotonView>().TransferOwnership(col.GetComponent<PhotonView>().Owner);
print("changed ownership to: " + col.GetComponent<PhotonView>().Owner);
}
}
If the trigger is actually entered this should show the player as the owner and not the scene...
So if someone has a clue about this I'll take it ...

Unity 2D same state for different enemies issue

I'm making 2D platformer and im getting weird bug - when i hit one enemy, every one else of that type getting the same state. I mean i wanted them to enter "angry" state when my player hit one of them with sword.
Problem looks like this:
->Hit Enemy1 with sword,
->Enemy1 is getting damage and going to "angry" state,
->Enemy2/3/4/5 didn't get damage, but went in "angry" state.
If getting damage is individual for every one of them so why am i suffer that kind of situation. I think the cause is in my Damage Script. If anyone have an idea i would be glad to hear it. Thanks in advance.
public void DealDmg()
{
blob = FindObjectOfType<EnemyScript>();
if (attackPos.gameObject.activeSelf == true)
{
Collider2D[] enemiesToDamage = Physics2D.OverlapCircleAll(attackPos.position, attackRange, whatIsEnemy);
for (int i = 0; i < enemiesToDamage.Length; i++)
{
EnemyScript enemyScript = enemiesToDamage[i].GetComponent<EnemyScript>();
enemyScript.GetComponent<EnemyScript>().TakeDmg(damage);
if (gameObject.GetComponent<PlayerControls>().facingRight == true)
{
enemyScript.GetComponent<Rigidbody2D>().AddForce(new Vector2(30f, 20f), ForceMode2D.Impulse);
StartCoroutine("ResetValues");
blob.CalmLogic();
}
else if (gameObject.GetComponent<PlayerControls>().facingRight == false)
{
enemyScript.GetComponent<Rigidbody2D>().AddForce(new Vector2(-30f, 20f), ForceMode2D.Impulse);
StartCoroutine("ResetValues");
blob.CalmLogic();
}
}
attackPos.gameObject.SetActive(false);
}
}
public IEnumerator ResetValues()
{
gotHit = true;
blob.gotAngry = true;
yield return new WaitForSeconds(resetValuesDelay);
gotHit = false;
yield return new WaitForSeconds(resetValuesDelay);
blob.gotAngry = false;
}
Track enemy state inside the enemy
Right now it looks like your code is running on the player and the player is keeping track of enemy state. This is wrong. Your player script should never know anything about (much less modify!) the properties of your enemy. All the player should do is:
when the player successfully hits an enemy, the player tells the enemy "you've been hit!"
The enemy script then takes that information (such as how much damage, what damage type it was, etc) and deal with itself: reducing the damage ("am I wearing armor?"), enhancing the damage ("am I weak to fire?") and so on and so forth...like getting angry at the player and the resulting cooldown before its calm again.
Your player script does not need to know (and does not care!) about this information and any attempt to try and handle it here is folly. As soon as you change how many enemies there are, or create a new enemy type that does something ELSE you end up with a giant pile of useless junk you can't manage.