Unity - Check if mouse click was inside of a rect transform - c#

I try to figure out if a mouse click was inside of a rect transform or not.
Each time the user clicked on the screen, a ball will be thrown. But in case the user clicks on the pause button, no ball should be thrown.
I tried to solve with this piece of code but it seems that only the top right quarter of the rect transform is recognized. Here's a short video to show the actual problem: https://youtu.be/gdyDBK6ubgo
Here's the code snippet:
void Update() {
//Check if user touch on display / click mouse button
Vector2 mousePos = new Vector3(Screen.width - Input.mousePosition.x,Screen.height - Input.mousePosition.y, 0);
if (Input.GetMouseButtonDown(0) && props.throwable && !checkCollisionWithPauseButton(mousePos) && props.remainingBalls > 0)
{
fireBall(Input.mousePosition);
}
}
bool checkCollisionWithPauseButton(Vector3 mousePos){
//TODO: This does not work very well
return pauseButton.GetComponent<RectTransform>().rect.Contains (mousePos);
}
Here's a screenshot which shows the rect transform.

Use RectTransformUtility.RectangleContainsScreenPoint to check if the mouse pointer is in the Rect Transform. This will work regardless of where the rectTransform is positioned locally.
public RectTransform rectTransform;
...
Vector2 mousePos = Input.mousePosition;
RectTransformUtility.RectangleContainsScreenPoint(rectTransform, mousePos);

None of these worked in my case. Here is what I ended up doing:
public RectTransform rectTransform;
...
Vector2 lp;
Vector2 mousePos = Input.mousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, mousePos, Camera.main, out lp);
if (rectTransform.rect.Contains(lp))
..ect

It's not working because you're performing some unnecessary work. You don't need this line:
Vector2 mousePos = new Vector3(Screen.width - Input.mousePosition.x,Screen.height - Input.mousePosition.y, 0);
Simply pass Input.mousePosition to the Rect.Contains function and that should work.
Vector2 mousePos = Input.mousePosition;
pauseButton.GetComponent<RectTransform>().rect.Contains (mousePos);
Even though that may work, this is not how to detect clicks properly on UI or GameObjects. The EventSystems is used for that. See this for example.

Related

Why isn't my attempt at making an FPS shooter zoom working?

OBJECTIVE
I am using this script I got from Unity's forums to move my camera around. It works perfectly and this is exactly the style of camera I want. Here it is in action:
https://streamable.com/j7ozps
I wanted to create a zoom effect when the user holds the right mouse button.
PROBLEM
After zooming in, the aim is off by a lot. Here's what happens:
https://streamable.com/8aiil0
MY ATTEMPT
void Update () {
if (Input.GetMouseButton(1))
{
int layerMask = 1 << CombatManager.GROUND_LAYER; // -> public const int GROUND_LAYER = 8;
Ray mouseClick = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit[] hitInfos;
float maxDistance = 100.0f;
hitInfos = Physics.RaycastAll(mouseClick, maxDistance,
layerMask, QueryTriggerInteraction.Ignore);
mainCamera.fieldOfView = 10;
mainCamera.transform.LookAt(hitInfos[0].point);
}
else
mainCamera.fieldOfView = startingFieldOfView;
I also tried swapping the order of the LookAt and field of view assignment.
What am I doing wrong?
Seems that what you want is to zoom towards the cursor position, not towards where the ray hits which are likely not the same point. To check that out you can draw a debug cube where the ray hits, to check if the point you are looking at is the one you need, like so:
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = hitInfos[0].point;
Check Camera.ScreenToWorldPoint that gives you the worldspace point created by converting the screen space point at the provided distance z from the camera plane.
What I would try:
Vector3 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//check if this is the point you want to look at
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = point;
//look at it
mainCamera.transform.LookAt(point);
It should not mind if you are using the cam.nearClipPlane or the cam.farClipPlane in the ScreenToWorldPoint function, but I would play with that in case something is not working as intended.
Vector3 screenPoint = Input.mousePosition;
screenPoint.z = Camera.main.farClipPlane;
Vector3 worldPoint = Camera.main.ScreenToWorldPoint(screenPoint);

Unity: TopDown view - GameObject does not rotate toward mousepos

I've been doing some research on why my player(GameObject) is does not rotate toward my mouse position in my TopDown 3D game and I can't seem to find what is wrong with my code, so im making this post. The problem thats I have is that only the GameObject of my player (in my case, a capsule) rotate toward my mouse position but the axis of my player stays the same. In other word, I can't rotate the axis of my player, to face my mouse position, but I can rotate the GameObject of my player to face my mouse position. Its really hard to explain and this never happened to me before. Question is how can I rotate the axis of my player to face my mouse position. Keep in mind that my game is a top down view.
Here is the code im using for my playerMouvment and for my mouseLook:
public class Controller : MonoBehaviour
{
public float moveSpeed = 6;
Rigidbody rb;
Camera viewCamera;
Vector3 velocity;
void Start()
{
rb = GetComponent<Rigidbody>();
viewCamera = Camera.main;
}
void Update()
{
Vector3 mousePos = viewCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, viewCamera.transform.position.y));
transform.LookAt(mousePos + Vector3.up * transform.position.y);
velocity = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized * moveSpeed;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
}
}
Again I tried and look for any error in my code and I can't find anything that cause this weird situation and so if anyone can help me find a better way to write this code and solve my problem it would be great!
If I understand you correctly everything is fine with your game and the player is turning as it should, but only in the editor that the axis of the player (red, green and blue arrows) don't turn with the player?
If this is the problem it might be that you are using global space handle instead of local space. Clicking the icon I highlighted in the image should do the trick.
Use this code instead of LookAt() function
Vector2 direction = mousePos.position - player.transform.position;
player.transform.right /* Maybe you need Up or -Up or -right */ = direction;
This would work too in some cases
Vector2 direction = new Vector2
(
mousePos.position.x - player.transform.position.x,
mousePos.positoin.y - player.transform.position.y
)
player.transform.right /* Maybe you need Up or -Up or -right */ = direction;

Unity - best way to drag a RigidBody2D Gameobject by mouse/touch

I am creating a 2D game in Unity and wanted to see if anyone has any suggestion on how I can improve the script below which I am using to drag a paddle in a breakout/arkanoid style game. I know there are more complex ways to drag objects but this works ok for me but the only issue I encounter is that when I test my game on a mobile device the dragging is not 100% sharp and when I stop dragging the paddle seems to lag ever so slightly. I don’t have any issues with my mobile device as I have played other breakout games I downloaded from the Play store and the dragging is very crisp.
The script below is attached to the paddle.
Vector3 dist;
float posX;
float posY;
void OnMouseDown(){
dist = Camera.main.WorldToScreenPoint(transform.position);
posX = Input.mousePosition.x - dist.x;
posY = Input.mousePosition.y - dist.y;
}
void OnMouseDrag(){
Vector3 curPos = new Vector3(Input.mousePosition.x - posX, Input.mousePosition.y - posY, dist.z);
Vector3 worldPos = Camera.main.ScreenToWorldPoint(curPos);
transform.position = worldPos;
}
I would advise doing your translation of the x and y-axis values using the mouse's position as it's being dragged via the subtracted difference between what the mouse's position value was as it's first pressed down.
A summary of that would be:
Store a 2D vector as a private field, called previousPos (so
mousedown and mousemove can both access it) and set it's value to the result of the mouse's current position.
In the mouse drag function, get the mouse position again and assign the
value to a 2D vector called currentPos and subtract that from
the previousPos, which gives you the x and y-axis values to set the
paddle's transform position to.
Then update the previousPos at the end of the drag function, and
assign the value of currentPos to it so that next time around it
gives the new change and not the aggregated change.
*You probably want to have a boolean that you set to true when mouse is down and at the end of the drag set it to false. Use that bool in the drag as a check to see if you need to set the paddle position in the first place (only set paddle position if the boolean is true) -- Not sure if unity does this for you by only firing mouse dragged when the mouse is down or not.
An example in code:
private Vector2 _previousPos;
private bool _isMouseDown;
void OnMouseDown(){
_isMouseDown = true; //because we're in the on mouse down function
_previousPos = Input.mousePosition; //get the current mouse position
}
void OnMouseDrag(){
if(!_isMouseDown)
return;
Vector2 currentPos = Input.mousePosition; //get updated mouse pos
Vector2 paddlePos = currentPos - previousPos; //the delta change
transform.position = paddlePos; //new paddle position
_isMouseDown = false; //drag is complete, mouse btn is no longer down
_previousPos = currentPos; //reset previous pos for next mouse move
}

Rotation of a Sprite Around Its Pivot

I have a class below that I attach to a object in order to make it rotate around its pivot. I sent the pivot of the sprite via the inspector.
This works exactly how I want it too, BUT the issue I am having is that whenever I touch and drag it, and then touch and drag it again, it snaps to a new position.
What I would like for it to do is, when it is rotated and then rotated again, the sprite stays in its same rotation and not snap to a new position and I would like the angle of the sprite to be reset to 0. The next then is that I want the angle to continually rotate. So if I rotate it in the positive direction, the angle should keep increasing in the positive direction and not change..Such as 0---> 360 ----> 720 -----> etc, etc. And then when the mouse is released, the sprite stays in the same position but the angle is now set back to 0. And then when clicked again to rotate, it rotates from that exact position.
Here is my code thus far which works well for rotating, but I would like to modify it to achieve the above scenario. Any help with this?
public class Steering : MonoBehaviour {
float prevAngle,wheelAngle,wheelNewAngle = 0;
public SpriteRenderer sprite;
void Start () {
}
void Update () {
}
public float GetAngle(){
return wheelAngle;
}
void OnMouseDrag(){
Vector3 mouse_pos = Input.mousePosition;
Vector3 player_pos = Camera.main.WorldToScreenPoint(this.transform.position);
mouse_pos.x = mouse_pos.x - player_pos.x;
mouse_pos.y = mouse_pos.y - player_pos.y;
wheelNewAngle = Mathf.Atan2 (mouse_pos.y, mouse_pos.x) * Mathf.Rad2Deg;
if (Input.mousePosition.x > sprite.bounds.center.x) {
wheelAngle += wheelNewAngle - prevAngle;
} else {
wheelAngle -= wheelNewAngle - prevAngle;
}
this.transform.rotation = Quaternion.Euler (new Vector3(0, 0, wheelAngle));
Debug.Log (wheelAngle);
prevAngle = wheelNewAngle;
}
void OnMouseUp(){
prevAngle = wheelNewAngle;
wheelAngle = 0;
}
}
By angle of the sprite, do you mean the rotation? I'm not sure how the position is changing if there's nothing in your code doing that. Does it always move to the same position? I'm having a little trouble visualizing how your system is supposed to look but I hope this helps.
It looks like you might want to store the previous mouse position so you can get the relative amount to rotate each frame.
At the top:
Vector3 prevMousePos = Vector3.zero;
This method will help get the position when the player pressed:
void OnMouseDown(){
prevMousePos = Input.mousePosition;
}
Then in OnMouseDrag() get the difference between the two mouse positions to get the relative position (if you moved the mouse left, right, up, or down since pressing):
Vector3 mouseDiff = Input.mousePosition - prevMousePos;
With this it will use the relative mouse position after pressing instead of the current one, which should smooth things out.

Release (drop) object being dragged

I am using an OnMouseDrag event to move an object. Trouble I have is that unless the mouse button is released the object will not drop. I want to be able to have the object drop if dragged to a certain location on screen (2d). So even if the mouse button is still down drop the object.
Here is the code I am using:
void OnMouseDown()
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
Debug.Log ("We clicked fire block!");
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, gameObject.transform.position.y, screenPoint.z));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, gameObject.transform.position.y, screenPoint.z);
if (curScreenPoint.x <= 1) {
return;
}
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint)+offset;
transform.position = curPosition;
isDrag = true;
}
I didn't understand one thing: this location is a portion of the screen or is a 3D location in the game?
Posting for both cases:
1 - Location is a 3D place in the game:
Use Physics.Raycast inside your OnMouseDragUpdate method to check if your mouse cursor is hitting the area it is supposed to release the dragged object (you'll need a game object with a collider representing the location). If so, simply do isDrag = false.
Here's an example of how to do the raycast.
2 - Location is a portion of the screen:
Input.mousePosition ranges from 0 (0%) to 1 (100%), so simply check the mouse position inside your OnMouseDragUpdate method to verify if it's inside the region that you want, and if so do isDrag = false.

Categories

Resources