hard problem - need help

i am going crazy with this problem, it seems that it is really hard for me, and i am asking for help from experienced forum members

in short, i am trying to slide the rectangle that serves as a label to the other side on a certain condition. check out the image:

i guess the problem is because every frame i get to calculate the position of the rectangle (to convert from world to screen space) and
in the same time to slide the rectangle…so i tried to stop calculation when i do sliding, but everything goes back to beginning later, and rect doesnt slide to appropriate place, i guess i should convert from world to screen space again…i dont know it is confusing. i hope all of this makes some sense…

here is the code i have so far…
i made a class that contans information relevant to the label (positions and such…)

here it is:

class CLabel{
	
  function CLabel(width : float,height : float){
    rWidth=width;
    rHeight=height;	
  }
	
  var startPoint : Vector3;
  var endPoint : Vector3;
	
  var startPoint2D : Vector2;
  var endPoint2D : Vector2;
	
  var rPosX : float;
  var rPosY : float;
	
  var rWidth : float;
  var rHeight : float;
	

}

in short, what following script does:

everything is done in DrawLabel function

//current camera target transform is stored
target=camScript.currentTarget;

//end and start points for the line are calculated
//based on the position of the target and is it on
//the negative or positive x-axis
CalculateLinePoints();

//calculate position of the rect based on calculated points
//for the line (this is where conversion from world to screen
//space is happening
CalculateRectPoints();

//THIS WILL JUST ENABLE RENDERING INSIDE
//ONPOSTRENDER (maybe we should have to explicitly
//enable rendering in the OnPostRender()
RenderLabelLine();

//renders label rectangle
RenderLabelRect();

i made a script called LabelControl and attached it to the camera:

  var cam : Camera;
  var camScript : MainCamera;

  //MAKE THE INSTANCE OF THE CLABEL OBJECT
  var Label : CLabel=new CLabel(200,150);

  //VARIABLE THAT HOLDS THE CURRENT TARGET TRANSFORM
  var target : Transform;

  //ENABLE LINE RENDER
  var bEnableRender : boolean = false;
  var bCalculatePositions = true;

  //MATERIAL THAT WILL BE USED TO RENDER THE LINE
  var lineMaterial : Material;

function Awake(){

 //GET THE CAMERA INSTANCE
 cam=GameObject.Find("MainCamera").GetComponent("Camera");
 camScript=GameObject.Find("MainCamera").GetComponent("MainCamera");
	
 target=camScript.currentTarget;

}

function OnGUI(){

  if(!(camScript.currentTarget.name=="Center")){
    DrawLabel();
  }

}


function DrawLabel(){

 //GET TARGET
 target=camScript.currentTarget;	
	
 CalculateLinePoints();
 CalculateRectPoints();
	
 //THIS WILL JUST ENABLE RENDERING INSIDE
 //ONPOSTRENDER (maybe we should have to explicitly
 //enable rendering in the OnPostRender()
 RenderLabelLine();
	
 //THIS EXECUTES IN ONGUI ANYHOW
 RenderLabelRect();
	
 //MONITOR RECT STATE
 //MonitorRectState();

}

function SlideToRight(){

 bCalculatePositions=false;
	
 Label.rPosX=Label.endPoint2D.x;

 var t = 0.0;
 while (t<1.0){
    t+=Time.deltaTime *(1.0/0.2);
    //MOVE THE RECT	
    Label.rPosX=Mathf.Lerp(Label.rPosX,Label.rPosX-Label.rWidth,t);
    Debug.Log("Label.rPosX: " + Label.rPosX);
		
    yield;
		
    if(t>1.0)
    bCalculatePositions=true;
 }
}

//THIS FUNCTION JUST ENABLES RENDER LINE
//IN ONPOSTRENDER FUNCTION
function RenderLabelLine(){

 bEnableRender=true;

}

//THIS FUNCTION CONSTRUCTS THE RECT
//FROM GIVEN DATA
function RenderLabelRect(){

 GUI.BeginGroup(Rect(Label.rPosX,Label.rPosY,Label.rWidth,Label.rHeight));
		
 GUI.Box(Rect(0,0,Label.rWidth,Label.rHeight),"");
 GUI.Box(Rect(5,5,Label.rWidth-10,Label.rHeight-10),target.name);
				
 if(GUI.Button(Rect(10,30,40,40),"I")){
    SlideToRight();
 }
	
 GUI.EndGroup();

}

function CalculateRectPoints(){

 var temp : Vector3;
			
 if(bCalculatePositions){
   if(Label.endPoint.x>0){
    temp=cam.WorldToScreenPoint(Label.endPoint);		
    Label.rPosX=temp.x;
   } else {
   
   temp=cam.WorldToScreenPoint(Label.endPoint);
   Label.rPosX=temp.x-Label.rWidth;
   }

   temp=Camera.main.WorldToScreenPoint(Label.endPoint);	
   temp.y=Screen.height-temp.y;
								
   Label.rPosY=temp.y-Label.rHeight;
	
   }
}



function CalculateLinePoints(){

 //USED TO DETERMINE LEFT OR RIGHT SIDE
 //OF THE LABEL
 var direction : Vector3;
		
 //IF THE OBJECT IS ON THE RIGHT SIDE
 if(target.position.x<0){
    direction=Vector3(-1,0.25,0);
 } else {  //IF THE OBJECT IS ON THE LEFT SIDE
    direction=Vector3(1,0.25,0);
 }		
  //STORE THE LINE POSITIONS
  Label.startPoint=target.position;		
  Label.endPoint=direction + Label.startPoint;
		
  Label.startPoint2D=cam.WorldToScreenPoint(Label.startPoint);
  Label.endPoint2D=cam.WorldToScreenPoint(Label.endPoint);
		
}


function OnPostRender(){

 if(bEnableRender){
	
  CreateLineMaterial(); 
  lineMaterial.SetPass(0); 
			
  GL.Begin(GL.LINES); 
  GL.Color(Color(1,1,1,1));
  GL.Vertex3(Label.startPoint.x,Label.startPoint.y,Label.startPoint.z);
  GL.Vertex3(Label.endPoint.x,Label.endPoint.y,Label.endPoint.z); 
  GL.End();	
	
 }
	
}//END OF ONPOSTRENDER



function CreateLineMaterial() { 
	
 if( !lineMaterial ) { 
 lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" +
   			"SubShader { Pass { " + 
				"    Blend SrcAlpha OneMinusSrcAlpha " + 
				"    ZWrite Off Cull Off Fog { Mode Off } " + 
				"    BindChannels {" + 
				"      Bind \"vertex\", vertex Bind \"color\", color }" + 
				"} } }" ); 
			lineMaterial.hideFlags = HideFlags.HideAndDontSave; 
			lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave; 
		} 
}  //END OF CREATE MATERIAL FUNCTION

You can greatly simplify matters by changing the design:

  • Have a function calculate the basic (unslided) Rect
  • Have the Coroutine that does the sliding calculate a slide offset: a Vector2 that contains the amount of pixels that the baseRect should be offset this frame. This Vector would be (0,0) when the rect isn’t sliding and will interpolate to the final offset position when the coroutine is running.
  • In OnGUI:
var myRect = basicRectangle;
myRect.x -= rectangleOffset.x;
myRect.y -= rectangleOffset.y;
DrawLabelAtRect(myRect);

This way, both the rectangle function and the offset function can operate without affecting eachother.

I would also suggest looking into Bob Berkebiles( pixelplacement1 on the forums) iTween script. It simplifies animation of objects including GUI

iTween for Unity by Bob Berkebile (pixelplacement). Very powerful. Similar to TweenMax/Lite in the flashworld.

@tomvds

i read your suggestion few times, and i think i know what you mean, but i dont have the idea how to do it…can you clarify a bit?

@slem

thanks for the information, i will look into it, i need to get this thing to work first…

thanks both of you for looking into it

iTween is a suggestion for how to get this working; take a look at it (particularly, the ‘Using ValueTo’ example.

What didn’t you understand about the solution tomvds suggested?

Your main problem at the moment is that you have two different processes going on. One of them calculates the screen position of the rectangle, the other moves the rectangle to an alternate position. Since both processes can happen at the same time and both work on the same variable, they start fighting each other.

My suggestion is to separate the two by not having them work on the same variable. The first process will have the job of calulating the position of the rectangle as it is in the top picture. It doesn’t take into account any possible sliding, it’s job is just to calculate the basic rectangle.

The second process is the coroutine (a function with yield in it) you start whenever the “certain condition” is met that causes the sliding to the situation to the left. Instead of messing with the rectangle, it should produce a Vector2 that is used to offset the position of the rectangle during the sliding animation. At the start of the animation, this Vector2 is (0, 0) which means the rect is in its base spot. Then during the animation time, you interpolate the value of the vector to (-rect.width, 0), as it appears from your picture that the rectangle has to slide exactly its own width to the left. This interpolation is where iTween comes in handy, although you can also do it without if you prefer. When (-rect.width, 0) is reached, the rect has arrived at its alternate location.

All that is left is to combine the rectangle of process 1 and the vector2 of process 2 into a single rectangle that will be used for drawing the actual label. This is where the small code snippet I posted before comes into play.

thanks for clarifying that for me, i managed to get it to work. basically i did what you said, in the function that renders rectangle, before everything else i put

	Label.rPosX+=rectangleOffset.x;
	Label.rPosY+=rectangleOffset.y;

and the rectangleOffset is Vector2 just as you suggested that changes value in the coroutine on certain conditions…

one certain condition is the rotation of the camera represented by x and y values in degrees. so when the camera is in the position that between the camera and the target is the label of that object, label slides to left or right side so it doesnt obscure the object.

i had some problems getting that done, because of the states that need to be set…but i managed to make it work.

last thing that is left regarding labels is that i make them not go off the screen rect. i can zoom in and out camera, so sometimes labels go outside the screen, i would like them to stick to the edge of the screen somehow.

btw, i was thinking about how to stick the label to the edge of the screen if it goes outside, and i got this part ready

  //RECTANGLE THAT REPRESENTS THE WINDOW
  var WindowRect : Rect;
  //INITIALIZE THE WINDOW RECT
  WindowRect=Rect(0,0,Screen.width,Screen.height);
//FUNCTION THAT MONITORS RECT POSITION
 function MonitorRectPosition(){

 if(!(WindowRect.Contains(Vector2(Label.rPosX,Label.rPosY)))){
	
   Debug.Log("it's outside");

  } else {
	
   Debug.Log("it's inside");
	
  }
}

so far it is good, it tells me when the rect is outside the window. i am thinking about how to do the part that will not let the rect to go outside.

maybe the same thing with offset will work… any ideas?