Wrong sprite is destroyed in Unity (DontDestroyOnLoad) - c#

I have a problem where I'm changing the Image of a SpriteRenderer as a onClick method is called.
However I had a problem of duplicates in the Scene after reloading it (i.e going out of the scene and then back again).
I have tried solving this by destroying the correct duplicate when reentering the scene. However, the old (changed) sprite (the one I would like to keep) keeps getting destroyed while the new one is still there.
This is part of my code for saving and destroying the sprite:
private void saveSprite(Clue c){
markedObjects.Add(c);
Debug.Log ("Save");
DontDestroyOnLoad (c.getSprite());
create = true;
}
private void destroySprite(Clue c){
foreach(Clue g in markedObjects){
print (g);
if (!markedObjects.Contains(c)){
Debug.Log("Destroy");
Destroy (c.getSprite());
}
}
}
I really don't understand how the destroySprite condition !markedObjects.Contains(c) can be passed while still destroying the incorrect sprite.
Any help would be greatly appreciated.

private void destroySprite(Clue c){ <-- I assume Clue c is the sprite you want to destroy
foreach(Clue g in markedObjects){ <-- get each Clue in markedObjects
print (g);
if (!markedObjects.Contains(c)){ <-- if c is not within all of markedObjects then destroy c? Perhaps you meant to destroy g.
Debug.Log("Destroy");
Destroy (c.getSprite());
}
}
}

Related

Unity MLAPI ServerRPC not getting called

I'm implementing a system in which a player can pickup an item from the game world. After picking the item up, I want to destroy the game object. To do this, I figured I'd make a ServerRPC that deletes the object, but the ServerRPC is not getting called. I tried making a ClientRPC as well, but that one isn't being called either. I noticed that it only gets called when the host of the game tries to pick up the item -- any ideas on how to fix this? The documentation is pretty bare but please let me know if I missed anything. Here is my code:
public override void Interact(GameObject player)
{
player.GetComponent<PlayerInventory>().AddItem(this.item);
Debug.Log("before");
TestClientRpc();
TestServerRpc();
}
[ServerRpc]
public void TestServerRpc()
{
Debug.Log("server");
// Destroy(gameObject);
}
[ClientRpc]
public void TestClientRpc()
{
Debug.Log("client");
// Destroy(gameObject);
}
EDIT: image of the components on the weapon
EDIT: This class extends a class that extends the networkbehaviour class. The objects are just sitting in the scene at start -- they are not spawned/instantiated (not sure if that matters or not).
The most plausible solution to this problem , either it is running into a error in some previous lines or as some other person pointed out , requireOwnership is not set to false .
For in depth analysis of MLAPI , https://youtube.com/channel/UCBStHvqSDEF751f0CWd3-Pg
I found the tutorial series on this channel best
I needed to add the following attribute to my ServerRpc:
[ServerRpc(RequireOwnership = false)]
since the player was not the owner of the item.
I have the same issue. Been looking at it for 2 days but I am inclined to think it is a bug to be honest.
I just spent 4+ hours banging my head against the wall because they didn't write this important info in the documentation. When calling ServerRpc from a client that doesn't own the Network Object, RPC attribute should be set to RequireOwnership = false.
For me the issue was that the GameObject(with NetwrokObject component) was sitting in the scene before starting the game, I couldn't use NetworkVariables nor ServerRpc. I think those are only usable on spawned object, but not sure. So I would say : either instantiate the object and add it to the NetworkManager or use normal variable on those objects.
Had the same issue but later realized I just forgot to inherit NetworkBehaviour
For Example:
using Unity.Netcode;
using UnityEngine;
class myObject : NetworkBehaviour {
public override void Interact(GameObject player)
{
player.GetComponent<PlayerInventory>().AddItem(this.item);
Debug.Log("before");
TestClientRpc();
TestServerRpc();
}
[ServerRpc]
public void TestServerRpc()
{
Debug.Log("server");
//Destroy(gameObject);
}
[ClientRpc]
public void TestClientRpc()
{
Debug.Log("client");
// Destroy(gameObject);
}
}
I had the same problem, where the ServerRpc wouldn't even be called. For me it worked after I made the GameObject that my script was attached to a prefab and added it to the NetworkManager's list of NetworkPrefabs.
Note: (I am using Netcode for GameObjects, I don't think it will be the same for other Multiplayer solutions)

How to unsubscribe from an event inside of the gamemanager?

In my GameManager script I have a delegate. In my Door script, I subscribe to this delegate. I've tried unsubscribing from it in both the OnDisable and OnDestroy methods in the Door script. In both cases, I get an error when I stop running the game in the editor:
Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)
Using Debug.Log, I found out that this is because the GameManager will always be destroyed before the Door script. Even if I do a null check inside either the OnDisable or OnDestroy of the Door script to see if the GameManager is null, I get the same error
if (GameManager.Instance)
{
GameManager.Instance.OnAllEnemiesKilled -= OpenDoor;
}
Somebody told me that I don't need to unsubscribe from it, as the delegate will automatically become null when the Door object is destroyed, but that's not true. During runtime, after the Door is destroyed, my update loop inside of the GameManager is still printing that the delegate has one subscriber: the Door.
I suspect you're spawning a new singleton when you call GameManager.Instance after it's been destroyed? If so, do something like this instead:
public class GameManager : MonoBehaviour
{
public static GameManager Instance
{
get
{
if (isDestroyed) return null;
// Your spawn logic...
}
}
static bool isDestroyed;
void OnDestroy()
{
isDestroyed = true;
}
}
As Lece pointed out, I'm spawning a new singleton when I call GameManager.Instance. Rather than creating a static bool to remedy the problem however, I replaced if (_instance == null) with if ((object)_instance == null) inside my Instance getter and it solved the problem. This is because, while the object is destroyed in the native code, it still exists in the managed code. So I'm now referencing it in the managed world. Moreover, Unity makes it so that when an object is destroyed in native code, its value in managed code will still return null.

Can't find object on loaded scene

I'm working on a save system and everything is working perfectly except one thing. When game is loading scene with actual level saved position of player won't set. I've tried to load it in additive mode and then unload the previous scene, but console only shows me that player couldn't be found. I checked multiple times for typo.
It worked one time when i putted function for checking if game was loaded. It looked like this
is_loaded = true;
SceneManager.LoadScene("scene_to_load");
And in another script linked with object on level
void Start()
{
if (is_loaded)
{
load();
}
}
void load()
{
//actual loading code
}
It's working but i don't like how this work. There must be a better way to do that.

Passing a boolean between different objects not working

I know this has been covered in the past, but I believe this issue is being caused by the update to Unity 5, thus deprecating the older information. No errors come up, but the debug won't come up. The public variable of 'pushBlockEnter' does become true visibly on the player script, but the pushBlock class will not recognize it no matter what. I just want to be able to check if a variable is true in one script from another script in Unity 5, any way of doing it would be fine. I'm sure it is something simple but I just can't figure it out...I should also mention that both scripts are on a different object. Thanks in advance!:
public class pushBlock : MonoBehaviour {
public Player playerScript;
void Update () {
if (GameObject.Find("Player").GetComponent<Player>().pushBlockEnter)
{
Debug.Log ("do something blahh");
//Do Anything
}
}
}
Figured it out:
GameObject playerReference = GameObject.Find("Player");
void Update(){
if (GameObject.Find("pushBlockCollider").GetComponent<pushBlockCollider>().inPushBlock){
Debug.Log ("got to pushblockCollider True");
}

Boolean seemingly changing itself (XNA)

I am currently working on a save system in my XNA game that fires off an event when it's finished saving.
My game has multiple screens which are managed by a screen manager, each screen has its own Update and Draw methods.
In the constructor, my _newSave boolean is flagged as true, this boolean starts off the game save process (which is managed by helper), and once it starts the process, it is flagged to false to prevent constant looping (since i only want to save once per save screen).
When helper is finished saving, it fires off the event, back inside the SaveScreen class, which sets _newSave back to true, and tells the ScreenManager to change screens.
Playing the game everything seems to work correctly, until the second time saving, when this save is attempted the game freezes. It is worth noting that this bool is private and only used in this method the 4 times shown (found usage by visual studio to confirm)
class SaveScreen : LoadingScreen
{
private bool _newSave;
private Player _player;
public SaveScreen(EventHandler screenEvent, ContentManager Content, GraphicsDevice GraphicsDevice, Player player)
: base(screenEvent, Content, GraphicsDevice)
{
screenTexture = Content.Load<Texture2D>("saving");
_newSave = true;
this._player = player;
helper.FinishedSaving = new EventHandler(FinishedSaving);
}
public override void Update(GameTime gameTime)
{
if (_newSave)
{
helper.RequestSave(_player);
_newSave = false;
}
helper.UpdateSaving();
base.Update(gameTime);
}
private void FinishedSaving(object o, EventArgs e)
{
_newSave = true;
screenEvent.Invoke(this, new EventArgs());
}
}
With a breakpoint inside the FinishedSaving event, i confirmed that the bool is changing to true, which is correct, however, a following breakpoint on the next save cycle on the if statement, shows that bool is false.
I am so completely confused by this, as the only _newSave = false statement is inside the if statement that needs to be true to access, the breakpoint inside the event shows that it is true, yet on the first "new" loop of the update code, it is false.
I am really pulling my hair out with this and cannot understand what's happening.
Any help is hugely appreciated, and i'm sorry if it's something silly, i'm a relatively new programmer :)
Thank You! <3
EDIT: Pastebin of entire Helper.cs class: http://pastebin.com/uJ0g6e00
Loading Screen Class: pastebin.com/8W8HxBnq
Screen Class: pastebin.com/qr29gzuq
Are you using multiple threads? If so, I wonder whether it's a race condition.
For example:
Update is called
Let's suppose that _newSave is true
RequestSave is called
Before RequestSave returns, Update is called again, but _newSave is still true...
I figured out the problem, apologies to everyone for wasting their time, and thank you for trying to help, turns out that simply switching the _newSave; = false and helper.RequestSave(_player); statements around fixed the issue, I thought that the problem was isolated into this class alone due it being the only place where the changes happened, in fact the issue was that i invoked the delegate inside the RequestSave method when the player score was not greater than the high score, this caused the code to then return to the if block and since the "_newSave = false;" statement was directly after the method call, it was reverting the statement back to false!
So silly of me but sometimes it's really hard to see the simple problems :P Thank you again!
<3

Categories

Resources