Mathf.Clamp inside of a sphere radius Unity - c#

I have a simple joystick move script. I restricted its movement on x and z axis with a Mathf.Clamp. What I am trying to achive is to use that function inside a sphere radius.
I need the gameobject movement restrict its movement if the gameobjects position is outside of the radius.
void UpdateMoveJoystick()
{
horizontale = moveJoystick.Horizontal;
float ver = moveJoystick.Vertical;
Vector2 convertedXY = ConvertWithCamera(Camera.main.transform.position, horizontale, ver);
Vector3 direction = new Vector3(convertedXY.x, 0, convertedXY.y).normalized;
transform.Translate(direction * 0.02f * speed, Space.World);
Quaternion targetRotation = Quaternion.LookRotation(direction);
RestrictMovement();
}
void RestrictMovement()
{
var position1 = transformPos.transform.position.x;
var position2 = transformPos.transform.position.x;
var position3 = transformPos.transform.position.z;
var position4 = transformPos.transform.position.z;
float xMovementClamp = Mathf.Clamp(transform.position.x, position1 += leftBoundry, position2 += rightBoundry);
float zMovementClamp = Mathf.Clamp(transform.position.z, position3 += DownBoundry, position4 += UpBoundry);
transform.position = new Vector3(xMovementClamp, transform.position.y, zMovementClamp);
}
Anyway Thanks for help :)

The function you are looking for is Vector2.ClampMagnitude. This method takes a Vector2 and allows you to ensure that the magnitude (or vector length) is no longer than the desired length (or the radius of the circle).
With this in mind, the RestrictMovement method from your code would look something like this:
public float boundryRadius = 20.0f;
void RestrictMovement()
{
var positionXY = new Vector2(transform.position.x, transform.position.y);
positionXY = Vector2.ClampMagnitude(positionXY, boundryRadius);
transform.position = new Vector3(positionXY.x, positionXY.y, transform.position.z);
}
This would clamp the GameObject in the boundryRadius specified around the world position of 0, 0, 0. Additional maths can be used to change the centre of the circular boundary.

Related

How to use LookRotation to rotate an object based on hand positions?

I'm creating an interaction system for a VR game and I'm struggling with two hand interactions. I'm using the Quaternion.LookRotation() method to generate the rotation of the grabbed object based on the positions and rotations of the hands. The forward part is pretty simple:
Vector3 fwd = (primaryHand.position - secondaryHand.position).normalized;
The "up" part is what I have difficulty with. Initially I tried using the average up direction of both hands:
Vector3 avgUp = Quaternion.Slerp(primaryHand.rotation, secondaryHand.rotation, 0.5f) * Vector3.up;
There is an issue with this approach: the hand's up vector might get aligned with the fwd vector, which causes the object to flip over when it goes over it. Here is a simple illustration of the problem:
The light green arrows represent the up direction of the hands, while the dark green is the calculated direction used as an argument for the LookRotation() method.
The obvious solution seems to be to pick a different fixed vector instead of "up", one which won't be so easily aligned with the fwd vector. In the example it could be a vector aligned with the fingers. But keep in mind that there are no restrictions on initial hand rotation so no matter which vector you choose the hands can always happen to be rotated so that the vectors align. And even if you pick the an optimal vector dynamically (one that is perpendicular to fwd), it's still at best 90 degrees from aligning with fwd.
To solve this I tried restricting the direction to the values which don't cause problems but this caused another issues (I had difficulties with determining which values are ok and which should be discarded). I feel like I'm doing something wrong here, is there any better solution to this problem?
You can calculate the delta rotations of the hands and apply it to the "base up" of the object (the new up if we only take into account the change in position of hands...which will of course be orthogonal to the axis of the object). Then determine the change in angle that results in that up being rotated with each hand. Average those angles out, then apply those angles with the hand-hand axis using Quaternion.AngleAxis to the "base up" from earlier. Then you have your forward and up for Quaternion.LookRotation).
Below is an example of how you can use this, including VR hand noise simulation. To see the test, create a new scene in unity and attach this to the camera and it will build the scene on play start. There is a grip/release gui that will appear in Play view. You can adjust the hand rotation in Scene view
Vector3 leftHandPosCurrent;
Vector3 rightHandPosCurrent;
Vector3 worldAxisPrev;
Quaternion leftHandRotPrev;
Quaternion leftHandRotCurrent;
Quaternion rightHandRotPrev;
Quaternion rightHandRotCurrent;
bool isGripping;
bool firstFrameGripping;
Rigidbody grippedRB;
Transform leftHand;
Transform rightHand;
Quaternion targetRot;
/*
* On subsequent frames of gripping, calculate deltas in positions and
* rotations, average out the hand's effects, then apply them to the gripped
* object
*/
void HandleGrippedRot()
{
Vector3 worldAxisCurrent = rightHandPosCurrent - leftHandPosCurrent;
if (!firstFrameGripping)
{
Vector3 prevUp = targetRot * Vector3.up;
// we haven't moved the transform based on the hands yet, so
// find the new up would be ignoring hand rotations
Vector3 newUp = Quaternion.FromToRotation(worldAxisPrev,
worldAxisCurrent) * prevUp;
float leftHandAngle = GetDegRot(newUp, leftHandRotPrev,
leftHandRotCurrent, worldAxisCurrent);
float rightHandAngle = GetDegRot(newUp, rightHandRotPrev,
rightHandRotCurrent, worldAxisCurrent);
float avgAngle = (leftHandAngle + rightHandAngle) * 0.5f;
newUp = Quaternion.AngleAxis(avgAngle, worldAxisCurrent) * prevUp;
targetRot = Quaternion.LookRotation(worldAxisCurrent,
newUp);
}
else
{
firstFrameGripping = false;
}
leftHandRotPrev = leftHandRotCurrent;
rightHandRotPrev = rightHandRotCurrent;
worldAxisPrev = worldAxisCurrent;
}
/*
* Given the "up" of the object without taking hand rotations into account
* and the axis, determine how a hand's delta rotation affects that up
* around the axis and return the angle of that rotation
*/
float GetDegRot(Vector3 baseUp, Quaternion prevHandRot, Quaternion curHandRot,
Vector3 axis)
{
Vector3 adjUp = (curHandRot * Quaternion.Inverse(prevHandRot)) * baseUp;
adjUp = Vector3.ProjectOnPlane(adjUp, axis);
return Vector3.SignedAngle(baseUp, adjUp, axis);
}
void Update()
{
AddVRNoise(leftHand);
AddVRNoise(rightHand);
leftHandPosCurrent = leftHand.position;
rightHandPosCurrent = rightHand.position;
leftHandRotCurrent = leftHand.rotation;
rightHandRotCurrent = rightHand.rotation;
if (isGripping)
{
HandleGrippedRot();
}
}
void StartGrip()
{
if (isGripping) return;
isGripping = true;
firstFrameGripping = true;
// grippedTransform is set accordingly at some point
}
void EndGrip()
{
if (!isGripping) return;
isGripping = false;
}
/*
* example of using targetRot to move rb
*/
private void FixedUpdate()
{
if (!isGripping) return;
Quaternion delta = targetRot
* Quaternion.Inverse(grippedRB.transform.rotation);
delta.ToAngleAxis(out float angle, out Vector3 axis);
// convert to shortest angle form
if (angle > 180f)
{
axis = -axis; angle = 360f - angle;
}
grippedRB.angularVelocity = angle * 0.25f * axis;
}
/*
* just for testing purposes
*/
void Start()
{
leftHand = CreateHand(true);
leftHand.position = Vector3.left;
rightHand = CreateHand(false);
rightHand.position = Vector3.right;
CreateArrow();
}
/*
* just for testing purposes
*/
void AddVRNoise(Transform hand)
{
Quaternion noise = Random.rotation;
noise.ToAngleAxis(out float angle, out Vector3 axis);
angle = 100f * Time.deltaTime;
noise = Quaternion.AngleAxis(angle, axis);
Quaternion noisyRot = hand.rotation * noise;
hand.rotation = noisyRot;
}
/*
* just for testing purposes
*/
void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 50), "Grip"))
{
StartGrip();
}
if (GUI.Button(new Rect(100, 0, 100, 50), "Release"))
{
EndGrip();
}
}
/*
* just for testing purposes
*/
Transform CreateHand(bool isLeft)
{
string handName = isLeft ? "Left" : "Right";
GameObject hand = new GameObject($"{handName}hand");
GameObject palm = GameObject.CreatePrimitive(PrimitiveType.Cube);
palm.transform.localScale = new Vector3(0.5f, 0.2f, 1f);
palm.transform.SetParent(hand.transform);
GameObject thumb = GameObject.CreatePrimitive(PrimitiveType.Cube);
thumb.transform.localScale = new Vector3(0.2f, 0.1f, 0.1f);
thumb.transform.SetParent(hand.transform);
thumb.transform.localPosition = new Vector3(isLeft ? 0.32f : -0.32f,
0f, -.31f);
return hand.transform;
}
/*
* just for testing purposes
*/
void CreateArrow()
{
GameObject arrow = new GameObject();
GameObject body = GameObject.CreatePrimitive(PrimitiveType.Cube);
body.transform.localScale = new Vector3(1f, 1f, 5f);
body.transform.SetParent(arrow.transform);
GameObject head = GameObject.CreatePrimitive(PrimitiveType.Cube);
head.transform.SetParent(arrow.transform);
head.transform.localEulerAngles = Vector3.up * 45f;
head.transform.localPosition = new Vector3(0f, 0f, 2.5f);
grippedRB = arrow.AddComponent<Rigidbody>();
grippedRB.useGravity = false;
arrow.transform.position = 2f * Vector3.up;
}

Making Field of view using Raycasts With for loops (Using Unity C#)

Code:
void IdleState ()
{
RaycastHit hit;
for (float i = -ViewWidth; i < ViewWidth; i++)
{
float Iterater = i/20;
if (Physics.Raycast(transform.position, transform.forward + new Vector3(Iterater,0,0), out hit, ViewRange))
{
Debug.DrawRay(transform.position,(transform.forward + new Vector3(Iterater,0,0)).normalized * ViewRange, Color.red);
if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Player"))
{
FoundPlayer(hit.transform);
}
}
}
}
Problem: In Unity I am trying to create a Field of view for an enemy AI by drawing multiple raycasts with for loops. For some reason the raycasts do this:
GIF
I've been trying to fix this for days Please help!
Also the FoundPlayer() function in case you need it:
void FoundPlayer (Transform DetectedObject)
{
float step = TurnSpeed * Time.deltaTime;
Vector3 Direc = DetectedObject.position - transform.position;
Vector3 RotMath = Vector3.RotateTowards(transform.forward, Direc,step,0.0f);
transform.rotation = Quaternion.LookRotation(RotMath);
Vector3 CurrentRot = transform.eulerAngles;
transform.rotation = Quaternion.Euler(0,CurrentRot.y,0);
}
The FoundPlayer() function just rotates the enemy towards the player when one of the raycasts hit it.
Regarding Raycast:
transform.Forward is in world-space coordinates, to which you add some fraction of world-space X-axis offset. What you wanted is to add some fraction of 'local-space' X-axis. transform.Right is the world-space conversion of local-space X-axis. Try:
var rayDirection = (transform.Forward + (Vector3.Scale(transform.Right, new Vector3(Iterater, 0, 0))).normalized;
Regarding Fields of View:
If all you want to do is check what objects are within a FOV, start finding everything within a sphere, then filter those objects to what's within appropriate angles from transform.forward:
float ViewRange = 10;
float hHalfFov = 45; // Horizontal Half-Field of View (Degrees)
float vHalfFov = 45; // Vertical Half-Field of View (Degrees)
void IdleState() {
// Find all colliders within ViewRange
var hits = Physics.OverlapSphere(transform.position, ViewRange);
foreach (var hit in hits) {
if ( hit.gameObject == this.gameObject ) continue; // don't hit self
// Check FOV
var direction = (transform.position - hit.transform.position);
var hDirn = Vector3.ProjectOnPlane(direction, transform.up).normalized; // Project onto transform-relative XY plane to check hFov
var vDirn = Vector3.ProjectOnPlane(direction, transform.right).normalized; // Project onto transform-relative YZ plane to check vFov
var hOffset = Vector3.Dot(hDirn, transform.forward) * Mathf.Rad2Deg; // Calculate horizontal angular offset in Degrees
var vOffset = Vector3.Dot(vDirn, transform.forward) * Mathf.Rad2Deg; // Calculate vertical angular offset in Degrees
if (hOffset > hHalfFov || vOffset > vHalfFov) continue; // Outside of FOV
Debug.DrawLine(transform.position, hit.transform.position, Color.red);
if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Player")) {
FoundPlayer(hit.transform);
}
}
}

Unity2D Smooth Rotation using Slerp

I'm making a patrol script for a game object. I want the object to rotate smoothly and slowly to face it's patrol target.
Unfortunately, the object snaps to it's new location.
I've asked on unity forums and can't get an answer.
How can I get the rotation to be smooth and slow?
Here's my code.
public Transform[] patrol;
public int Currentpoint;
public float moveSpeed;
public Vector3 john = new Vector3(0,1,0);
public Vector3 targetLocation;
void Start()
{
}
void Update()
{
if (transform.position == patrol [Currentpoint].position) {
Currentpoint++;
if (Currentpoint >= patrol.Length) {
Currentpoint = 0;
}
targetLocation = patrol [Currentpoint].position;
Vector3 targetDir = targetLocation - transform.position;
float angle = Mathf.Atan2 (targetDir.y, targetDir.x) * Mathf.Rad2Deg;
transform.localRotation = Quaternion.SlerpUnclamped (transform.localRotation, Quaternion.AngleAxis (angle, Vector3.forward), Time.deltaTime * 3);
Debug.Log (Currentpoint);
}
transform.position = Vector3.MoveTowards (transform.position, patrol [Currentpoint].position, moveSpeed * Time.deltaTime);
}
public static Quaternion Slerp(Quaternion a, Quaternion b, float t); The parameter t is clamped to the range [0, 1]
your times 3 is throwing it out so it is not between 0-1 ... I believe
If you like some mathematics then I have a solution for you.
You want to rotate object around another, like Earth and Sun. May be some other solutions may available but I would do it through LookAt and parametric equation of circle.
x = r * cos(theta) + displacementX
y = r * sin(theta) + displacementY
where r is radius, distance in your case
displacementX and displacementY are the distance from origin. If both (displacementX and displacementY) is 0 then it will rotate around origin (0,0). In other words displacementX and displacementY is the origin of rotation.
In Object(Earth) script, do it as follow
public Transform _sun;
float _theta = 0;
void Start ()
{
StartCoroutine ("ChangeAngle");
}
void Update ()
{
transform.LookAt (_sun);
float newX = (5 * Mathf.Cos (_theta)) + _sun.position.x;
float newY = (5 * Mathf.Sin (_theta)) + _sun.position.y;
transform.position = new Vector3 (newX, newY, _sun.position.z);
}
IEnumerator ChangeAngle ()
{
while (true) {
yield return new WaitForSeconds (0.01f);
_theta += 0.1f;
if (_theta >= 360)
_theta = 0;
}
}
You can further play with it
I found an answer,
It turns out that placing the rotational instructions within the if statement was the problem. I converted the rotation to a function, then placed the function above the general patrol movement in the same loop segment.
I don't know why it worked.
Thanks to everyone for their help.

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.

Unity 2D Raycasting from a Rotating Transform

I'm trying to create a vision field in Unity 2d. I'm projecting raycasts from a rotating gameobject which rotates according to where the character is looking. However this character moves back and forth so when they are moving left I set the transform.scale to -1. The problem is when I do this the raycasts don't change direction along with the character and stay pointing right! Here is the code, I'm probably missing something obvious! Any help would be appreciated!
Transform parent;
float vision_angle_ = 50;
float direction;
Vector3 angle;
Vector2 position;
Quaternion q;
int x = 10;
void Start ()
{
parent = transform.parent;
}
void Update ()
{
direction = parent.GetComponent<Behaviour>().direction;
angle = new Vector2 (x, Mathf.Tan ((vision_angle_) * .5f * Mathf.Deg2Rad) * x);
q = Quaternion.AngleAxis (1, -transform.forward);
position = new Vector2 (transform.position.x, transform.position.y);
for (float i = 0; i < 50; i++) {
angle = q * angle;
RaycastHit2D tile_hit = Physics2D.Raycast (position, transform.TransformDirection (angle), 10);
Debug.DrawRay (position, transform.TransformDirection (angle), Color.green);
}
}
TransformDirection doesn't take the scale of your transform into account. You can adjust to compensate:
Vector2 direction = transform.TransformDirection(angle);
if (transform.localScale.x < 0f) {
direction.x = -direction.x;
}
RaycastHit2D tile_hit = Physics2D.Raycast(position, direction, 10);

Categories