i am trying to rotate its x and z axis to the mouse position while not changing the y. for some reason the y keeps changing!!!
my current code looks like this
public float moveSpeed = 5;
public float maxMoveSpeed = 15;
CharacterController body;
// Start is called before the first frame update
void Start()
{
body = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Vector3 point = new Vector3(hit.point.x, 0, hit.point.z);
print(point);
transform.LookAt(point);
}
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 moveDis = transform.forward * v * moveSpeed;
moveDis += transform.right * h * moveSpeed;
body.SimpleMove(moveDis);
}
for some reason if i remove the player controller it works fine!
i am trying to rotate its x and z axis
No you are not ^^
What you are doing is
Vector3 point = new Vector3(hit.point.x, 0, hit.point.z);
transform.LookAt(point);
where LookAt
Rotates the transform so the forward vector points at /target/'s current position.
which in most cases will rotate your object around the X and Y axis!
It is unclear what your actual goal would be in order to provide a possible solution to that, though.
Related
How to limit my ai movement to move only on the z axis. Ive already tried freezing the rotation and position on it's rigidbody but instead when i jump my ai also goes up with me on it's position and slightly rotates towards me.
private void Update()
{
StopFollowing();
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos);
Quaternion current = transform.localRotation;
transform.localRotation = Quaternion.Slerp(current, rotation, Time.deltaTime
* LookSpeed);
}
// Update is called once per frame
void followPlayer()
{
Vector3 pos = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
rig.MovePosition(pos);
;
}
Freezing the rigidbody will only affect physics (using AddForce or rb.velocity)
You are using MoveTowards (basically teleporting it ignoring physics)
But you can limit it to Z-Axis manually:
void followPlayer()
{
Vector3 targetPos = target.position; // copy target Position
targetPos.x = transform.position.x; // keep x
targetPos.y = transform.position.y; // keep y
Vector3 pos = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime); // now only considers z-difference
rig.MovePosition(pos);
}
You basically modify the target Position to be equal on the x and y axis, so that the MoveTowards only uses Z effectively.
What I am trying to do is have a pillar in the center of a scene, and what i think is happening is the quaternion.RotateTowards is receiving a different starting/initial quaternion than the action which is causing it to snap/teleport into a different location which then starts to move to the next. I thought it may be because i'm misunderstanding how quaternions are handled in unity, so i've tried messing with normalizing it, but i can't seem to get any change on the teleport.
The goal is to attach this scrip to a simple 3D cylinder and have it wobble basically, where there will be a player on top of it trying to stay on it. However I can't seem to figure out why it is teleporting and was hoping for a second set of eyes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlatformWobble : MonoBehaviour
{
public float timeDelay = 0;
public float rRange = 0.5f;
public float maxRotation = 20.0f;
public float rotRate = 0.05f;
private bool wobble = false;
private Vector3 randomRotation;
private Quaternion rotation;
private Quaternion destination;
private float x, y, z;
private bool inPlace;
private void Start()
{
randomRotation = new Vector3();
inPlace = true;
}
// Update is called once per frame
void FixedUpdate()
{
if (inPlace)
{
destination = RotateRandomly();
inPlace = false;
}
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, destination, rotRate * Time.deltaTime);
if (transform.localRotation == destination)
{
inPlace = true;
}
}
//This will grab the rotation of the object and move it randomly, but won't exceed maxRotation;
Quaternion RotateRandomly()
{
randomRotation = new Vector3(Random.Range(-rRange, rRange), Random.Range(-rRange, rRange), Random.Range(-rRange, rRange));
rotation = transform.localRotation;
x = rotation.x + randomRotation.x;
if(x >= maxRotation && x <= 360 - maxRotation) { x = rotation.x; }
y = rotation.y + randomRotation.y;
if (y >= maxRotation && y <= 360 - maxRotation) { y = rotation.y; }
z = rotation.z + randomRotation.z;
if (z >= maxRotation && z <= 360-maxRotation) { z = rotation.z; }
return new Quaternion(x, y, z, transform.localRotation.w);
}
}
Your quaternion calculations are incorrect: quaternions do not hold angles, instead, they hold the representation of a rotation about an axis. I emphasized "representation" because it is a little complicated...
The x, y, z components of a quaternion hold the rotation axis unit vector scaled by the sine of the half angle of rotation. The w component holds the cosine of the half angle. That is...
// NOTE: rotationAngle is in radians rather than degrees
Quaternion MakeQuaternion (Vector3 rotationAxis, float rotationAngle)
{
float c = Mathf.Cos (rotationAngle / 2);
float s = Mathf.Sin (rotationAngle / 2);
Vector3 v = rotationAxis.normalized * s;
return new Quaternion (v.x, v.y, v.z, c);
}
Now, the tricky part for your problem is coming up with the rotation axis and angle for the desired effect.
One solution (if you wish to stick to Euler angles) is to compute quaternions for each Euler rotation and then combine them:
Quaternion EulerToQuat (float XAngle, float YAngle, float ZAngle)
{
Quaternion X = MakeQuaternion (Vector3.right, XAngle);
Quaternion Y = MakeQuaternion (Vector3.up, YAngle);
Quaternion Z = MakeQuaternion (Vector3.forward, ZAngle);
// combine the rotations such that the object is first rotated about the Z axis,
// then about the Y axis, then the X (ie, reverse order of multiplication).
// Reminder: quaternion multiplicate is not commutative: order matters, so if this
// is not the order you want, just siwtch things around
rotate X * Y * Z;
}
FixedUpdate doesn't get called every render frame, only on physics frames. You need a way to tell Unity to have each frame showing the rotation change, rather than only updating the rendering when the physics frame has just run.
That is what Rigidbody.MoveRotation is for. Cache a reference to the Rigidbody, calculate the new global rotation it should have, then call MoveRotation:
private Rigidbody rb;
private void Start()
{
randomRotation = new Vector3();
inPlace = true;
rb = GetComponent<Rigidbody>();
}
// ...
// Update is called once per frame
void FixedUpdate()
{
if (inPlace)
{
destination = RotateRandomly();
inPlace = false;
}
Quaternion newLocalRot = Quaternion.RotateTowards(transform.localRotation,
destination, rotRate * Time.deltaTime);
Quaternion newGlobalRot = transform.parent.rotation * newLocalRot;
rb.MoveRotation(newGlobalRot);
if (transform.localRotation == destination)
{
inPlace = true;
}
}
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
I am making a top down game on Unity, so I am using the x and z axis as my plane. I have my character rotated x 90, y 0, z 0 so that it is flat on the plane. As soon as I hit play the character is rotated vertical?! I think it has something to do with my script to face the mouse position.
What it should look like:
When I hit play:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public static float moveSpeed = 10f;
private Rigidbody rb;
private Vector3 moveInput;
private Vector3 moveVelocity;
// Update is called once per frame
void Start()
{
rb = GetComponent<Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
void Update()
{
// Setting up movement along x and z axis. (Top Down Shooter)
moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
moveVelocity = moveInput * moveSpeed;
//Make character look at mouse.
var dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
}
void FixedUpdate()
{
// Allows character to move.
rb.velocity = moveVelocity;
}
}
Figured it out: I am answering my own question to help others.
Vector3 difference = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(90f, 0f, rotZ -90);
This does EXACTLY what I wanted!
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);