C# change camera target object problem

Greetings Unity community. I am new to C# and help would be appreciated.
I am trying to write a script that lets you view a character model, but when you click on different parts of the model or different models in the scene, it sets them to be the new camera target.

I am doing that with two scripts:

MouseOrbitBlender.cs - this script is attached to the camera object (“hackCam”). It makes the camera rotate with mouse control around a target object. It’s called MouseOrbitBlender, because like blender it uses middle click to orbit around the target.
This script is a slight modification of a script that somebody here posted before.

OnRightClick.cs- this script is attached to all objects that are potential focus targets. So when I click on objects with it, it tells the camera script to change it’s target value to be the object that the script is attached to. I am aware that it should be called onleftclick, but its not on my priorities to change that

My problem is not that the scripts dont work at all, but in that they don’t do what they’re supposed to.

Problems:
Attaching the OnRightClick script to a cube, a sphere and a cilinder. I dublicated sphere to test if it works to click on clones.
The startTarget is set to sphere in the inspector

  • clicking on cube changes the target to cube, however doesn’t let me click on any of the other objects any more
  • clicking on cilinder changes the target to cube, it doesn’t let me click on any of the other objects any more
    effects.
  • to be clickable, objects need to be set as coliders. That throws of the camera abit, when it colides with the objects. I need to somehow tell the camera to ignore the other coliders in the scene as it rotates around its target.

The scripts:

Camera that orbits around a target

using UnityEngine;
using System.Collections; 

[AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
public class MouseOrbitBlender : MonoBehaviour {
 //user defined variables
	//calls for a transform variable type and calls that "target"
    public Transform target;
	//the target now target
	public Transform startTarget;
	//startObject target
	
    public float distance = 5.0f;
    public float xSpeed = 120.0f;
    public float ySpeed = 120.0f;
 
    public float yMinLimit = -20f;
    public float yMaxLimit = 80f;
 
    public float distanceMin = .5f;
    public float distanceMax = 15f;
 //internal variables (no Public)
    float x = 0.0f;
    float y = 0.0f;	
	// Use this for initialization
	void Start () {
		
			target = startTarget;
		
        Vector3 angles = transform.eulerAngles;
        x = angles.y;
        y = angles.x;
 
        // Make the rigid body not change rotation
         if (rigidbody)
            rigidbody.freezeRotation = true;
	}
 
    void LateUpdate () {
		
    if (target) {
        if ( Input.GetMouseButton (2)){
		//if middle click is held the following happens
		x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.02f;
        y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
			}
 
			if ( Input.GetMouseButton (1)){
				// implement moving Vertically- might need more work!!
			}
        y = ClampAngle(y, yMinLimit, yMaxLimit);
 
        Quaternion rotation = Quaternion.Euler(y, x, 0);
 
        distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*5, distanceMin, distanceMax);
 
        RaycastHit hit;
        if (Physics.Linecast (target.position, transform.position, out hit)) {
                distance -=  hit.distance;
        }
        Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
        Vector3 position = rotation * negDistance + target.position;
 
        transform.rotation = rotation;
        transform.position = position;
 
    }
 
}
 
    public static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360F)
            angle += 360F;
        if (angle > 360F)
            angle -= 360F;
        return Mathf.Clamp(angle, min, max);
    }
	
//Jan
	public void setTarget(Transform newTarget )
    {
        target = newTarget;
        print("new X:"+target.position.x);
        print("new Y:"+target.position.y);    
}	
 //Jan test access:
 //public int getTarget()
    //{
    //    return 5;
  //  }
}

Click to make a target script

using UnityEngine;
using System.Collections;
public class onRightClick : MonoBehaviour {
	public RaycastHit hit;	
	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
    var cam = GameObject.Find("hackCam");
	if (Input.GetMouseButtonDown(0))  //LEFT CLICK
			//1 is right click, 2 is middle click, 0 is left click
   {
			//creates a ray and its equal to the mouse
	  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      RaycastHit hit = new RaycastHit();
      //this if checks, a detection of hit in an GameObject with the mouse on screen
      //ROTATE OBJECT
	 if(Physics.Raycast(ray,out hit)){
			//WORKING:
          MouseOrbitBlender cameraObject = (MouseOrbitBlender) cam.GetComponent("MouseOrbitBlender");
				//this prints the clicked object
				print("object:"+gameObject.name);
                //this tests if we have access to getTarget function in camera object:
				//print(cameraObject.getTarget());
				//this prints the new target coordinates
				//print("target X:"+transform.position.x);
                //print("target Y:"+transform.position.y);
				//this sets new variable directly to a component above classes
				//cameraObject.target = transform;
				//this sets variable through a class- WORKS:
				
				//Problems- clicking on cilinder makes it the cube
				//clicking on sphere doesnt work (going home)
			   cameraObject.setTarget(transform);
			}
		}
	}
}

How badly am I messing this up? Is there a way to do this more efficiently or fix it?

Thanks in advance for any help. I just want to improve on an old camera script.

After you raycast, you’re only using local properties of the gameObject the script is attached to (in the clicky script).
You’re basically always setting the camera target to every object every time any object is clicked.
You need to test to see if the ray actually hit ‘this’ object, -then- assign the camera target.

I don’t see any collision stuff in your camera script. Does your camera have an actual collider attached to it? :o
The common way to make the camera collide is by using raycasts to force it to “X units or closer” to the target, but if you’re using colliders you can set which layers collide with each other in Edit > Project Settings > Physics. Just put your camera object on a layer that doesn’t collide with your clicky objects

so would you say that I need to change only the clicky script? I thought the problem would be that the camera target is a public type variable.

How do i do it?
cameraObject.setTarget(this.gameObject.Transform);?

Thats the variable I need to somehow access with the clicky script. To do it I made a class in the camera script

public void setTarget(Transform newTarget )
    {
        target = newTarget;
        print("new X:"+target.position.x);
        print("new Y:"+target.position.y);    
}

I’m really bad with syntax in unity. I’m trying to figure out how to get it to change the Target variable in the camera script. Thats not supposed to be a public variable in the inspector then?

The layers thing worked. Thanks

Your setTarget is working, but check this out:

if (Input.GetMouseButtonDown(0)) { // if the mouse is clicked
      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      RaycastHit hit = new RaycastHit();
     if(Physics.Raycast(ray,out hit)){ // raycast from mouse position into scene
          // if the raycast hit anything then:
          MouseOrbitBlender cameraObject = (MouseOrbitBlender) cam.GetComponent("MouseOrbitBlender");
          print("object:"+gameObject.name);
          cameraObject.setTarget(transform);

So what that’s all doing is:
Whenever the mouse is clicked -
If the mouse-raycast hits anything -
set my transform to be the camera’s target

Instead of always setting the transform, you need to check to see if the raycast actually hit THIS object:

if ( hit.gameObject == gameObject ) {
  // set transform
}

Side note:
Using strings in GetComponent is unnecessarily slow. Better to use .GetComponent(Type) or .GetComponent.(). Use strings when you need to change which component you fetch at runtime ('cause you can’t do that with the other two versions).

you’re right. But the syntax still doesnt seem to work for me

I got an error

Type `UnityEngine.RaycastHit' does not contain a definition for `gameObject' and no extension method `gameObject' of type `UnityEngine.RaycastHit' could be found (are you missing a using directive or an assembly reference?)

is this a syntax problem or I miss to define something? I just want to be able to click on an object to trigger the attached script to it .

This guys has a bunch of demos
http://forum.unity3d.com/threads/31708-Detecting-an-object-from-a-point-on-the-screen

but his approach seems to be different- he is defining 2 target values that would then need to be assigned in the inspector. That approach seems to create more work than just attaching the script to any object that you want to be a clickable focus target

EDIT:
Nevermind, I got it to work with

if ( hit.transform == gameObject.transform ) {

Thank for for helping me out. I learned a lot from you today. :))

the strings tip is good too!!

Is there a good unity book you could recommend?

Some of this syntax stuff if tough to google, because of all the java stuff out there.

As for the camera coliding with other objects and being jumpy, I found that the Camera script has this line which does it

RaycastHit hit;
        if (Physics.Linecast (target.position, transform.position, out hit)) {
               distance -=  hit.distance;
        }

I uncommented it as it does more damage than good with multiple focus objects in the scene.

You want to hang out on Unity’s Script Reference; it has nearly all the everything you’ll need.

The error you got was my fault, RaycastHit doesn’t actually have a .gameObject. It does have a .collider, though, so you can get the GameObject as “hit.collider.gameObject”.