- Home /
Script variables resetting on play
I'm trying to find out why my variables are being set to the minimum possible size when I hit play, and how to fix this problem
I'm working with the Unity GUI and the OnGUI function and I've setup a GroupGUI class which is able to contain any number and any kind of general GUI item, by being able to contain one GUIContent variable, a couple of Rect for relative positioning, and an array of GroupGUI.
When I hit play to view my GUI (The master GroupGUI is attached to a camera and contains 2 children attached to junk) the children get re-sized to 12px by 12px... This is what I have hard coded as being the smallest possible width and height for the objects but I can't find why they're being re-sized to this because their default size set in the inspector is much larger (although smaller than their parent's limit).
The way this system works is that you can attach a master GUI item to the camera (could be empty, or a border for a menu, or just the main item if only one item needed), then all the children are limited to be within that item's area, and the position of the children is relative to the master, rather than relative to the screen. If a master/parent item moves then all it's children and their children move along with it.
This may seem pointless or others may have done it but I'm new to making things in Unity and thought that this "advanced" menu API could be a good way to practice with a couple of things.
Their aren't any unused values or undefined functions, I've just removed anything that doesn't alter the behavior of the item positioning. Thanks in advance for any help
The code
public class GroupGUI: MonoBehaviour{
public bool isActive; //Not important for this question
public GUITYPES guiType; //Not important for this question
public bool CenterPosOnX;
public bool posCenterOffset;
public bool forceUpdate;
public Rect position;
public GUIContent content;
public GroupGUI[] subs;
private string textEdit; //Not important for this question
private GroupGUI parent;
private Rect realPos;
private Rect prevPos;
private Rect positionLimit;
void Start(){
forceUpdate = true;
textEdit = content.text;
prevPos = position;
if(parent){
parent.correctAlignment();
positionLimit = parent.position;
}
else{
positionLimit = new Rect(0, 0, Screen.width, Screen.height);
}
for(int i=0; i<subs.Length; i++){
if(subs[i] == this)
subs[i] = null;
else{
subs[i].positionLimit = realPos;
subs[i].parent = this;
}
}
}
void Update(){
if(forceUpdate || prevPos.width != position.width || prevPos.height != position.height || prevPos.x != position.x || prevPos.y != position.y){
for(int i=0; i<subs.Length; i++) {
if(subs[i].parent != this) {
subs[i].parent = this;
}
}
forceCorrectAlignment();
forceUpdate = false;
if(posCenterOffset) {
if(!CenterPosOnX)
realPos.x = (positionLimit.x) + (positionLimit.width / 2) - (realPos.width / 2) + position.x;
realPos.y = (positionLimit.y) + (positionLimit.height / 2) - (realPos.height / 2) + position.y;
}
else {
realPos.x = (positionLimit.x) + position.x;
realPos.y = (positionLimit.y) + position.y;
}
if(CenterPosOnX) {
realPos.x = positionLimit.x + (positionLimit.width / 2) - (realPos.width / 2);
position.x = (posCenterOffset) ? 0 : positionLimit.width/2;
}
prevPos = position;
}
}
void OnGUI() {
if(!isActive)
return;
switch(guiType){
case GUITYPES.Empty:
break;
case GUITYPES.Box:
GUI.Box(realPos, content);
break;
case GUITYPES.Button:
if(GUI.Button(realPos, content)){
GUI_ImHit();
}
break;
case GUITYPES.RptButton:
if(GUI.RepeatButton(realPos, content)){
GUI_ImHit();
}
break;
case GUITYPES.Label:
GUI.Label(realPos, content);
break;
case GUITYPES.Password:
GUI.PasswordField(realPos, content.text, '*');
break;
case GUITYPES.TextArea:
textEdit = GUI.TextArea(realPos, content.text);
if(textEdit != content.text){
GUI_ImHit();
}
break;
case GUITYPES.TextField:
textEdit = GUI.TextField(realPos, content.text);
if(textEdit != content.text){
GUI_ImHit();
}
break;
}
}
private void forceCorrectAlignment(){
correctAlignment();
for(int i=0; i<subs.Length; i++){
subs[i].positionLimit = realPos;
subs[i].forceCorrectAlignment();
}
}
private void correctAlignment(){
correctAlignment(this, positionLimit);
}
private static void correctAlignment(GroupGUI arg, Rect limit){
correctAlignment(arg, limit.width, limit.height);
}
private static void correctAlignment(GroupGUI arg, float w, float h){
if(arg.position.width < 12)
arg.position.width = 12;
if(arg.position.height < 12)
arg.position.height = 12;
if(arg.position.width > w)
arg.position.width = w;
if(arg.position.height > h)
arg.position.height = h;
if(arg.posCenterOffset){
if(arg.position.x < (arg.position.width / 2) - (w / 2))
arg.position.x = (arg.position.width / 2) - (w / 2);
if(arg.position.x + (arg.position.width / 2) > w / 2)
arg.position.x = (w / 2) - (arg.position.width / 2);
if(arg.position.y < (arg.position.height / 2) - (h / 2))
arg.position.y = (arg.position.height / 2) - (h / 2);
if(arg.position.y + (arg.position.height / 2) > h / 2)
arg.position.y = (h / 2) - (arg.position.height / 2);
}
else{
if(arg.position.x < 0)
arg.position.x = 0;
if(arg.position.x + arg.position.width > w)
arg.position.x = w - arg.position.width;
if(arg.position.y < 0)
arg.position.y = 0;
if(arg.position.y + arg.position.height > h)
arg.position.y = h - arg.position.height;
}
arg.realPos.width = arg.position.width;
arg.realPos.height = arg.position.height;
}
}
The variables
Master:
isActive: true
GuiType: Box
CenterPosOnX: false
PosCenterOffset: true
Position:
X: 0, H: 0, W: 100, H: 100
Content:
Text: Menu
Image: (None)
Tooltip: (None)
Subs:
Size: 2
Element 0: Child0
Element 1: Child1
Child0:
isActive: true
GuiType: Button
CenterPosOnX: false
PosCenterOffset: true
Position:
X: 0, H: 25, W: 75, H: 25
Content:
Text: Hello
Image: (None)
Tooltip: (None)
Subs:
Size: 0
Child1:
isActive: true
GuiType: Button
CenterPosOnX: false
PosCenterOffset: true
Position:
X: 0, H: 60, W: 75, H: 25
Content:
Text: Hello2
Image: (None)
Tooltip: (None)
Subs:
Size: 0
More Info
When play is hit the master box appears in center of screen at correct size as it should but the 2 children are at smallest possible size, and are positioned with an offset relative to the top left corner of the screen that is equal to half of the width and height of the master item. The child items will jump into the master item once the master item has been updated (moved/re-sized) and THEN the child is updated.
Answer by Bunny83 · Jul 05, 2014 at 01:33 PM
There are some things that are prone to fail or simply strange:
"Start" of each object can be called in any order, same for "Update". So it isn't guaranteed that for example Start of the parent object is called before the child(s).
It seems that each child will call "parent.correctAlignment();" on the parent. That doesn't make much sense.
Are you sure your "positionLimit" is always correct? Especially when your objects are initialized in a random order?
If you want a hierarchical relationship, why don't you use the Transform component for that? You get the parenting for free.
Those kind of class-based GUI systems are usually better done with a single OnGUI method on the topmost object. You would simply call your own "GUI" callback on the childs from the "master". That way you have full control over the execution order.
However if it isn't "that" urgent it's worth waiting for Unity 4.6 and the new GUI system
I was able to fix the problem before your reply but I did so by making all instances not actually use OnGUI until 5 Update ticks have passed, this ensures that the parent sets all it's children to have the parent value, and updates are forced on all objects and the limits are in place correctly. I didn't actually work out how many ticks are needed though and just used trial and error, I fear that the deeper the child list gets then it'll take longer to do this. Anyways as I said this was more just for getting into Unity3D and C#, thanks for the help.
I was able to fix the problem before your reply but I did so by making all instances not actually use OnGUI until 5 Update ticks have passed, this ensures that the parent sets all it's children to have the parent value, and updates are forced on all objects and the limits are in place correctly. I didn't actually work out how many ticks are needed though and just used trial and error, I fear that the deeper the child list gets then it'll take longer to do this. Anyways as I said this was more just for getting into Unity3D and C#, thanks for the help.