Keep Camera relative to left half of a gameobject - unity3d

I am trying to place my camera on the x-axis relative to a gameobject (in my case a sphere). I need this to preview only the half of that sphere no matter what resolution the window will be.
So if the user resizes the window, the camera should adjust itself to only see the left half. See the attached Image. Red is the cameras view and black is the Sphere

Using the Camera.ViewerportPointToRay function you can get a position and direction in world space from a point on the screen. Screen coordinates are defined as (0,0) on the bottom left to (1, 1) on the top right. So to position the sphere on the middle right of the screen you'll want to convert the screen coordinate (1, 0.5) to world coordinates.
Here's an idea of how to get the point on the middle-right of the screen half-way between the near and far clip planes of the camera:
// get the world ray from screen coordinates
Ray ray = camera.ViewpoirtPointToRay(new Vector3(1, 0.5, 0));
// make the z-component of the direction 1
ray.direction /= ray.direction.z;
// get the world position for where to place the sphere by scaling the ray
// halfway down the camera's frustum
Vector3 worldPos = ray.origin + ray.direction * (camera.far - camera.near) * 0.5;
sphere.position = worldPos;
Hopefully that helps! Let me know if anything is unclear!

Related

Positioning UI or Camera relatively to each other (and screen border)

I'm struggling with this sort of
Screen disposition.
I want to position my Camera so that the world is positionned like in the image with the origin at bottom left. It's easy to set the orthographicSize of the camera as I know how many unit I want vertically. It is also easy to calculate the Y position of the camera as I just want it to be centered vertically. But I cannot find how to compute the X position of the camera to put the origin of the world in this position, no matter what the aspectRatio of the screen is.
It brings me two questions :
How can I calculate the X position of the camera so that the origin of the world is always as the same distance from the screen left and bottom borders ?
Instead of positioning the camera regarding the UI, should I use RenderMode Worldspace for the UI canvas. And if so, how could I manage responsiveness ?
I don't understand the second question, but regarding positioning the Camera on the X axis so that the lower left corner is always at world 0 you could do the following:
var lowerLeftScreen = new Vector3(0, 0, 10);
var pos = transform.position;
var lowerLeftScreenPoint = Camera.main.ScreenToWorldPoint(lowerLeftScreen).x;
if (lowerLeftScreenPoint > 0)
{
pos.x -= lowerLeftScreenPoint;
}
else
{
pos.x += Mathf.Abs(lowerLeftScreenPoint);
}
transform.position = pos;
Debug.Log(Camera.main.ScreenToWorldPoint(lowerLeftScreen));
Not the nicest code, but gets the job done.
Also the Z component in the Vector does not really matter for our orthographic camera.

Rotating player is messing up my movement

I wrote a simple player movement script which moves my player like this:
private void MovePlayer()
{
// Initialize Directions For Player Movement
movement = transform.right * horizontal * playerSpeed + transform.forward * vertical * playerSpeed;
// Move Player
rb.AddForce(movement, ForceMode.Acceleration);
}
and I am trying to rotate my player towards the axes, for example if the player is pressing a the horizontal will be -1 and I want to rotate my player left horizontal * 90f, now when I try this, my horizontal axis is acting like my vertical, if I press A it will bring my player backwards, if I press D it will do the same thing, this is how I rotate the player:
// buggy code:
private void RotatePLayerTowardsAxis()
{
// Rotate PLayer Horizontaly
transform.rotation = Quaternion.Euler(0f, horizontal * 90, 0f);
}
is there a way I can do this?
Edit:
The vertical is still pushing me up and down.
First, it is important to check if you are looking at the scene in Local or Global view. Check your axes in Local mode:
If your character model faces towards the blue axis, then everything should be okay.
If you want to rotate your character only by 90 degrees all the time, then it can be done somehow like this:
transform.rotation = Quaternion.Euler(0, 90, 0);
You can use the following as well, but this might not fit your needs:
transform.Rotate(transform.up, 90);
This will make your character rotate by 90 degrees AROUND the up axis. If you want it to rotate always around the world up axis:
transform.Rotate(Vector3.up, 90);
However, transform.rotation = Quaternion.Euler(0, 90, 0); might be better for you, as it always "resets" the rotation when you overwrite it. This will make the character fixed to a direction. So if you press left, the charater will always look into the left by 90 degree. And if you press right after the left turn, your character will do a 180° turn instead of looking forward. I hope you get what I'm trying to say. This means, that your character will be bound to the world axis instead of its own. To modify this (if you want to), write something like this:
transform.rotation += Quaternion.Euler(0, 90, 0);
Hope I could help!

Draw line relative to Image position and scale

I am making a game in Unity and I have a Canvas set to Screen Space - Overlay and it has that background green as you can see from the image. I also have a RawImage with the background blue as a child of the Canvas and the player will have to draw an object like a car or a house inside the RawImage.Right now, the line Instantiates in a random position on the screen even if I give it the coordinated (0, 0).
What I need help with is to find a way to convert the coordinates so I only work with the inside coordinates of the RawImage. For example, the (0, 0) coordinate I will pass to the line, has to be converted to the bottom-left corner of the RawImage. and the maximum width or height should also depend on the RawImage width and height.
Here is the CreateLine function I have for now:
public void CreateLine(int x, int y)
{
currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity);
currentLine.transform.parent = GameObject.Find("GameMenu(Clone)").transform; //Make the line a child of the Canvas named GameMenu
lineRenderer = currentLine.GetComponent<LineRenderer>();
lineRenderer.SetPosition(0, new Vector3(x, y, 99));
lineRenderer.SetPosition(1, new Vector3(x, y, 99));
}
Any amount of help will be greatly appreciated. Have a great day!

Rotate sprite to the direction of a vector

I'm not too great at math but what I am trying to accomplish is rotating my sprite to the direction of a vector impulse that is applied to it. My game is in 2D
If I tap below my sprite it goes upwards, if I tap below my sprite and to the right, it goes upwards and to the left, etc. etc.
I am doing this by just applying a normalized vector (unit vector?) impulse to my sprite which i got from the difference in position between the sprite and my tap.
let x = (ball.position.x - location.x)
let y = (ball.position.y - location.y)
let vectorLength = sqrt((x*x) + (y*y))
// Ignore constants
let unitVector = CGVector(dx: (x/vectorLength) * 25, dy: (y/vectorLength) * 50)
ball.physicsBody!.applyImpulse(unitVector)
Now what I would like to accomplish is the ability to rotate the sprite in the direction of that vector.
So for example if my sprite is traveling up and to the left at lets say a 45 degree angle, how can I rotate the sprite counterclockwise 45 degrees using the vector so that it appears to be facing the facing the direction its traveling?
something like sprite.zRotation = atan(unitVector.dy, unitVector.dx)?

Detect tap on a sphere in unity

I want to detect a tap on sphere. I have searched on google and many approaches like ontriggerenter() and using ray cast etc were found.
But what I want to get some values also that where user has touched on ball.
Like if the center of a sphere is x=0, y=0. then I should got positive x and y when user touch upper right corner of sphere.
It is not necessary to get exactly this value, Value can be anything but by these value I should be able to know that user has tapped on one of these 8 portions of ball.
upper right near center of circle
lower right near center of circle
upper left near center of circle
lower left near center of circle
upper right near corner of circle
lower right near corner of circle
upper left near corner of circle
lower left near corner of circle
You can use the methods you found, with raycasting you will get the exact position of the tap. Then you have to transform the centerpoint and the tap position of the sphere to screenspace coordinates. Then you can get the difference between those vectors to get the direction and distance from the center.
PS: Do circles have corners?
you need to have a GameObject with a Collider attatched to it which is set to "Is Trigger". And a script containing following code.
void OnMouseDown()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//hits for sure, because we are in the click event
Physics.Raycast(ray, out hit);
Vector3 hitOnScreen = Camera.main.WorldToScreenPoint(hit.point);
Vector3 centerOnScreen = Camera.main.WorldToScreenPoint(transform.position);
Vector3 offset = hitOnScreen - centerOnScreen;
if(offset.x > 0 && offset.y > 0)
{
Debug.Log("upper right");
}else if(offset.x < 0 && offset.y > 0)
{
Debug.Log("upper left");
}else if(offset.x > 0 && offset.y < 0)
{
Debug.Log("lower right");
} else //if(offset.x < 0 && offset.y < 0)
{
Debug.Log("lower left");
}
}
For the distance to the center it is getting more complicated.
We have to get a vector perpendicular to the from the camera to the center and scale this to the propper size. If we add this to the center and transform it into screenspace we will have the maximum magnitude a point on the surface of the sphere could reach.
Vector3 perpendicular = Vector3.Cross(transform.position - Camera.main.transform.position, Vector3.one);
Vector3 maxDistToCenter = transform.position + (perpendicular.normalized * (transform.lossyScale.x * 0.5f));
Vector3 maxDistToCenterOnScreen = Camera.main.WorldToScreenPoint(maxDistToCenter);
float maxDist = (maxDistToCenterOnScreen - centerOnScreen).magnitude;
float dist = offset.magnitude;
if (dist < maxDist * 0.5f) // 50% of the way not the area
{
Debug.Log("inner 50%");
}
else
{
Debug.Log("outer 50%");
}
Combining both grant you the ability to evaluate any point on the sphere in angle and distance to the center compared with the maximum distance.
If you just want to apply force to the point clicked, you just need a ridgit body and raycasting. This oficial Unity tutorial will explay it.
Maybe you have to combine both answers, but I think the Unity tutorial is sufficient for your needs.
PS: Please ask questwions with the final goal you want to reach and not just a step you think is needed to get the job done.
You dont need to se raycasts, you can use "OnMouseDown".
Documentation here: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
Note: your object needs a collider in order for this to work.