Dragging an object in one line - c#

I am trying to make a dragging effect. I have a project where u are supposed to pull a bone out of meat. The dragging is working, but when i grab the bone i can move it in all directions. What i would like to achieve is that i can only drag it in one direction. On the images below i mean the red line. I tried many things but nothing worked so far. Any help is appreciated.
I used these functions for the dragging.
void OnMouseDown()
{
offset = this.transform.position - Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}

Just get the x component of your mouse and use localPosition:
void OnMouseDown()
{
offset = this.transform.localPosition - Camera.main.ScreenToWorldPoint(new Vector2(transform.localPosition.x, Input.mousePosition.y));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector2(transform.localPosition.x, Input.mousePosition.y);
Vector3 mousePos = Camera.main.ScreenToWorldPoint(curScreenPoint);
Vector3 curPosition = new Vector3(mousePos.x, 0f, 0f) + offset;
transform.localPosition = curPosition;
}

Related

How to Rotate 2D Sprite Towards Moving Direction?

I have been searching all day and reading forums but I can't find a way that works. I'm making a top-down view horror game. When my player walks normally he can look around with the cursor in any direction, but when he wants to run he switches to "tank" controls and rotates toward the running direction. I need something like this.
My player movement script so far:
public float walkSpeed;
public float runSpeed;
public float turnSpeed;
private Rigidbody2D rb;
public Camera cam;
private Vector2 moveDirection;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
ProcessInput();
}
void FixedUpdate()
{
Move();
}
private void ProcessInput()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY).normalized;
}
void Move()
{
if (Input.GetKey(KeyCode.LeftShift))
{
//Looking toward movement direction should be applied here
} else {
rb.velocity = new Vector2(moveDirection.x * walkSpeed, moveDirection.y * walkSpeed);
Vector3 mousePosition = cam.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;
float angle = Vector2.SignedAngle(Vector2.right, direction) - 90f;
Vector3 targetRotation = new Vector3(0, 0, angle);
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(targetRotation), turnSpeed * Time.deltaTime);
}
}
Any help is greatly appreciated! Thanks in advance!
This problem can be solved by substituting moveDirection instead of the mouse look direction, here it is enough to define a hypothetical variable called direction to detect the correct direction in each of these conditions.
var direction = new Vector2();
var currentSpeed = walkSpeed;
if (Input.GetKey(KeyCode.LeftShift))
{
direction = moveDirection;
currentSpeed = runSpeed;
} else {
direction = cam.ScreenToWorldPoint(Input.mousePosition) - transform.position;
}
var angle = Vector2.SignedAngle(Vector2.right, direction) - 90f;
var targetRotation = new Vector3(0, 0, angle);
var lookTo = Quaternion.Euler(targetRotation);
rb.velocity = new Vector2(moveDirection.x, moveDirection.y) * runSpeed *Time.deltaTime;
transform.rotation = Quaternion.RotateTowards(transform.rotation, lookTo , turnSpeed * Time.deltaTime);

Rotate rigidbody with moverotation in the direction of the camera

I want to use moverotation to rotate the object in the direction of the Main Camera, like a common third person shooter, but I don't know how to set the quaternion values or otherwise
`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movimento : MonoBehaviour
{
[SerializeField] float walk = 1;
[SerializeField] float run = 2;
Vector3 movement = Vector3.zero;
private Rigidbody rig;
// Start is called before the first frame update
void Start()
{
rig = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift)) walk = (walk + run);
if (Input.GetKeyUp(KeyCode.LeftShift)) walk = (walk - run);
float Horizontal = Input.GetAxis("Horizontal");.
float Vertical = Input.GetAxis("Vertical");
movement = Camera.main.transform.forward * Vertical + Camera.main.transform.right * Horizontal;
float origMagnitude = movement.magnitude;
movement.y = 0f;
movement = movement.normalized * origMagnitude;
}
private void FixedUpdate ()
{
rig.MovePosition(rig.position + movement * walk * Time.fixedDeltaTime);
Quaternion rotation = Quaternion.Euler(???);
rig.MoveRotation(rig.rotation * rotation);
}
}`
i use a coroutine to do smooth rotation. I use Quaternion.LookRotation for the job.
so you indicate the position of object to look at and the duration of animation. Here you want to rotate face to the main camera
StartCoroutine(SmoothRotation(Camera.main.transform, 3f));
:
:
IEnumerator SmoothRotation(Transform target, float duration)
{
float currentDelta = 0;
var startrotation = transform.rotation;//use your rigisbody if you want here i use the gameobject
var LookPos = target.position - transform.position;
var finalrot = Quaternion.LookRotation(LookPos);
while (currentDelta <= 1f)
{
currentDelta += Time.deltaTime / duration;
transform.rotation = Quaternion.Lerp(startrotation, finalrot, currentDelta);//
yield return null;
}
transform.rotation = finalrot;
}
if you want to see (in scene when running) where your camera points just add this line of code in update():
Debug.DrawRay(Camera.main.transform.position, Camera.main.transform.TransformDirection(Vector3.forward) * 10f, Color.black);
if you want to point in same direction tha nthe Camera just change the line of finalrot in SmoothRotation Method:
var finalrot = Camera.main.transform.rotation;
you dont need to calculate the LookPos
for your problem of crazy rotation, i suggest you to reset rotation x and z
direction = hit.transform.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(direction);
rotation.x = 0f;
rotation.z = 0f;
a tips to detect object what you want with the raycast inside spere : Physics.OverlapSphere: you could select what you want to cast when using the optional parameter layermask
private void DetectEnemy(Vector3 center, float radius)
{
var hitColliders = Physics.OverlapSphere(center, radius );
for (var i = 0; i < hitColliders.Length; i++)
{
print(hitColliders[i].name + "," + hitColliders[i].transform.position);
// collect information on the hits here
}
}
I created a raycast from the camera, and I would like to rotate the rigidbody to where the raycast is pointing but if i launch unity, it rotated wildly. What is the error?
Vector3 direction;
Vector3 rayDir = new Vector3(Screen.width/2,Screen.height/2);
void Update()
Ray ray = Camera.main.ScreenPointToRay(rayDir);
Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
RaycastHit hit = new RaycastHit ();
direction = hit.point - transform.position;
private void FixedUpdate ()
Quaternion rotation = Quaternion.LookRotation(direction);
rig.MoveRotation(rig.rotation * rotation);
Add a character controller component, this is what is for. See:
https://docs.unity3d.com/Manual/class-CharacterController.html

C# Instantiate Prefab with Rotation

I have a little problem with this code:
private void Update()
{
if (Input.GetMouseButtonDown(0) && canClick)
{
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPosition.z = player.transform.position.z;
directionVector = player.transform.position - mouseWorldPosition;
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
Quaternion InstanceRotation = Quaternion.Euler(mouseWorldPosition.x - 90f, 0f, 0f);
GameObject effect = Instantiate(SteamFx, mouseWorldPosition, InstanceRotation);
effect.transform.LookAt(directionVector);
}
}
The problem is that when instantiating the object, it has a z rotation. So I have an effect that when I click on the screen, it should instantiate, and blow in the player direction. It has different rotation, how to make the rotation correct.
Thks!!!

Move the camera only until a certain position

https://scontent.fmgf1-2.fna.fbcdn.net/v/t34.0-12/15870843_1543174992374352_1359602831_n.gif?oh=dc048c9e04617007c5e82379fd5a9c1a&oe=586CC623
Can you see the blue area in this gif? I want block the camera when the player go more to left, to not see the blue area. This is the code that I'm using to move the camera:
public class configuracoesDaCamera : MonoBehaviour {
Vector3 hit_position = Vector3.zero;
Vector3 current_position = Vector3.zero;
Vector3 camera_position = Vector3.zero;
float z = 0.0f;
public static bool bDedoNoHud;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
hit_position = Input.mousePosition;
camera_position = transform.position;
}
if (Input.GetMouseButton(0))
{
current_position = Input.mousePosition;
LeftMouseDrag();
}
Debug.Log("bDedoNoHud" + bDedoNoHud);
}
void LeftMouseDrag()
{
if (!bDedoNoHud)
{
// From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height
// with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic.
current_position.z = hit_position.z = camera_position.y;
// Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position)
// anyways.
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
// Invert direction to that terrain appears to move with the mouse.
direction = direction * -1;
Vector3 position = camera_position + direction;
transform.position = position;
}
}
}
You mean setting up boundaries?
This should help you
Put it in the update()

How can I figure out the length in units from the player to the end of the camera view?

I'm working with Unity, in c#, and this is my setup.
The camera is facing down, to look at the cube. I'll be referring to the cube as the 'player' from now on.
The problem:
I want to spawn something where the camera cannot see it. This means I need to know exactly how far there is from the player to the end of the FOV, at the player's position.y (Which is always 0), in units.
The reason this cannot just be a constant variable is that the camera's position.y is not constant, and thus the player is allowed to see more of the game area the longer he plays.
There is extra info on what I've tried below, but if you have a better solution, I'll gladly take it.
Extra info:
This is the current script I'm sitting with:
using UnityEngine;
using System.Collections;
public class cameraFollowTarget : MonoBehaviour {
private Transform target;
private float defaultHeight = 3.0f;
private float cameraY;
private float playerSize;
private float moveSpeed = 2.0f;
//Playing with FOV//
private float verticalFOVrad;
private float verticalFOV;
private float cameraHeightAt1;
private float horizontalFOVrad;
private float horizontalFOV;
private float angleToPlayer;
private float defaultAngleToPlayer;
private Vector3 currentPos;
private Vector3 targetPos;
private Vector3 targetLookDir;
private Vector3 leftSideToCamera;
private Vector3 rightSideToCamera;
// Use this for initialization
void Start () {
target = GameObject.FindGameObjectWithTag ("Player").transform;
playerSize = target.GetComponent<playerCollect>().getPlayerSizeStart();
transform.position = new Vector3(transform.position.x, defaultHeight, transform.position.z);
cameraY = defaultHeight;
calculateAngleToPlayer();
defaultAngleToPlayer = angleToPlayer;
}
// Update is called once per frame
void FixedUpdate () {
if (transform.position != target.position) {
playerSize = GameObject.FindGameObjectWithTag("Player").GetComponent<playerCollect>().getPlayerSize();
currentPos = transform.position;
calculateAngleToPlayer();
while(angleToPlayer > defaultAngleToPlayer)
{
cameraY += 0.1f;
calculateAngleToPlayer();
}
targetPos = new Vector3(target.position.x, cameraY, target.position.z);
transform.position = Vector3.Slerp(currentPos, targetPos, moveSpeed * Time.deltaTime);
Camera.main.farClipPlane = cameraY + playerSize / 2;
}
if (transform.rotation != target.rotation) {
Vector3 targetRot;
//Not working
//targetRot = Vector3.Lerp (transform.eulerAngles, new Vector3(90, target.transform.eulerAngles.y, 0), turnSpeed * Time.deltaTime);
//Working but ugly
targetRot = new Vector3(90, target.transform.eulerAngles.y, 0);
transform.eulerAngles = targetRot;
}
//Playing with FOV//
getVerticalFOV ();
getHorizontalFOV ();
print ("Horizontal = " + getHorizontalFOV());
print ("Vertical = " + getVerticalFOV());
}
float getVerticalFOV()
{
horizontalFOVrad = Camera.main.fieldOfView * Mathf.Deg2Rad;
cameraHeightAt1 = Mathf.Tan(horizontalFOVrad * 0.5f);
verticalFOVrad = Mathf.Atan(cameraHeightAt1 * Camera.main.aspect) * 2;
verticalFOV = verticalFOVrad * Mathf.Rad2Deg;
return verticalFOV;
}
float getHorizontalFOV()
{
horizontalFOV = Camera.main.fieldOfView;
return horizontalFOV;
}
float calculateAngleToPlayer()
{
Vector3 imaginaryPos = new Vector3(target.position.x, transform.position.y + cameraY, target.position.z);
leftSideToCamera = new Vector3(target.position.x - (playerSize / 2.0f), target.position.y, target.position.z) - imaginaryPos;
rightSideToCamera = new Vector3(target.position.x + (playerSize / 2.0f), target.position.y, target.position.z) - imaginaryPos;
angleToPlayer = Vector3.Angle(leftSideToCamera, rightSideToCamera);
return angleToPlayer;
}
public float getScreenUnitHorizontal(GameObject target)
{
GameObject imaginaryPos = new GameObject ();
imaginaryPos.transform.position = target.transform.position;
imaginaryPos.transform.rotation = Camera.main.transform.rotation;
float screenUnitHorizontal = 0.0f;
Vector3 vecMidToCamera = Camera.main.transform.position - new Vector3 (Camera.main.transform.position.x, 0.0f, Camera.main.transform.position.z);
Vector3 vecImagiToCamera = Camera.main.transform.position - imaginaryPos.transform.position;
while (Vector3.Angle(vecMidToCamera, vecImagiToCamera) <= getHorizontalFOV() / 2) {
screenUnitHorizontal += 0.1f;
imaginaryPos.transform.position = target.transform.forward * screenUnitHorizontal * Time.deltaTime;
vecMidToCamera = Camera.main.transform.position - new Vector3 (Camera.main.transform.position.x, 0.0f, Camera.main.transform.position.z);
vecImagiToCamera = Camera.main.transform.position - imaginaryPos.transform.position;
}
Debug.DrawLine(Camera.main.transform.position, new Vector3 (Camera.main.transform.position.x, 0.0f, Camera.main.transform.position.z), Color.red);
Debug.DrawLine(Camera.main.transform.position, imaginaryPos.transform.position, Color.red);
Destroy (imaginaryPos);
return screenUnitHorizontal;
}
}
"GetScreenUnitHorizontal" is the main problematic function. It is working, but it is not doing what I was intending.
My intention:
Create a gameobject at the player's position. Then move the gameobject forward until it reaches an angle that is greater than the FOV.
This works fine, in (0, 0, 0). It does not if I move away, and rotate.
If I keep rotating one way, the gameobject seem to place itself in some kind of curve. Possibly a sinus curve.
The solution
31eee384 was the one who solved it for me.
The part of my code that is the solution looks like this:
public class cameraFollowTarget : MonoBehaviour {
private Ray lowerLeft;
private Ray lowerRight;
private Ray upperLeft;
private Ray upperRight;
void FixedUpdate () {
lowerLeft = Camera.main.ScreenPointToRay(new Vector3(0, 0));
lowerRight = Camera.main.ScreenPointToRay(new Vector3(Camera.main.pixelWidth, 0));
upperLeft = Camera.main.ScreenPointToRay(new Vector3(0, Camera.main.pixelHeight));
upperRight = Camera.main.ScreenPointToRay(new Vector3(Camera.main.pixelWidth, Camera.main.pixelHeight));
}
Vector3 getScreenCollisionPoint(Ray corner)
{
Plane spawnPlane = new Plane (new Vector3 (0, 1, 0), Vector3.zero);
float _Distance;
Vector3 collisionPoint;
if (spawnPlane.Raycast (corner, out _Distance) == true) {
collisionPoint = corner.GetPoint(_Distance);
}
Debug.DrawLine(transform.position, collisionPoint, Color.red);
return collisionPoint;
}
If the function getScreenCollisionPoint is called in Update(), it will keep showing where the corners are.
In my setup I also have:
print ("upperLeft = " + getScreenCollisionPoint (upperLeft).z + "," + getScreenCollisionPoint (upperLeft).z);
print ("upperRight = " + getScreenCollisionPoint (upperRight).z + "," + getScreenCollisionPoint (upperRight).z);
print ("lowerLeft = " + getScreenCollisionPoint (lowerLeft).z + "," + getScreenCollisionPoint (lowerLeft).z);
print ("lowerRight = " + getScreenCollisionPoint (lowerRight).z + "," + getScreenCollisionPoint (lowerRight).z);
so that I can see what the values of x and z are, for each of the corners.
Check out Camera.ScreenPointToRay. You can call that with four vectors to get a Ray at each corner of the screen (passing <0,0,0> <x,0,0> <0,y,0> <x,y,0> where x = pixelWidth and y = pixelHeight).
To do this with the main camera:
Ray upperLeft = Camera.main.ScreenPointToRay(new Vector3(0, Camera.main.pixelHeight, 0));
Then, you need to do a Plane.Raycast on a x-z (flat) plane to find the position of each corner where y = 0.
Plane spawnPlane = new Plane(new Vector3(0, 1, 0), Vector3.zero);
float distance;
if (spawnPlane.Raycast(upperLeft, out distance))
{
// The cast has collided! Now find out where it hit.
Vector3 collisionPoint = upperLeft.GetPoint(distance);
}
collisionPoint is then the point where y = 0 corresponding to the upper-left corner of the screen!
Doing this for each corner of the screen gives you the square where the camera can see if you connect up the points. (A trapezoid if you choose to rotate the camera.) You can use that "viewable x-z plane shape" to do whatever else you need to do!
To do what you're trying to do now directly, you can instead use ScreenPointToRay with <pixelWidth/2, pixelHeight, 0> to find the ray at the top-center of the camera view.
To see this at work, I made a script that draws debug lines onto the x-z origin plane using this technique. Copy this code into a new component and add it to the camera:
using System.Linq;
using UnityEngine;
public class Test : MonoBehaviour
{
void Update()
{
Camera cam = GetComponent<Camera>();
Ray[] rays = new[]
{
new Vector3(0, 0),
new Vector3(0, cam.pixelHeight),
new Vector3(cam.pixelWidth, 0),
new Vector3(cam.pixelWidth, cam.pixelHeight)
}.Select(ray => cam.ScreenPointToRay(ray)).ToArray();
Plane xz = new Plane(new Vector3(0, 1, 0), Vector3.zero);
foreach (Ray ray in rays)
{
float distanceAlongRay;
if (xz.Raycast(ray, out distanceAlongRay))
{
Vector3 intersect = ray.GetPoint(distanceAlongRay);
Debug.DrawLine(transform.position, intersect, Color.red);
}
}
}
}
Assuming the camera always stays exactly above the player position, the distance from the player position to the edge of the camera's field of view is:
tan(0.5 * FOV) * camera_height
Where FOV is the field of view in the direction you want to move the object, tan is the tangent (Mathf.Tan), and camera_height is the vertical distance from the player to the camera.

Categories