I am using Unity3D to move the player around the circumference of a large circle facing inwards towards the centre at all times.
The following code works by using transform.forward
// Rotate the forward vector towards the target direction
Vector3 newDirection = Vector3.RotateTowards(transform.forward, targetDirection, singleStep, 0.0f);
and then I move the player sideways by using
characterController.Move(horizontalSpeed * transform.right * Time.deltaTime);
I have been stuck on how to get the player to move around the circumference but facing forward with the left of the player facing the centre of the circle.
My code is as follows
void Start()
{
characterController = GetComponent<CharacterController>();
}
void Update()
{
// Determine which direction to rotate towards
Vector3 targetDirection = GameObject.Find("Platforms").transform.position - transform.position;
// The step size is equal to speed times frame time.
float singleStep = 1 * Time.deltaTime;
// Rotate the forward vector towards the target direction by one step
Vector3 newDirection = Vector3.RotateTowards(transform.forward, targetDirection, singleStep, 0.0f);
// Draw a ray pointing at our target in
Debug.DrawRay(transform.position, newDirection*50, Color.red);
// Calculate a rotation a step closer to the target and applies rotation to this object
transform.rotation = Quaternion.LookRotation(newDirection);
CheckIfOnGround();
characterController.Move(velocity * Time.deltaTime);
}
Replace transform.forward to transform.left
Related
For a school assignment I am trying to make a tank point and shoot game, where I need align the tank to the plane normal using raycasting. But when I do this the Y axis rotaton gets locked and I can't rotate it any more.
The idea is that if a plane is angled, the tank is sticking to it and the transform.up is defined by the plane normal and the tank is able to go up and down the plane and also rotate on it.
This is the code.
public class PlayerController : MonoBehaviour
{
public GameObject player;
public float movementSpeed;
public float rotationSpeed;
RaycastHit hitinfo;
public float hoverHeight = 0.7f;
float offsetdistance;
//public Vector2 moveVal;
public Vector2 moveVal;
public Vector3 Dir;
public float moveSpeed;
//get OnMovie input and put it in a vector to be used later on
void OnMove(InputValue value)
{
moveVal = value.Get<Vector2>();
}
void Update()
{
//moves player
PlayerHover();
player.transform.Translate(new Vector3(0, 0, moveVal.y) * moveSpeed * Time.deltaTime);
player.transform.Rotate(0, moveVal.x * rotationSpeed * Time.deltaTime, 0, Space.Self);
}
void PlayerHover()
{
if (Physics.Raycast(transform.position, -Vector3.up, out hitinfo, 20f))
{
offsetdistance = hoverHeight - hitinfo.distance;
transform.up = hitinfo.normal;
transform.position = new Vector3(transform.position.x, transform.position.y + offsetdistance, transform.position.z);
}
}
You are probably using the wrong overload of transform.Rotate, you should probably be using:
public void Rotate(Vector3 axis, float angle, Space relativeTo = Space.Self);
Where the axis parameter should be the plane normal. Assuming you want to rotate around the plane normal
If you want to set the rotation directly you might need to use SetPositionAndRotation, you should be able to get the quaternion from LookDirection using the plane normal for the forward parameter, but you may need to play around with the axes or apply a 90-degree rotation to get the desired axis to point in the right direction.
In general if you want to rotate an object so that one axis matches up to some other axis you can:
Calculate the angle between the axes, i.e. compute the dot-product and apply the ACos function. Or use any built in methods.
Calculate an orthogonal vector by taking the cross-product between the two vectors
Use this axis and angle in the Rotate function above to produce the desired rotation. Or any other functions that produce a rotation that take an axis and angle.
Use the up-direction of your tank and the plane normal as input axes for the algorithm above if you want to rotate your tank to be orientated to the plane.
Im tried to make enemy face player by passing transform.LookAt(target) but with this i cannot achieve the parallel rotation to the ground.
I added a raycast downward for the enemy to find out the angle of the ground but im not sure how to add that rotation with the enemy looking at the player rotation together
void Groundangle()
{
Vector3 Current_Rotation = (target.position - transform.position).normalized;
RaycastHit Hit;
if (Physics.Raycast(EnemyEyes.position, EnemyEyes.TransformDirection(Vector3.down), out Hit, Mathf.Infinity, groundDetct))
{
float angle = Vector3.Angle(transform.TransformDirection(Vector3.down), Hit.normal) - 180f;
Debug.Log(angle);
Quaternion newrot = Quaternion.LookRotation(new Vector3(Current_Rotation.x, angle, Current_Rotation.z));
transform.rotation = Quaternion.Slerp(transform.rotation, newrot, Time.deltaTime);
}
}
This here works fine with the look at player part but i dont know how to implement ground rotation with the forward rotation.
You could try using
trasform.LookAt(target);
if (Physics.Raycast(EnemyEyes.position, -EnemyEyes.up, out var hit, Mathf.Infinity, groundDetct))
{
transform.up = hit.normal;
}
This will first rotate the object to face directly with it's forward vector towards the target and then rotate it again slightly to match the up vector according to the ground.
Or as alternative pretty similar you could take the direction
Vector3 Current_Rotation = (target.position - transform.position).normalized;
and in case of a ground hit map it onto the plane of the ground like
if (Physics.Raycast(EnemyEyes.position, -EnemyEyes.up, out var hit, Mathf.Infinity, groundDetct))
{
Current_Rotation = Vector3.ProjectOnPlane(Current_Rotation, hit.normal).normalized;
}
transform.rotation = Quaternion.LookRotation(Current_Rotation);
then you can still use Slerp
Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.
I am having a problem with the camera following the player. When the player moves, the camera shakes and this effect is more noticeable when the player is in the crouched position. I am using root motion for the player with animations by mixamo.
Player Script:
Transform cameraT;
void Start () {
cameraT = Camera.main.transform;
}
void FixedUpdate ()
{
float sideMotion = Input.GetAxis("SideMotion");
float straightMotion= Input.GetAxis("StraightMotion");
if (Mathf.Abs(sideMotion) > 0 || Mathf.Abs(straightMotion) > 0)
{
transform.eulerAngles = new Vector3(transform.eulerAngles.x,
cameraT.eulerAngles.y);
}
}
Camera Script:
public float distanceFromPlayer=2f;
public float mouseSensitivity=6;
public Transform player;
public Vector2 pitchConstraint= new Vector2(-30,80);
Vector3 rotationSmoothVelocity;
Vector3 currentRotation;
public float rotationSmoothTime = 0.2f;
float yaw; //Rotation around the vertical axis is called yaw
float pitch; //Rotation around the side-to-side axis is called pitch
private void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchConstraint.x, pitchConstraint.y);
currentRotation = Vector3.SmoothDamp
(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.eulerAngles = currentRotation;
transform.position = player.position - transform.forward * distanceFromPlayer;
}
For public transform I just added an empty game object to player chest level and parented it to the player. I got the rotating camera smoothly trick from an online tutorial but that exact thing won't work on player rotation though.
A character controller is attached to player without any rigidbody or collider.
You are going to want to use Lerp on the camera in order to smooth its motion from one position to another. The Scripting API has a good example of Vector3.Lerp.
So in your case, you could add a public variable for smoothing position as well. Something like positionSmoothTime. Then make a "Desired Position" variable, we'll call it destPosition.
Vector3 destPosition = player.position - transform.forward * distanceFromPlayer;
transform.position = Vector3.Lerp(transform.position, destPosition, positionSmoothTime);
This should effectively smooth it to where the stuttering should go away. Another thing that will help that someone else mentioned is using a part of the body that moves less (Like the head) as the target. This combined with the Lerp function will give you a smooth camera movement.
Another large help would be to move things into the Update() function. The reason being is FixedUpdate() doesn't get called every frame. So you could potentially get stutter as a result. If you move everything into Update() it will update every frame and help smooth things out. If you do this though you will need to multiply all movement by Time.deltaTime as shown in the example below.
Vector3 destPosition = (player.position - transform.forward * distanceFromPlayer) * Time.deltaTime;
For more examples, check the links to each function to see Unity's documentation on it. It has examples of everything I've shown here.
Im trying to get a sprite rotation by key input (arrow down or up).
The point is lifting the arrow (sprite) to choose the angle. Its like a system of a golf game, actually.
So far i tried:
void Update () {
if (Input.GetKey(KeyCode.UpArrow)){
transform.Rotate (Vector3.forward * -2); }
if (Input.GetKey(KeyCode.DownArrow)){
transform.Rotate (Vector3.forward * +2); }
}
I will need the angle, since it will be related to a "shot" part i will be doing next. My point is setting the right angle with the keys up and down.
I can move the "arrow" sprite with my code, but i cannot set the max angle (90), minimum (0) and get the angle to use in the shot ^^
Hard question to answer without just simply giving you the code. This code works by assuming your character's forward vector is actually it's right vector (common in 2d sprite games) in order to shoot in the other direction, rotate your objects y axis 180.
float minRotation = 0f;
float maxRotation = 90f;
float rotationSpeed = 40f; //degrees per second
//get current rotation, seeing as you're making a sprite game
// i'm assuming camera facing forward along positive z axis
Vector3 currentEuler = transform.rotation.eulerAngles;
float rotation = currentEuler.z;
//increment rotation via inputs
if (Input.GetKey(KeyCode.UpArrow)){
rotation += rotationSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow)){
rotation -= rotationSpeed * Time.deltaTime;
}
//clamp rotation to your min/max
rotation = Mathf.Clamp(rotation, minRotation, maxRotation );
//set rotation back onto transform
transform.rotation = Quaternion.Euler( new Vector3(currentEuler.x, currentEuler.y, rotation));
If you were making a golf game, you'd set the ball's velocity to be transform.right * shotPower