How to orbit one GameObject around another in the direction opposite of the mouse in 2D?
I'm currently making a 2D pool (billiards) game. To move the ball, I add force in the direction of the mouse whenever I click.
I would like to have the cue orbit at a certain distance around the cue ball while pointing at the mouse.
Cue pointing up
Cue pointing left
Ideally, I would like to have the cue go to the position on the cue ball that's on the other side of the mouse while rotating to face both the mouse and the center of the ball ball. I've already tried to make a script this does this but the cue just ends up jittering and rotating in a seemingly random fashion. This is my current script:
public float distance;
Vector3 rot;
float AngleRad;
float AngleDeg;
void Update () {
lookAtMouse();
rotateAroundBall ();
}
void lookAtMouse(){
AngleRad = Mathf.Atan2(mouse.mousePos.y - transform.position.y, mouse.mousePos.x - transform.position.x);
AngleDeg = (180 / Mathf.PI) * AngleRad;
rot = new Vector3(0, 0, AngleDeg - 90);
this.transform.rotation = Quaternion.Euler (rot);
}
void rotateAroundBall(){
transform.RotateAround (cueBall.transform.position, Vector3.forward, rot.z);
}
What is the best way to achieve this? Thanks.
Answer by Robert_s_a · Mar 11, 2017 at 11:34 PM
@zackarhino Hi zackarhino,
I'm working on a similar scenario in 3 dimensions, and here's what I can contribute...
I think you're getting stuck between two different coordinate systems, and this is causing you two levels of problem.
First is the different coordinate axies - The world scene coordinate system has its origin at a virtual point arbitrarily called (0,0) or (0,0,0) in 3D, and the gameObject translations, rotations, etc. are based on this origin, with positive x extending to the right, and positive y extending up. The mouse position however, uses a display-screen based coordinate system with the origin (0,0) at the top left corner of the screen with positive x extending to the right, and positive y extending down.
Second is the different scale for these systems. The world scene uses arbitrary units to measure, and depending on your scene, and your scale, etc. a single unit (from x = 3 to x = 4) could mean any number of different things. The mouse position uses a scale measured in pixels, so a change in mouse position from x = 3 to x = 4 may have no bearing whatsoever on the motion of your cue.
One or the other, or both of these issues are likely why you're getting apparently random rotations for your cue.
I took another tact, and rather than using mathematical calculations to determine the position, orbit, rotation etc. of the cue, I've created another object (called AimHere - just a unit sphere, and in my production build it will be invisible and have no physical effects on the world). I intend to make my version of the cue be a child object which attaches as a child to the my cue ball. As a child, any translation or rotation of the cue ball will automatically be transferred to the cue. Then I will use the transform.LookAt() method to orient my cue ball (and the cue will follow). Before attaching it as a child to the cue ball, it should be oriented to be pointing directly at the cue ball from the negative Z direction. I figure that the LookAt method would be easier, if I can solve the scale issue, because it will work without any math needed, regardless of where my cue ball is in the scene.
Here's the sample script I have so far, however, I have not yet worked out the problem of scaling between pixels and world measurement. For testing purposes, my cue ball, and AimHere are unit spheres, and currently my cue is a cylinder primitive with a position of (0,0,0), a rotation of (90,0,0), and a scale of (0.1, 2.0, 0.1) - I'll adjust it later. I had my cue ball located at (0,0,0), rotated (0,0,0) and scaled (1,1,1) when I attached the cue as its child. This is important, because the cue will maintain its relative position, rotation, and scale when its attached, so if you want to adjust it, detach it, make your adjustments, and then attach it again.
(If you run this with your scene window zoomed way out, you can see the AimHere object moving around way out there because of the translation between pixels and game units.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CueControl : MonoBehaviour
{
public GameObject AimHere;
private Event e;
private Screen theScreen;
private Vector2 theMousePosition;
private float screenWidth;
private float screenHeight;
private float xAdjust;
private float yAdjust;
// For interactions with the GUI system
private void OnGUI()
{
// Read the current event system actions
e = Event.current;
theMousePosition = e.mousePosition;
// There's still a scale issue in here that I haven't resolved yet, but hopefully this will get you started...
// Move the AimHere object to the adjusted position
AimHere.transform.position = new Vector3(theMousePosition.x + xAdjust, -1 * (theMousePosition.y + yAdjust), 0.0f);
}
// Use this for initialization
void Start ()
{
// Read screen dimensions for translation
screenWidth = Screen.width;
screenHeight = Screen.height;
xAdjust = screenWidth / -2;
yAdjust = screenHeight / -2;
}
// Update is called once per frame
void Update ()
{
// Aim my cue ball (and also the cue because it is a child) at the AimHere object
this.transform.LookAt(AimHere.transform.position);
}
}
I hope this was of some help!
I'm not sure if I understand this fully, but, from what I can tell, you need mousePos = cam.ScreenToWorldPoint (Input.mousePosition);
which allows Unity to tell you your mouse position in world coordinates. mousePos
is a Vector3 and cam
is the main camera. transform.LookAt()
didn't really work for me either, and I'm not sure why. I have, however, figured out that transform.RotateAround()
isn't right either as it just orbits an object relative to time rather than something like mouse position. I'm still trying to figure it out. Thanks for your help, though.
Your answer
![](https://koobas.hobune.stream/wayback/20220612112853im_/https://answers.unity.com/themes/thub/images/avi.jpg)