Moving the character controller to vector 3 position - c#

I'm currently making my Boss AI perform a jump attack against the player, the AI use both navmesh and character controller for movment (navmash only for pathfinding), but I'm having a hard time trying to move the AI to the designated position. here is my code:
CharacterController chara;
[SerializeField]
Transform playerTran;
[SerializeField]
float gravity = 3.8f;
[SerializeField]
float jumpForce = 50F;
Vector3 moveVector = Vector3.zero;
[SerializeField]
Transform jumpCheck;
[SerializeField]
Transform jumpPos;
// Use this for initialization
void Start ()
{
chara = GetComponent<CharacterController>();
playerTran = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
// Update is called once per frame
void Update ()
{
chara.Move(moveVector);
if (chara.isGrounded)
{
transform.LookAt(playerTran);
}
moveVector -= Vector3.up * gravity * Time.deltaTime;
if (Input.GetKeyUp(KeyCode.J))
{
jumpCheck.position = new Vector3(playerTran.position.x, 0, playerTran.position.z);
float angle = findAngle( playerTran.position.x - transform.position.x , playerTran.position.z - transform.position.z);
Vector3 _toJumpPos = MakeJumpCricle(playerTran.position , jumpCheck.localScale.x/2, angle);
jumpPos.position = new Vector3(_toJumpPos.x, 0, _toJumpPos.z);
moveVector = Vector3.up * jumpForce * Time.deltaTime;
}
}
float findAngle(float x, float y)
{
float value;
value = (float)((Mathf.Atan2(x, y) / Mathf.PI) * 180);
if (value < 0)
{
value += 360;
}
Debug.Log(value);
return value;
}
Vector3 MakeJumpCricle( Vector3 center, float radius, float angle)
{
Vector3 pos = Vector3.zero;
pos.x = center.x - radius * Mathf.Sin(angle * Mathf.Deg2Rad);
pos.y = 0;
pos.z = center.z - radius * Mathf.Cos(angle * Mathf.Deg2Rad);
return pos;
}
I want to move the AI to the jumpPos with both forward and up vectors but I'm not sure to do this.
visualization of the code

code visualization
I found a good solution, I used a Bezier Curves to generate a path
posting it here so other might find it helpful.
refrence link
http://www.theappguruz.com/blog/bezier-curve-in-games
public LineRenderer jumpLine;
private int numberOfPoint = 50;
[SerializeField]
List<Vector3> pointPositions = new List<Vector3>();
CharacterController chara;
[SerializeField]
Transform playerTran;
[SerializeField]
float gravity = 3.8f;
[SerializeField]
float jumpForce = 50F;
Vector3 moveVector = Vector3.zero;
[SerializeField]
Transform jumpCheck;
[SerializeField]
Transform jumpPos;
[SerializeField]
Transform jumpHightOne;
bool movejump;
Vector3 pZero;
Vector3 pOne;
float time;
// Use this for initialization
void Start ()
{
chara = GetComponent<CharacterController>();
playerTran = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
jumpLine.positionCount = numberOfPoint;
jumpLine.gameObject.SetActive(false);
}
// Update is called once per frame
void Update ()
{
chara.Move(moveVector);
if (chara.isGrounded)
{
transform.LookAt(playerTran);
}
moveVector -= Vector3.up * gravity * Time.deltaTime;
if (Input.GetKeyUp(KeyCode.J))
{
jumpCheck.position = new Vector3(playerTran.position.x, 0, playerTran.position.z);
float angle = findAngle( playerTran.position.x - transform.position.x , playerTran.position.z - transform.position.z);
Vector3 _toJumpPos = MakeJumpCricle(playerTran.position , jumpCheck.localScale.x/2, angle);
Vector3 middlePoint = GetTheMiddlePoints(transform.position, playerTran.position, 0.5f);
jumpHightOne.position = new Vector3(middlePoint.x, jumpHightOne.position.y, middlePoint.z);
jumpPos.position = new Vector3(_toJumpPos.x, 0, _toJumpPos.z);
//moveVector = Vector3.up * jumpForce * Time.deltaTime;
//movejump = true;
DrawLinerBezierCurves();
}
if (movejump)
{
//MoveTowardsTarget(jumpPos.position);
}
}
Vector3 GetTheMiddlePoints(Vector3 origin, Vector3 destination, float middlepointfactor)
{
return (destination - origin) * middlepointfactor + origin;
// (destination - origin) * 0.5f;
}
float findAngle(float x, float y)
{
float value;
value = (float)((Mathf.Atan2(x, y) / Mathf.PI) * 180);
if (value < 0)
{
value += 360;
}
//Debug.Log(value);
return value;
}
Vector3 MakeJumpCricle( Vector3 center, float radius, float angle)
{
Vector3 pos = Vector3.zero;
pos.x = center.x - radius * Mathf.Sin(angle * Mathf.Deg2Rad);
pos.y = 0;
pos.z = center.z - radius * Mathf.Cos(angle * Mathf.Deg2Rad);
return pos;
}
void MoveTowardsTarget(Vector3 targetPostios)
{
var offset = targetPostios - transform.position;
if (offset.magnitude > .1f)
{
offset = offset.normalized * 15;
chara.Move(offset * Time.deltaTime);
}
else
{
movejump = false;
}
}
// line Bezier Curves
Vector3 CalculateBezierCurvesPoints(float t , Vector3 p0, Vector3 p1 )
{
return p0 + t * (p1 - p0);
// P = P0 + t(P1 – P0) , 0 < t < 1
}
// line Bezier Curves
Vector3 CalculateBezierCurvesPoints(float t, Vector3 p0, Vector3 p1, Vector3 p2)
{
float u = 1 - t;
float uu = u * u;
float tt = t * t;
Vector3 p = uu * p0;
p = p + 2 * u * t * p1;
p = p + tt * p2;
return p;
//P = (1-t)^2 P0 + 2 (1-t) t P1 + t^2 P2 , 0 < t < 1
// uu u tt
// uu * p0 + 2 * u * t * p1 + tt * p2
}
void DrawLinerBezierCurves()
{
if (pointPositions.Count > 0)
{
pointPositions.Clear();
jumpLine.positionCount = 0;
jumpLine.positionCount = numberOfPoint;
}
for (int i = 1; i < numberOfPoint + 1; i++)
{
float t = i / (float) numberOfPoint;
if (!jumpLine.gameObject.activeInHierarchy)
{
jumpLine.gameObject.SetActive(true);
}
pointPositions.Add(CalculateBezierCurvesPoints(t, transform.position,jumpHightOne.position, jumpPos.position));
jumpLine.SetPosition(i - 1, pointPositions[i - 1]);
}
}

Related

Converting Calculating To Movement Overtime?

I am moving an object in a parabolic arc this way:
public IEnumerator ParabolicMovement()
{
Vector3 startPos;
Vector3 targetPos;
float speed = 6;
float arcHeight = 3;
Vector3 nextPos = Vector3.zero;
while (transform.position != targetPos)
{
// Compute the next position, with arc added in
float x0 = startPos.x;
float x1 = targetPos.x;
float dist = x1 - x0;
float nextX = Mathf.MoveTowards(transform.position.x, x1, (speed) * Time.deltaTime);
float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
transform.position = nextPos;
yield return null;
}
}
This works, but I now want to take this and make it happen over a specific amount of time. I removed the loop from the original method and broke it up into two separate methods to accomplish this:
public IEnumerator BeginJumpOverTime()
{
float duration = 1f;
float startTime = Time.time;
float endTime = startTime + duration;
while (Time.time <= endTime)
{
float tNormalized = Mathf.Clamp((Time.time - startTime) / duration, 0f, 1f);
Vector2 newXAndY = CalculateXAndY(tNormalized);
transform.position = newXAndY;
yield return null;
}
}
public Vector2 CalculateXAndY(float t)
{
Vector3 startPos = GameEngine.Instance.battleManager.TurnHero.transform.position;
Vector3 targetPos = GameEngine.Instance.battleManager.TargetEnemy.transform.position;
float speed = 6;
float arcHeight = 3;
Vector3 nextPos = Vector3.zero;
// Compute the next position to make the parabola
float x0 = startPos.x;
float x1 = targetPos.x;
float dist = x1 - x0;
float nextX = Mathf.MoveTowards(transform.position.x, x1, (speed) * (Time.deltaTime) );
float baseY = Mathf.Lerp(startPos.y, targetPos.y, (nextX - x0) / dist);
float arc = arcHeight * (nextX - x0) * (nextX - x1) / (-0.25f * dist * dist);
nextPos = new Vector3(nextX, baseY + arc, transform.position.z);
return (nextPos);
}
I'm pretty certain this concept should work, I just can't seem to figure out where to factor tNormalized when it's passed into CalculateXandY(). Is anyone math savvy able to assist me with this? Thanks a ton!
Kind regards,

I don't want to let an object go out of the fan-shaped area

enter image description here
Like the attached image,
I don't want the red circle following the green mouse position to go out of the fan-shaped area.
So I wrote the code as below.
However, it is not working properly.
What's the problem?
float GetDegree(Vector3 start, Vector3 end)
{
var dx = end.x - start.x;
var dz = end.z - start.z;
var degree = Mathf.Atan2(dx, dz) * Mathf.Rad2Deg;
return degree;
}
void update()
{
float range = 5;
float centerAngle = 30;
Vector3 centerPosition = new vector3 (0, 0, 0);
Vector3 mousePosition = Input.mousePosition
float R = Vector3.Distance(centerPosition, mousePosition);
float T = GetDegree(centerPosition, mousePosition);
float tmin = Mathf.Abs(90f - (centerAngle) * 0.5f) * (T >= 0 ? 1F : -1F);
float tmax = (T >= 0 ? centerAngle : -centerAngle) + tmin;
float r = range;
float R1 = Mathf.Min(R, r);
float T1 = Mathf.Clamp(T, tmin, tmax);
float rcost = R1 * Mathf.Cos(T1);
float rsint = R1 * Mathf.Sin(T1);
Vector3 result = new vector3 (rcost, 0f, rsint);
}

Find an angle and velocity to launch the projectile with to reach a specific point

I am trying to make a cannon that shoots a target located in a 3D world in Unity... I hava a LaunchConfig enum ->
public enum LauncherConfig
{
CalculateNone = 0,
CalculateAngle = 1,
CalculateVelocity = 2,
CalculateBoth = 3
}
When CalculateAngle is selected the user can input the Initial Velocity for the projectile and the angle the projectile needs to be launched at to reach the target has to be calculated.
Same for CalculateVelocity.
CalculateNone allows the user to input both the values and CalculateBoth calculates both the values.
What equations do I use to calculate the values so that they line up, i.e. when CalculateAngle is selected the velocity calculated should be such that the projectile looks natural coming out of the barrel. Same for CalculateBoth, the angle should be calculated so that the velocity calculated will launch the projectile strait out the barrel and not any other direction.
I have my current location (Vector3), target location (Vector3).
The calculated angle will affect the x-rotation of the cannon.
The y-rotation is lined up with the target already so that it faces the target;
Here is the code for the class
using System;
using UnityEngine;
public class Launcher : MonoBehaviour
{
[SerializeField] private LauncherSettings settings = default;
[SerializeField] private Transform target = default;
private Transform partToRotateY;
private Transform partToRotateX;
private Transform projectileSpawnPosition;
private float x;
private float y;
private Vector3 velocity;
private void Awake()
{
partToRotateX = transform.GetChild(0);
partToRotateY = transform.GetChild(1);
projectileSpawnPosition = partToRotateX.GetChild(0);
settings.inputController = new InputActions.Launcher();
settings.inputController.Automatic.Launch.performed += _ => Shoot();
}
private void Update()
{
CalculateVelocity();
CalculateAngle();
LookAtTarget();
Shoot();
}
private void OnEnable()
{
settings.inputController.Enable();
}
private void OnDisable()
{
settings.inputController.Disable();
}
private void LookAtTarget()
{
Vector3 direction = target.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(direction);
y = lookRotation.eulerAngles.y;
Quaternion rotationY = Quaternion.Euler(0f, y, 0f);
Quaternion rotationX = Quaternion.Euler(-x, y, 0f);
partToRotateY.rotation = Quaternion.Slerp(partToRotateY.rotation, rotationY, Time.deltaTime * settings.rotationSpeed);
partToRotateX.rotation = Quaternion.Slerp(partToRotateX.rotation, rotationX, Time.deltaTime * settings.rotationSpeed);
}
private float nextTimeToFire = 0f;
private void Shoot()
{
nextTimeToFire -= Time.deltaTime;
if (!(nextTimeToFire <= 0f)) return;
nextTimeToFire = 1 / settings.fireRate;
var rb = Instantiate(settings.projectilePrefab, projectileSpawnPosition.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.velocity = velocity;
}
private void CalculateAngle()
{
if (settings.launcherConfig == LauncherConfig.CalculateVelocity ||
settings.launcherConfig == LauncherConfig.CalculateNone)
{
x = Mathf.Clamp(settings.launchAngle, -20f, 80f);
}
else
{
var position = target.position;
var position1 = transform.position;
var dist = Math.Sqrt(Mathf.Pow((position.x - position1.x), 2) + Mathf.Pow((position.y - position1.y), 2));
var a = Physics.gravity.y * Mathf.Pow((float) dist, 2) / (2 * Mathf.Pow(velocity.magnitude, 2));
var b = (float) -dist;
var c = position.z - position1.z + a;
x = (float) Math.Atan2(QuadraticRoot(a, b, c), 1);
Debug.Log(x);
}
}
private void CalculateVelocity()
{
if (settings.launcherConfig == LauncherConfig.CalculateAngle ||
settings.launcherConfig == LauncherConfig.CalculateNone)
{
velocity = partToRotateX.forward * settings.velocity;
}
else
{
float h;
if (settings.launcherConfig == LauncherConfig.CalculateBoth && settings.calculateMaxHeight)
{
h = Mathf.Abs(target.position.y - partToRotateX.position.y * settings.maxHeightMultiplier);
}
else
{
h = settings.maxHeight;
}
var position = partToRotateX.position;
var position1 = target.position;
var gravity = Physics.gravity.y;
var displacementY = position1.y - position.y;
var displacementXZ = new Vector3 (position1.x - position.x, 0, position1.z - position.z);
var time = Mathf.Sqrt(-2*h/gravity) + Mathf.Sqrt(2*(displacementY - h)/gravity);
var velocityY = Vector3.up * Mathf.Sqrt (-2 * gravity * h);
var velocityXZ = displacementXZ / time;
velocity = velocityXZ + velocityY * -Mathf.Sign(gravity);
}
}
private double QuadraticRoot(double a, double b, double c){
double D = Math.Pow(b, 2) - (4 * a * c);
return (-b + Math.Sqrt(D)) / (2 * a);
}
}
The LauncherSettings Class...
using Attributes.DrawIf;
using Attributes.DrawIfAndOr;
using UnityEngine;
[CreateAssetMenu]
public class LauncherSettings : ScriptableObject
{
public InputActions.Launcher inputController;
public LauncherConfig launcherConfig = LauncherConfig.CalculateVelocity;
public GameObject projectilePrefab = default;
public float rotationSpeed = 5f;
public float fireRate = 5f;
[DrawIfAndOr(nameof(launcherConfig), LauncherConfig.CalculateAngle, LauncherConfig.CalculateNone)]
public float velocity = 200f;
[DrawIfAndOr(nameof(launcherConfig), LauncherConfig.CalculateVelocity, LauncherConfig.CalculateNone)]
public float launchAngle = 0f;
[DrawIf(nameof(launcherConfig), LauncherConfig.CalculateBoth)]
public bool calculateMaxHeight = true;
[DrawIf(nameof(calculateMaxHeight), false)]
public float maxHeight;
[DrawIf(nameof(calculateMaxHeight), true)]
public float maxHeightMultiplier = 5f;
}
The DrawIf and DrawIfAndOr are attributes that hide the vaule in inspector if the first paramerter is equal to the other. You can completely ignore them. The calculation of Velocity is by
Sebastian Lague (https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ) in his Kinematic Equations (E03: ball problem) (https://youtu.be/IvT8hjy6q4o). The calculation of the angle is from an answer on my other question (Find an angle to launch the projectile at to reach a specific point).
Any help is appreciated...
Thanks...

Touch to Zoom And Rotate script for Unity player

I had this unity player embedded in android studio activity.
It is a 3d model with animation, which I would like viewer to be able to zoom and view in different angle.
Script are from this link
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MobilemaxCamera : MonoBehaviour {
public Transform target;
public Vector3 targetOffset;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public float xSpeed = 5.0f;
public float ySpeed = 5.0f;
public int yMinLimit = -80;
public int yMaxLimit = 80;
public float zoomRate = 10.0f;
public float panSpeed = 0.3f;
public float zoomDampening = 5.0f;
private float xDeg = 0.0f;
private float yDeg = 0.0f;
private float currentDistance;
private float desiredDistance;
private Quaternion currentRotation;
private Quaternion desiredRotation;
private Quaternion rotation;
private Vector3 position;
private Vector3 FirstPosition;
private Vector3 SecondPosition;
private Vector3 delta;
private Vector3 lastOffset;
private Vector3 lastOffsettemp;
//private Vector3 CameraPosition;
//private Vector3 Targetposition;
//private Vector3 MoveDistance;
void Start() { Init(); }
void OnEnable() { Init(); }
public void Init()
{
//If there is no target, create a temporary target at 'distance' from the cameras current viewpoint
if (!target)
{
GameObject go = new GameObject("Cam Target");
go.transform.position = transform.position + (transform.forward * distance);
target = go.transform;
}
distance = Vector3.Distance(transform.position, target.position);
currentDistance = distance;
desiredDistance = distance;
//be sure to grab the current rotations as starting points.
position = transform.position;
rotation = transform.rotation;
currentRotation = transform.rotation;
desiredRotation = transform.rotation;
xDeg = Vector3.Angle(Vector3.right, transform.right);
yDeg = Vector3.Angle(Vector3.up, transform.up);
}
/*
* Camera logic on LateUpdate to only update after all character movement logic has been handled.
*/
void LateUpdate()
{
// If Control and Alt and Middle button? ZOOM!
if (Input.touchCount==2)
{
Touch touchZero = Input.GetTouch (0);
Touch touchOne = Input.GetTouch (1);
Vector2 touchZeroPreviousPosition = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePreviousPosition = touchOne.position - touchOne.deltaPosition;
float prevTouchDeltaMag = (touchZeroPreviousPosition - touchOnePreviousPosition).magnitude;
float TouchDeltaMag = (touchZero.position - touchOne.position).magnitude;
float deltaMagDiff = prevTouchDeltaMag - TouchDeltaMag;
desiredDistance += deltaMagDiff * Time.deltaTime * zoomRate * 0.0025f * Mathf.Abs(desiredDistance);
}
// If middle mouse and left alt are selected? ORBIT
if (Input.touchCount==1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchposition = Input.GetTouch(0).deltaPosition;
xDeg += touchposition.x * xSpeed * 0.002f;
yDeg -= touchposition.y * ySpeed * 0.002f;
yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);
}
desiredRotation = Quaternion.Euler(yDeg, xDeg, 0);
currentRotation = transform.rotation;
rotation = Quaternion.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomDampening);
transform.rotation = rotation;
if (Input.GetMouseButtonDown (1))
{
FirstPosition = Input.mousePosition;
lastOffset = targetOffset;
}
if (Input.GetMouseButton (1))
{
SecondPosition = Input.mousePosition;
delta = SecondPosition - FirstPosition;
targetOffset = lastOffset + transform.right * delta.x*0.003f + transform.up * delta.y*0.003f;
}
////////Orbit Position
// affect the desired Zoom distance if we roll the scrollwheel
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
currentDistance = Mathf.Lerp(currentDistance, desiredDistance, Time.deltaTime * zoomDampening);
position = target.position - (rotation * Vector3.forward * currentDistance );
position = position - targetOffset;
transform.position = position;
}
private static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
The zoom in and out work perfectly.
But the problem is, the rotate/pan is totally not working.
Anyone can give some help in this?
For the multi-touch, you have to use this script which I have given below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultiTouch: MonoBehaviour
{
float initialFingersDistance;
Vector3 initialScale;
float rotationRate = 0.2f;
int direction = 1;
void LateUpdate()
{
if (Input.touches.Length == 1)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.touches[0];
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = transform.eulerAngles;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
// transform.Rotate(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, 0, Space.World);
Vector3 rot = new Vector3(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, transform.eulerAngles.z* rotationRate);
// transform.rotation = Quaternion.EulerAngles(rot);
}
}
else if (Input.touches.Length == 2)
{
Touch t1 = Input.touches[0];
Touch t2 = Input.touches[1];
if (t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began)
{
initialFingersDistance = Vector2.Distance(t1.position, t2.position);
initialScale = gameObject.transform.localScale;
}
else if (t1.phase == TouchPhase.Moved || t2.phase == TouchPhase.Moved)
{
var currentFingersDistance = Vector2.Distance(t1.position, t2.position);
// Debug.Log(currentFingersDistance);
////if (currentFingersDistance != initialFingersDistance)
//{
var scaleFactor = currentFingersDistance / initialFingersDistance;
gameObject.transform.localScale = initialScale * scaleFactor;
//}
float Dx = t1.position.x - transform.position.x;
float Dy = t1.position.y - transform.position.y;
//var cameraTransform = Camera.main.transform.InverseTransformPoint(0, 0, 0);
//transform.position = Camera.main.ScreenToWorldPoint(new Vector3(t2.position.x, t2.position.y, cameraTransform.z -0.5f));
Vector3 pos = t2.position;
//Vector3 pos = t1.position - t2.position;
Vector3 touchedPos = Camera.main.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 10));
transform.position = Vector3.Lerp(transform.position, touchedPos, Time.deltaTime * 4);
// transform.position += touchedPos;
float pinchAmount = 0;
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.pinchDistanceDelta) > 0)
{ // zoom
pinchAmount = TouchLogic.pinchDistanceDelta;
}
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = Vector3.zero;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
transform.position += Vector3.forward * pinchAmount;
}
}
}
}
For your touch control logic, you have to use this second script which I gave below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TouchLogic: MonoBehaviour
{
const float pinchTurnRatio = Mathf.PI / 2;
const float minTurnAngle = 0;
const float pinchRatio = 1;
const float minPinchDistance = 0;
const float panRatio = 1;
const float minPanDistance = 0;
/// <summary>
/// The delta of the angle between two touch points
/// </summary>
static public float turnAngleDelta;
/// <summary>
/// The angle between two touch points
/// </summary>
static public float turnAngle;
/// <summary>
/// The delta of the distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistanceDelta;
/// <summary>
/// The distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistance;
/// <summary>
/// Calculates Pinch and Turn - This should be used inside LateUpdate
/// </summary>
///
static public Touch LastTouch;
static public void Calculate()
{
pinchDistance = pinchDistanceDelta = 0;
turnAngle = turnAngleDelta = 0;
// if two fingers are touching the screen at the same time ...
if (Input.touchCount == 1)
{
Touch touch1 = Input.touches[0];
turnAngle = Angle(touch1.position, LastTouch.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
LastTouch.deltaPosition + LastTouch.position);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
LastTouch =Input.touches[0];
}
else if (Input.touchCount == 2)
{
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
// ... if at least one of them moved ...
if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
// ... check the delta distance between them ...
pinchDistance = Vector2.Distance(touch1.position, touch2.position);
float prevDistance = Vector2.Distance(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
pinchDistanceDelta = pinchDistance - prevDistance;
// ... if it's greater than a minimum threshold, it's a pinch!
if (Mathf.Abs(pinchDistanceDelta) > minPinchDistance)
{
pinchDistanceDelta *= pinchRatio;
}
else
{
pinchDistance = pinchDistanceDelta = 0;
}
// ... or check the delta angle between them ...
turnAngle = Angle(touch1.position, touch2.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
touch2.position + touch2.deltaPosition);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
}
}
}
static private float Angle(Vector2 pos1, Vector2 pos2)
{
Vector2 from = pos2 - pos1;
Vector2 to = new Vector2(1, 0);
float result = Vector2.Angle(from, to);
Vector3 cross = Vector3.Cross(from, to);
if (cross.z > 0)
{
result = 360f - result;
}
return result;
}
}
Both scripts are used in a single project. using these scripts you can easily rotate your 3d object.
Note: Please attach this both script in a single 3d object, so you can use this script easily.

How to Limit (clamp) Y axis Rotation for transform.rotatearound Unity

I have a camera that I want to rotate around a point (0,0,0) in all directions, but I want to put a clamp on it so that it can't go too far above or below the point. I have seen this question answered for the left and right directions before but never for the vertical one.
I have tried converting the code from these two questions (that basically say the same thing) to work in the vertical direction, but it bugs out at some points along the rotation, and I can't figure out why.
First Question, Second Question
And this is how I tried to convert it:
//how much we want to rotate by this frame
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed; //(before clamping)
//find current direction
Vector3 currentDirection = transform.position - Vector3.zero;
//find current angle between basis for clamp & where we are now
float angle = Vector3.Angle(Vector3.forward, currentDirection);
//finds out if it's up or down
if (Vector3.Cross(Vector3.forward, currentDirection).x < 0) angle = -angle;
//find out how much you can move without violating limits
float newAngle = Mathf.Clamp(angle + rotY, yMinLimit, yMaxLimit);
//grabs how much you are allowed to move the angle from the current angle
rotY = newAngle - angle;
//spinning the garden
transform.RotateAround(Vector3.zero, Vector3.up, rotX);
transform.RotateAround(Vector3.zero, transform.TransformDirection(Vector3.right), -rotY); //vertical rotation
If anyone knows of the correct way to make this work for the Y axis, or a different way to clamp the vertical rotation, I would be super excited to hear it! Ty!
I have a class here that do exactly what you want. It rotates a camera around a target and clamps the Y rotation. It uses the left button to rotate and the scroll press button to translate the target.
You can edit it to adjust to your specific needs - you might want to change the target to a Vector3 so you can set it to (0,0,0) without the need of an object. Hope it helps.
using UnityEngine;
public class RotateAroundCamera : MonoBehaviour
{
Camera cam;
public bool isControlable;
private Vector3 screenPoint;
private Vector3 offset;
public Transform target;
public float distance = 5.0f;
public float xSpeed = 50.0f;
public float ySpeed = 50.0f;
public float yMinLimit = -80f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
public float smoothTime = 2f;
public float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
float moveDirection = -1;
public void SetControllable(bool value)
{
isControlable = value;
}
// Use this for initialization
void Start()
{
cam = GetComponentInChildren<Camera>();
Vector3 angles = transform.eulerAngles;
rotationYAxis = (rotationYAxis == 0) ? angles.y : rotationYAxis;
rotationXAxis = angles.x;
Rigidbody rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
if (Input.GetMouseButton(1) && isControlable)
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
if (Input.GetMouseButton(2) && isControlable)
{
Vector3 curScreenPoint = new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = cam.ScreenToWorldPoint(curScreenPoint) + offset;
target.transform.position = curPosition;
}
if (Input.GetKeyDown(KeyCode.R) && isControlable)
{
target.transform.position = Vector3.zero;
}
if (Input.GetKeyDown(KeyCode.T) && isControlable)
{
moveDirection *= -1;
}
if (isControlable)
{
distance -= Input.GetAxis("Mouse ScrollWheel");
if (distance > distanceMax)
{
distance = distanceMax;
}
else if (distance < distanceMin)
{
distance = distanceMin;
}
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Quaternion rotation = toRotation;
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);
screenPoint = cam.WorldToScreenPoint(target.transform.position);
offset = target.transform.position - cam.ScreenToWorldPoint(new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z));
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}
}

Categories