How to move Line Renderer along with Camera - c#

I am trying to make Line Renderer's first point move along with Camera. When I do it with a Camera that is still, it works fine. But when camera changes position and in that position if I try to create new Line with Line Renderer it goes weird. I tried updating the position of first point by multiplying camera.tranform.position with dragBeginPos but it doesn't seem to help as it makes it even bad.
public class DragController : MonoBehaviour
{
[SerializeField] private float maxDrag = 3f; // Maximum drag distance
[SerializeField] private LineRenderer lr;
private Vector3 dragBeganPos; // Position of the mouse or touch when the drag began
private Vector3 dragEndPosPublic;
private Touch touch;
private PlayerBallMovement playerBallMovement;
[HideInInspector] public Vector3 dragDirection; // Pure drag direction without max drag distance
[HideInInspector] public Vector3 dragDirectionClamped; // Clamped drag direction with max drag distance
private enum ControlsType
{
Touch,
Mouse
}
private enum DirectionType
{
Normal,
Clamped
}
[SerializeField] private ControlsType controlsType = ControlsType.Mouse; // Default controls type are mouse
[SerializeField] private DirectionType directionType = DirectionType.Clamped; // Default direction type is clamped
void Update()
{
if (controlsType == ControlsType.Mouse)
{
DragWithMouse();
}
else if (controlsType == ControlsType.Touch)
{
DragWithTouch();
}
//UpdateLineRendererPointsPositions();
}
void DragWithMouse()
{
// Mouse button inputs
if (Input.GetMouseButtonDown(0)) DragBegan();
if (Input.GetMouseButton(0)) DragMoved();
if (Input.GetMouseButtonUp(0)) DragEnded();
}
void DragWithTouch()
{
// Touch inputs
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began) DragBegan();
if (touch.phase == TouchPhase.Moved) DragMoved();
if (touch.phase == TouchPhase.Ended) DragEnded();
}
}
// Drag begins defining start position of Line Rederer
void DragBegan()
{
dragBeganPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragBeganPos.z = 0f;
lr.positionCount = 1;
lr.SetPosition(0, dragBeganPos);
}
// Drag moved calculates the end point of the Line Rederer until mouse or touch is released
void DragMoved()
{
Vector3 dragMovedPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragMovedPos.z = 0f;
lr.positionCount = 2;
lr.SetPosition(1, dragMovedPos);
}
// Drag ended defines the end point of the Line Rederer and calculates the drag direction and clamped drag direction
void DragEnded()
{
lr.positionCount = 0;
Vector3 dragEndedPos = Camera.main.ScreenToWorldPoint(
controlsType == ControlsType.Mouse ? Input.mousePosition : (Vector3)touch.position
);
dragEndedPos.z = 0f;
dragEndPosPublic = dragEndedPos;
dragDirection = dragEndedPos - dragBeganPos; // It will apply force without any max speed defined (no clamp)
dragDirectionClamped = Vector3.ClampMagnitude(dragDirection, maxDrag); // It will apply force with max speed defined
Vector3 finalDirection = directionType == DirectionType.Clamped ? dragDirectionClamped : dragDirection;
// Here you can use dragDirection or dragDirectionClamped however you want
playerBallMovement = FindObjectOfType<PlayerBallMovement>();
playerBallMovement.ApplyVelocityInDirection(finalDirection);
}
}```

Related

Is there a way to zoom a 2D canvas in Unity?

I am making a 2d mobile app, and I would like to zoom in my screen. I have a Screen Space - Overlay in my canvas. I tried this but it does not zoom my screen.
I have attached this script to my canvas:
Vector3 touchStart;
public float zoomOutMin = 1;
public float zoomOutMax = 8;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (Input.touchCount == 2)
{
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
float prevMagnitude = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float currentMagnitude = (touchZero.position - touchOne.position).magnitude;
float difference = currentMagnitude - prevMagnitude;
zoom(difference * 0.01f);
}
else if (Input.GetMouseButton(0))
{
Vector3 direction = touchStart - Camera.main.ScreenToWorldPoint(Input.mousePosition);
Camera.main.transform.position += direction;
}
zoom(Input.GetAxis("Mouse ScrollWheel"));
}
void zoom(float increment)
{
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize - increment, zoomOutMin, zoomOutMax);
}
Instead of changing camera orthographic size you can try the other way round and change scale of canvas itself in both axis equally something like
Edit : I am editing the script to explain better. Just attach this script to Parent of the objects you want to zoom in to. You must not attach this on canvas as it will have no effect instead you can create an empty parent and move all of the objects to be zoomed in inside that parent as children and attach this script to parent.
public class ZoomTest : MonoBehaviour
{
[SerializeField] private float zoomOutMin;
[SerializeField] private float zoomOutMax;
private void Update()
{
float MouseWheelAxis = Input.GetAxis("Mouse ScrollWheel");
if (MouseWheelAxis != 0)
{
zoom(MouseWheelAxis);
}
}
void zoom(float increment)
{
float ClampX = Mathf.Clamp(transform.localScale.x +
increment,
zoomOutMin, zoomOutMax);
float ClampY = Mathf.Clamp(transform.localScale.y +
increment,
zoomOutMin, zoomOutMax);
transform.localScale = new
Vector2(ClampX ,ClampY);
}
}

Moving objects independently of each other, with the ability to move at the same time in Unity 2D

I have two objects. The point is that I need to move the object up and down (hold and drag), and at the same time I need to move the other object up and down (hold and drag) independently. Something like this:
Example
After searching the Internet, I found a small script, but it only works for one touch at a time, and dragging only one object. Plus, if I touch with second finger the object changes his position to second finger position:
public class Move : MonoBehaviour {
private Vector3 offset;
void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(-2.527f, Input.mousePosition.y));
}
void OnMouseDrag() {
Vector3 curScreenPoint = new Vector3(-2.527f, Input.mousePosition.y);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
}
I just can’t understand how I can make two objects drag and drop at the same time. I am new to unity and honestly i have problems with controllers
For touch screens I suggest you use Touch instead of mouse events. Touch class supports multiple touches at the same time and some useful information such as Touch.phase (Began, moving, stationary etc). I've written a script which you can attach to multiple objects with tag "Draggable", that makes objects move independently. Drag and drop the other object that should move when you use one finger to field otherObj and it should work. It only works for 2 obj in this version.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
public class PlayerActionHandler : MonoBehaviour
{
private Camera _cam;
public bool beingDragged;
public Vector3 offset;
public Vector3 currPos;
public int fingerIndex;
public GameObject otherObj;
// Start is called before the first frame update
void Start()
{
_cam = Camera.main;
}
// Update is called once per frame
void Update()
{
//ONLY WORKS FOR 2 OBJECTS
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(0).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = 0;
}
}
}
}else if (Input.touchCount == 1 && beingDragged)
{
otherObj.transform.SetParent(transform);
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}
//ONLY WORKS FOR 2 OBJECTS_END
else if (beingDragged && Input.touchCount > 1)
{
//We tie each finger to an object so the object only moves when tied finger moves
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}else if (Input.touchCount > 0)
{
for (var i = 0; i < Input.touchCount; i++)
{
//We find the fingers which just touched the screen
if(Input.GetTouch(i).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(i).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = i;
}
}
}
}
}
}else if (Input.touchCount == 0)
{
//if all fingers are lifted no object is being dragged
beingDragged = false;
}
}
}

How to link long press to move script

I found this script: https://unity3d.college/2018/01/30/unity3d-ugui-hold-click-buttons/
I am using Vuforia btw.
I was wondering how to link it to my movement script.
using UnityEngine;
public class MyDragBehaviour : MonoBehaviour
{
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase ==
TouchPhase.Moved)
{
// create ray from the camera and passing through the touch
position:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
// create a logical plane at this object's position
// and perpendicular to world Y:
Plane plane = new Plane(Vector3.up, transform.position);
float distance = 0; // this will return the distance from the camera
if (plane.Raycast(ray, out distance))
{ // if plane hit...
Vector3 pos = ray.GetPoint(distance); // get the point
transform.position = pos;
// pos has the position in the plane you've touched
}
}
}
}
The current movement script will move my object instantly to where the tap happened on screen. I would like to have it so that you have to long press the object before moving it to avoid having the object jump around on screen.
EDIT
using UnityEngine;
using UnityEngine.EventSystems;
public class MyDragBehaviour : MonoBehaviour
{
float pointerDownTimer = 0;
const float requiredHoldTime = 0.5f; //has to hold for 0.5 seconds
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
pointerDownTimer += Time.deltaTime;
if (pointerDownTimer >= requiredHoldTime)
{
pointerDownTimer = 0;
if (!EventSystem.current.IsPointerOverGameObject())
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// create ray from the camera and passing through the touch position:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
// create a logical plane at this object's position
// and perpendicular to world Y:
Plane plane = new Plane(Vector3.up, transform.position);
float distance = 0; // this will return the distance from the camera
if (plane.Raycast(ray, out distance))
{ // if plane hit...
Vector3 pos = ray.GetPoint(distance); // get the point
transform.position = pos; // pos has the position in the plane you've touched
} //whatever happens when you click
}
}
else
{
pointerDownTimer = 0;
}
}
}
}
You just need to implement a simple timer, that increases when you press and resets when you release:
float pointerDownTimer = 0;
const float requiredHoldTime = 0.5f //has to hold for 0.5 seconds
void Update(){
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
pointerDownTimer += Time.deltaTime;
if (pointerDownTimer >= requiredHoldTime){
...... //whatever happens when you click
}
} else{
pointerDownTimer = 0;
}
}

Limit where I can Instantiate on mousedown?

My script puts an object at the position of the mouse, regardless of the position.
I'd like to limit where I can place the object to a small area around the player sprite.
Say if mouse X if greater than (X position + a little) of the players X than the object wont Instantiate. I've tried if statements along these lines but haven't been able to get it to work.
Here is the placement script.
public GameObject seedlings;
public GameObject player;
Vector3 mousePOS = Input.mousePosition;
// Use this for initialization
void Start(){}
// Update is called once per frame
void Update()
{
PlantInGround();
}
void PlantInGround()
{
Vector3 mousePOS = Input.mousePosition;
if (Input.GetMouseButtonDown(0))
{
mousePOS.z = +12;
mousePOS = Camera.main.ScreenToWorldPoint(mousePOS);
Instantiate(seedlings, (mousePOS), Quaternion.identity);
Debug.Log(mousePOS);
}
}
Grateful for any help.
To check if the your seedling position is near your player's position:
float maxDist = 3F; //radius within the player that the seedling can be instantiated
if ( (mousePOS - player.transform.position).magnitude < maxDist )
{
//Do Something
}
You could compare the distance squared instead, since magnitude involves a Sqrt() call which is expensive, but given that you are doing this only on a mouse click, it shouldn't really matter much.
Of course, you have to be sure that your player is about 12 units away from the camera's forward viewing direction.. given that you are doing this:
mousePOS.z = +12;
mousePOS = Camera.main.ScreenToWorldPoint(mousePOS);
This is what ended up working. Leaving it for others. I honestly don't know why the coordinates just lined up. Thanks for the help #Lincon.
public class PlantItem : MonoBehaviour
{
public GameObject seedlings;
public GameObject player;
Vector3 mousePOS = Input.mousePosition;
void Update()
{
if (!Input.GetMouseButtonDown(0))
{
PlantInGround();
}
}
void PlantInGround()
{
Vector3 mousePOS = Input.mousePosition;
mousePOS.z = +12;
mousePOS = Camera.main.ScreenToWorldPoint(mousePOS);
if (((player.transform.position.y < mousePOS.y + 0.5) && (player.transform.position.y > mousePOS.y - 1.5)) && ((player.transform.position.x < mousePOS.x + 1) && (player.transform.position.x > mousePOS.x - 1)))
{
Instantiate(seedlings, mousePOS, Quaternion.identity);
}
}
}

Issue with moving object along dynamically defined line

I'm an absolute programming beginner. I'm working on a tiny game prototype just for fun.
You are dragging a character. When you drag the character, the char stays still and you see a targeting line, pointing the opposite direction. When you release the mouse button, the character should move along the targeting line until he hits something.
Everything pretty much works. But there is a slight offset. The character is moving a bit off the targeting line. I feel there is something wrong in the raycast part of the code (in the Dragging() method).
Here is my code:
using UnityEngine;
using System.Collections;
public class PlayerControllerTest : MonoBehaviour {
Rigidbody2D rig;
int dragging;
Vector3 mousePosition;
bool wasMoving;
LineRenderer lineRenderer;
void Start () {
lineRenderer = GetComponent<LineRenderer> ();
rig = GetComponent<Rigidbody2D> ();
}
void Update () {
if (dragging == 1) {
Dragging ();
}
if (dragging == 2) {
float distanceMouseToPlayer = Vector3.Distance (transform.position,mousePosition);
rig.velocity = (-transform.InverseTransformPoint (mousePosition))/distanceMouseToPlayer * 3;
}
}
void OnMouseDown()
{
dragging = 1;
}
void Dragging()
{
mousePosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
mousePosition.z = 0f;
var layerMask = 1 << 8;
layerMask = ~layerMask;
RaycastHit2D hit = Physics2D.Raycast (mousePosition,transform.position- mousePosition,Mathf.Infinity,layerMask);
lineRenderer.enabled = true;
lineRenderer.SetPosition (0, transform.position);
lineRenderer.SetPosition (1, hit.point);
}
void OnMouseUp()
{
dragging = 2;
lineRenderer.enabled = false;
}
}

Categories