Unity - drag to resize / scale plane based on handle position? - c#

Alright, I cant find any example of this already done and my attempt is yielding odd results - I need to drag to resize a flattened cube (like a plane, but must have thickness so it was a cube) using a handle in the corner. Like a window on your desktop.
So far Ive created my handle plane and gotten it via script attached to my cube plane. The cube plane and the handle are children of an empty to which the scale is being applied so that the cube plane scales from left to right as desired:
That works, however my attempt at using the delta scale handle position to scale the parent empty scales either way too much or in odd directions:
Awake() {
scaleHandle = GameObject.FindGameObjectWithTag("ScaleHandle");
scaleHandleInitialPos = scaleHandle.transform.localPosition;
}
Update()
{
width += -1*(scaleHandleInitialPos.x - scaleHandle.transform.localPosition.x);
height += -1 * (scaleHandleInitialPos.y - scaleHandle.transform.localPosition.y);
transform.parent.localScale = new Vector3(width, height, thickness);
}
what is wrong here?
Hierarchy:
Transform of the child:
With updating initialPos every Update() OR doing width = scaleHandle.transform.localPosition.x / scaleHandleInitialPos.x; where the white square is the scaleHandle

Related

Unity. Input.MousePosition is returning coordinates that are way too large for the screen

The highest Y position that is shown in my camera is 5 and -5.
For the X its 10.
I'm making a tower defense game and I want the tower to follow my mouseposition after I buy it until I click on a place in the track to build/ place it. I got so confused because I couldn't see my tower at all but now I realized that my mouse coordinates are HUGE. It's up to the hundreds on each axis. My screen obviously can't fit that. I tried even dividing the mouseposition in a vector 2 by 45 and making an offset so it can fit well. Unfortunately I have to change the values depending on the screen size so that can't work. I don't know if it matters but here's my script? This script get's called after the tower gets instantiated from the store. The store button is in the canvas if that helps? Maybe the canvas is why everything is off? How do I fix it?
public class FrogBotPrefab : MonoBehaviour
{
public frogbotshopscript shop;
public canbuildManager buildingscript;
public Vector2 mouseposition;
public float xoffset;
public float yoffset;
// Start is called before the first frame update
void Start()
{
xoffset = 9.55f;
yoffset = 5.19f;
shop = FindObjectOfType<frogbotshopscript>();
buildingscript = FindObjectOfType<canbuildManager>();
}
// Update is called once per frame
void Update()
{
mouseposition = Input.mousePosition/45;
mouseposition.x -= xoffset;
mouseposition.y -= yoffset;
if (shop.followingmouse)
{
transform.position = mouseposition;
}
}
}
Screen space is different from world space
In Unity, Input.MousePosition is measured in terms of pixels on your screen. Let's say you have a 1080p monitor - 1920 x 1080 - which is pretty common these days, that means Input.MousePosition will be in the following range when your game is fullscreen:
x: 0 to 1919
y: 0 to 1079
The actual world units - the units as seen in your scene - don't matter at all and can be basically anything.
Another thing of note is that your gameworld is 3D and the physical screen is 2D. Assuming your camera is looking into open space in your world, a single pixel on the screen is represented by an infinite line in the 3D world. This line is called a ray, and you can turn a 2D screen position into a ray via Camera.ScreenPointToRay, and then find what 3D objects that line intersects with via a Physics.Raycast.
In Unity there is a difference between the world position and the screen position!
That means that just because you are looking at point AB at the world it does not have to be this point on screen because the Screen is meassured in Pixels.
There obv is a way to calculate a point on the screen based on your camera into the world. You best have a look at Unity ScreenToWorldPoint for this.

Interpolate Up Vector Linearally when Up isn't truly Up?

Overview
I've been looking around for a while and haven't found an answer so hopefully the community here can help me out. I am re-working my look-at camera (written pre 2000) and am having trouble getting rid of an issue where the look-at and up vectors become aligned causing the camera to spin wildly out of control. I originally understood this to be gimbal lock, but now I'm not so sure of that.
From my understanding of gimbal lock, when pitch becomes aligned with roll, pitch becomes roll; and in essence this is what it appears to be, but the problem is that the rate of change shouldn't increase just because the axes become aligned, I should just get a smooth roll. Instead I get a violent roll in which I can't really tell which way the roll is going.
Updating the Camera's Position
When the user moves the mouse I move the camera based on the mouse's X and Y coordinates:
Vector2 mousePosition = new Vector2(e.X, e.Y);
Vector2 delta = mousePosition - mouseSave;
mouseSave = mousePosition;
ShiftOrbit(delta / moveSpeed);
Within the ShiftOrbit method, I calculate the new position based on the look-at, right, and up vectors in relationship to the delta passed from the mouse event above:
Vector3 lookAt = Position - Target;
Vector3 right = Vector3.Normalize(Vector3.Cross(lookAt, Up));
Vector3 localUp = Vector3.Normalize(Vector3.Cross(right, lookAt));
Vector3 worldYaw = right * delta.X * lookAt.Length();
Vector3 worldPitch = localUp * delta.Y * lookAt.Length();
Position = Vector3.Normalize(Position + worldYaw + worldPitch) * Position.Length();
This works smoothly as it should and moves the camera around its target in any direction of my choosing.
The View Matrix
This is where I experience the problem mentioned in the overview above. My Up property was previously set to always be 0, 0, 1 due to my data being in ECR coordinates. However, this is what causes the axis alignment as I move the camera around and the view matrix is updated. I use the SharpDX method Matrix.CreateLookAtRH(Position, Target, Up) to create my view matrix.
After discovering that the Up vector used when creating the view matrix should be updated instead of always being 0, 0, 1, I encountered another issue. I now caused roll when yaw and pitch were introduced. This shouldn't occur due to a requirement so I immediately began pursing a fix.
Originally I performed a check to see if was coming close to being axis aligned, if I was, then I set the Up used to create my view matrix to the local up of the camera, and if I wasn't then I used only the Z axis of the local up to ensure that up was either up or down.
float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
if (dot > 0.98)
Up = localUp;
else
Up = new Vector3(0, 0, localUp.Z);
However, this was a bit jumpy and still didn't seem quite right. After some trial and error, along with some extensive research on the web trying to find potential solutions, I remembered how linear interpolation can transition smoothly from one value to another over a period of time. I then moved to using Vector3.Lerp instead:
float dot = Math.Abs(Vector3.Dot(Up, Position) / (Up.Length() * Position.Length()));
Up = Vector3.Lerp(new Vector3(0, 0, localUp.Z), localUp, dot);
This is very smooth, and only causes any roll when I am very near to being axis aligned which isn't enough to be noticeable by the every day user.
The Problem
My camera also has the ability to attach to a point other than 0, 0, 0, and in this case, the up vector for the camera is set to the normalized position of the target. This causes the original issue in the overview when using Vector3.Lerp as above; so, in the case where my camera is attached to a point other than 0, 0, 0 I do the following instead:
Up = Vector3.Lerp(Vector3.Normalize(Target), localUp, dot);
However, even this doesn't work and I have no idea how to get it to do so. I've been working at this problem for a few days now and have made an extensive effort to fix it, and this is a big improvement so far.
What can I do to prevent the violent spinning using Vector3.Lerp when the up isn't equivalent to 0, 0, z?
Imagine a vertical plane that is rotated around the vertical axis by yaw (ϕ):
The camera is only allowed to rotate with the plane or in the plane, its in-plane orientation given by the pitch (θ):
ϕ and θ should be stored and incremented with the input delta. With this setup, the camera will never tilt, and the local up direction can always be computed:
d and u are the local front and up directions respectively, and are always perpendicular (so alignment won't be an issue). The target can of course be taken as the position + d.
But wait, there's a catch.
Suppose if you move your mouse to the right; ϕ increases, and you observe:
If the camera is upright, the view rotates to the right.
If the camera is upside-down, the view rotates to the left.
Ideally this should be consistent regardless of the vertical orientation.
The solution is to flip the sign of increments to ϕ when the camera is upside down. One way would be to scale the increments by cos(θ), which also smoothly reduces the sensitivity as θ approaches 90 / 270 degrees so that there is no sudden change in horizontal rotational direction.

Accelerometer movement limit according to screen size

I am using this code:
void Update()
{
accel = Input.acceleration.x;
transform.Translate (0, 0, accel);
transform.position = new Vector3 (Mathf.Clamp (transform.position.x,-6.9f, 6.9f), -4.96f, 18.3f);
}
It makes my gameObject move the way I want it BUT the problem is that when I put the app on my phone, (-6.9) and (6.9) are not the "ends" of my screen. And I cannot figure out how to change those values according to every screen size?
This is going to be a bit of a longer answer, so please bear with me here.
Note that this post is assuming that you are using an orthographic camera - the formula used won't work for perspective cameras.
As far as I can understand your desire is to keep your object inside of the screen boundaries. Screen boundaries in Unity are determined by a combination of camera size and screen size.
float height = Camera.main.orthographicSize * 2;
A camera's orthographic size determines the half of the screen's size in world units. Multiplying this value results in the amount of world units between the top and bottom of the screen.
To get the width from this value, we take the value and multiplying it by the screen's width divided by the screen's height.
float width = height * Screen.width / Screen.height;
Now we have the dimensions of our screen, but we still need to keep the object inside those bounds.
First, we create an instance of the type Bounds, which we will use to determine the maximum and minimum values for the position.
Bounds bounds = new Bounds (Vector3.zero, new Vector3(width, height, 0));
Note that we used Vector3.zero since the center of our bounds instance should be the world's center. This is the center of the area that your object should be able to move inside.
Lastly, we clamp the object's position values, according to our resulting bounds' properties.
Vector3 clampedPosition = transform.position;
clampedPosition.x = Mathf.Clamp(clampedPosition.x, bounds.min.x, bounds.max.x);
transform.position = clampedPosition;
This should ensure that your object will never leave the screen's side boundaries!

Camera units in Unity5

i'm currently programming an 2D topview unity game. And i want to set the camera such as, that just a specific area is visible. That means that i know the size of my area and when the camera, which is following the player currently reaches the border of the area, i want to visible stops.
So here is my question: i know where the camera is and how it can follow the player but i dont know how i can calculate the distance between the border of the field and the border of waht the camera sees. how can i do that?
Essentially, treat your playable area as a rectangle. Then, make a smaller rectangle within that rectangle that accounts for the camera's orthographic size. Don't forget to include the aspect ratio of your camera when calculating horizontal bounds.
Rect myArea; // this stores the bounds of your playable area
Camera cam; // this is your orthographic camera, probably Camera.main
GameObject playerObject; // this is your player
float newX = Mathf.Clamp(
playerObject.transform.position.x,
myArea.xMin + cam.orthographicSize * cam.aspect,
myArea.xMax - cam.orthographicSize * cam.aspect
);
float newY = Mathf.Clamp(
playerObject.transform.position.y,
myArea.yMin + cam.orthographicSize,
myArea.yMax - cam.orthographicSize
);
cam.transform.position = new Vector3(newX,newY,cam.transform.position.z);
If you're using an alternative plane (say xz instead of xy), just swap out the corresponding dimensions in all the calculations.

Discontinuity in RaycastHit.textureCoord values (getting coordinates on texture right)

Hi I'm trying to get a particular coordinate on texture (under mouse cursor). So on mouse event I'm performing:
Ray outRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit clickRayHit = new RaycastHit();
if (!Physics.Raycast(outRay, out clickRayHit))
{
return;
}
Vector2 textureCoordinate = clickRayHit.textureCoord;
Texture2D objectTexture = gameObject.GetComponent<Renderer>().material.mainTexture as Texture2D;
int xCord = (int)(objectTexture.width * textureCoordinate.x);
int yCord = (int)(objectTexture.height * textureCoordinate.y);
But the problem is that the coordinate I'm getting is not preciesly under the cursor but "somewhat near it". And it's not like coordinates are consistently shifted in one way but shifting is not random as well. They are shifted differently in different points of the texture but:
they remain somwhere in the area of real cursor
and coordinates shifted in the same way when cursor is above the same point.
Here is part of coordinates log: http://pastebin.ca/3029357
If i haven't described problem good enough I can record a short screencast.
GameObject is a Plane.
If it is relevant mouseEvent is generated by windows mouseHook. (Application specific thing)
What am I doing wrong?
UPD: I've decided to record screencast - https://youtu.be/LC71dAr_tCM?t=42. Here you can see Paint window image through my application. On the bottom left corner you can see that Paint is displaying coordinates of the mouse (I'm getting this coordinates in a way I've described earlier - location of a point on a texture). So as I move mouse cursor you can see how coordinates are changing.
UPD2:
I just want to emphasize one more time that this shift is not constant or linear. There could be "jumps" around the mouse coordinates (but not only jumps). The video above explains it better.
So it was scaling problem after all. One of the scale values were negative and was causing this behaviour.

Categories

Resources