0
\$\begingroup\$

I'm using the script stated below to move a spray bottle around a head.

The code works fine: I have assigned the script to the spray bottle, and I have set the head as the target.

However, I was not happy with the center that Unity seems to use for the spray bottle. The spray bottle never perfectly aimed at the center of the head.

To find out what is going on here, I added a long sphere to the spray bottle. Then I moved the sphere until it would perfectly visualize the center that Unity uses. As once can see, Unity uses the bottom of the spray bottle as its center. I have uploaded a video here to show the effect.

I imagined that I need to tell the script that the center of the spray bottle is different. I would have to include an offset (I guess a Vector3) in order to set the nozzle as the center.

I haven't been able to find out how to plug this "offset" into the script.

Can anybody tell me where / how I could do that?

Thank you very much!

enter image description here

using UnityEngine;
using System.Collections;

[AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
public class MouseOrbitImproved : MonoBehaviour
{

public Transform 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;

private Rigidbody rigidbody;

float x = 0.0f;
float y = 0.0f;

// Use this for initialization
void Start()
{
    Vector3 angles = transform.eulerAngles;
    x = angles.y;
    y = angles.x;
}

void LateUpdate()
{
    if (target)
    {
        x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.02f;
        y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;

        Quaternion rotation = Quaternion.Euler(y, x, 0);

        Vector3 nTargetPos = target.position + new Vector3(0, 0.1f, 0);//10 centimetres lower. The original target.position's center would be around the nose. Instead I want the forehead to be the center, that's why I add 10 centimeters to the y position.

        Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
        Vector3 position = rotation * negDistance + nTargetPos;

        transform.rotation = rotation * Quaternion.Euler(0, -90, 0);//compensate for the fact that the spray bottle should face the head (requiring yaw to be yaw-=90)
        transform.position = position;
    }
}
\$\endgroup\$
1
\$\begingroup\$

Things will be much simpler if you create another GameObject, put a GameObject with bottle model inside it, and adjust position and rotation of inner GameObject so the bottle should aim straight at its center. Then you can just set position of that outer GameObject to the point where the bottle should aim, and it will aim correctly with any rotation of outer object.

If you want to alter distance from bottle to target, change localPosition of inner object (most probably only z).


Okay, I made a working example.

a picture how it works

There are:

  • man - the object where bottle should aim
  • botl - the object which contain elements of the bottle.
  • aimed botl - the object which contains the bottle rotated and moved to aim at local (0, 0, 0). The distance to target also adjusted here.

There is a script on aimed botl based on your script.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class NewBehaviourScript : MonoBehaviour {

    public Transform target;
    public float xSpeed, ySpeed;
    float x, y;


    void Start () {
       var angles = transform.eulerAngles;
       x = angles.y;
       y = angles.x;
    }


    void Update () {
        if (target) {
            x += Input.GetAxis ("Mouse X") * xSpeed;
            y += Input.GetAxis ("Mouse Y") * ySpeed;
            y = Mathf.Clamp (y, -30, 75);
            var rotation = Quaternion.Euler (y, x, 0);
            transform.SetPositionAndRotation (target.position, rotation);
        }
    }

}

Transform is set to sphere of the man.
xSpeed is -5, ySpeed is 2.

That's all.

\$\endgroup\$
  • \$\begingroup\$ Thank you, but I need to attach the bottle to a character later on. I guess when I put the bottle into a new gameobject, I will have a hard time positioning it on the character. Therefore I'm looking for a way to add the offset in the script. \$\endgroup\$ – tmighty May 23 at 14:10
  • \$\begingroup\$ You can attach the bottle to his hand, for example, and set localPosition to different value once. Hand will move, and bottle will move with it. \$\endgroup\$ – trollingchar May 23 at 14:12
  • \$\begingroup\$ Thank you. I hear you, and I understand your suggestion. However, I would really like to know how to do it by code and an offset, just because I would like to see the math behind that. \$\endgroup\$ – tmighty May 23 at 17:13
  • \$\begingroup\$ @tmighty the math is in transformation matrices. The class is Matrix4x4, but you probably want to use Transform Translate and Rotate methods instead, they are simpler. First set the offset for bottle to aim at (0, 0, 0), then apply rotation, and the shift it by coordinates of target. Object hierarchy in Unity does the same, I think. \$\endgroup\$ – trollingchar May 23 at 17:23
  • \$\begingroup\$ I have now put the spray into a gameobject with scale 1,1,1. Now the rotation is absurd because the script now thinks the object is 1x1 metres in size. If I change the container gameobject's scale, it automatically shrinks the bottle. \$\endgroup\$ – tmighty May 23 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.