- Home /
non-static variable behaving like static (C#). Very confused.
So I have a prefab item in Unity called GameFrame with the script GameFrame attached to it. I have 2 instances of this prefab in my scene and for some reason the variable firstSelectedBlock is behaving as if it was static. The code swaps two blocks when you click on two that are right next to each other. When you click a block that ISN'T right next door it selects that block instead. Everything works fine. happy fun times.
HOWEVER, if I create 2,3,4 instances of the GameFrame prefab if I click a block in ANY of them it sets the firstSelectedBlock variable in all of them. The variable was originally private but I switched it to public just so I could watch it at run time easily and sure enough they are all synchronized at all times.
Am I missing something silly? I'm really lost on this one.
Thanks in advance for any help.. code below.
using UnityEngine;
using System.Collections;
public class GameFrame : MonoBehaviour {
public GameObject blockLifter;
public GameObject[] basicBlocks;
public LayerMask gameBlockMask;
private Vector2 blockSpacing = new Vector2(21,20);
private int levelHeight=5;
private int gameWidth=6;
private float xStartPosition;
private GameObject currentLifter;
private int liftSpeed=2;
private bool liftPaused=true;
private GameObject trackThisOne;
public GameObject firstSelectedBlock;
private bool canSelectBlocks=false;
void Start () {
xStartPosition=-((gameWidth / 2) * blockSpacing.x);
SetupNewGame();
}
// Update is called once per frame
void Update () {
//if we have a click
if(Input.GetMouseButtonDown(0) && canSelectBlocks){
//lets cast a ray and see if they clicked a block
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//if they did lets see which one
if(Physics.Raycast(ray, out hit, 1000f, gameBlockMask)){
GameObject hitObj = hit.collider.gameObject;
//if they already have a block selected lets swap them
//and that block is compatible for swapping (on same line AND right next door)
if(firstSelectedBlock && hitObj &&
Mathf.Abs(firstSelectedBlock.transform.position.y - hitObj.transform.position.y) < 1 &&
Mathf.Abs(firstSelectedBlock.transform.position.x - hitObj.transform.position.x) < blockSpacing.x + 1){
doSwapBlocks(firstSelectedBlock,hitObj);
}else{
if(firstSelectedBlock)
firstSelectedBlock.transform.position = new Vector3(firstSelectedBlock.transform.position.x,firstSelectedBlock.transform.position.y,0);
//otherwise lets select a block
firstSelectedBlock=hitObj;
hitObj.transform.position = new Vector3(hitObj.transform.position.x,hitObj.transform.position.y,blockSpacing.y * 0.75f);
}
}
}
}
i don't understand your code but i think you just want it nonserialized
I have tried all of the following (just incase) and unity is still sharing the variable across all instances of the script / prefab. I also renamed the script to GameFrameController and re-added the prefabs separately in hopes that maybe there was some "magic word" style connection that was going on, but it had no impact. It's still treating firstSelectedBlock like a static global variable for some reason.
//I tried each of the following with no luck
[SerializeField]
private GameObject firstSelectedBlock;
[System.NonSerialized]
private GameObject firstSelectedBlock;
[SerializeField]
public GameObject firstSelectedBlock;
[System.NonSerialized]
public GameObject firstSelectedBlock;
public GameObject firstSelectedBlock;
private GameObject firstSelectedBlock;
protected GameObject firstSelectedBlock;
As far as I know, the only important part of the code is the class definition and variable declaration. I just included the rest for a frame of reference. Also, this class is the only one running in this scene and that variable isn't referenced anywhere else...... I'm very stumped.
I also... just for funsies tried changing the lines that set the variables to use "this" in hopes that maybe it would limit it. Like this..... Didn't change anything (although I didn't really expect it to). Just wanna throw out what I did do incase someone answers this I can avoid things I already tried.
this.firstSelectedBlock=hitObj;
Update is running on all blocks at all times - so this particular section of code looks a little suspect to me:
if(firstSelectedBlock)
firstSelectedBlock.transform.position = new Vector3(firstSelectedBlock.transform.position.x,firstSelectedBlock.transform.position.y,0);
//otherwise lets select a block
firstSelectedBlock=hitObj;
hitObj.transform.position = new Vector3(hitObj.transform.position.x,hitObj.transform.position.y,blockSpacing.y * 0.75f);
Note that there's no "else" statement in there. The code is always selecting the hitObj, and setting it to the firstSelectedBlock...at least as long as the math check above it fails.
Answer by itslenny · Mar 29, 2013 at 11:30 PM
Solved... thanks to everyone that offered advise.
The solution was that the individual instances of GameFrame was setting the firstSelectedBlock variable to any block that was clicked even if it was in another GameFrame object. A simple test to see if the object clicked is a child of the game frame solved it.
I used the following...
if(hitObj.transform.parent.Equals(transform)){
Then changed it to the following as I think it's more proper...
if(hitObj.transform.IsChildOf(transform)){
thanks again for the help.
Answer by aldonaletto · Mar 29, 2013 at 11:14 PM
I suppose that the problem is caused by this script being run in all GameFrame objects: when you click one of them, all GameFrame objects do the raycast in the same frame, setting firstSelectedBlock in each script.
Actually, many variables in this script apparently should be unique and common to all GameFrame objects, like blockSpacing, firstSelectedBlock, canSelectBlocks etc. If this is the case, moving the common code to a single script attached to the camera (or other unique object) would be the wiser solution - keep in the prefab script only the variables that affect that particular instance.