Unity Rotate ball left or right insted of roll - c#

I'm trying to learn Unity3D and I'm using this tutorial to get started.
In my PlayerController below the "ball" rolls in the direction of the arrow key pressing. But my question is: When I press left or right arrow I don't want it to move in the direction but to turn in the direction.
So the ball moves forward/backward on arrow key up/down and rotate left/right on arrow key left/right.
public class PlayerController : MonoBehaviour {
public float speed;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody> ();
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
}
I've searched on google but haven't been able to find a solution.
UPDATE
Here is my camera controller.
public class CameraController : MonoBehaviour {
public GameObject player;
private Vector3 offset;
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
}
// Update is called once per frame
void LateUpdate () {
transform.position = player.transform.position + offset;
}
}

float delta = Input.GetAxis("Horizontal");
Vector3 axis = Vector3.forward;
rb.AddTorque (axis * speed * delta);
or
transform.Rotate (axis * speed * delta);

Instead of:
rb.AddForce (movement * speed);
you can use:
rb.AddTorque (movement * speed);
This will add angular force to the ball.

Related

How to add relative movement to multiple virtual cameras?

I am using a Cinemachine state driver to transition between my 8 directional cameras orbiting my player. Right now my player script is set to a basic isometric character controller:
Player.cs
public float speed = 5f;
Vector3 forward;
Vector3 right;
// Start is called before the first frame update
void Start()
{
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
// Update is called once per frame
void Update()
{
if (Input.anyKey)
{
Move();
}
}
void Move ()
{
Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 rightMovement = right * speed * Time.deltaTime * Input.GetAxis("Horizontal");
Vector3 upMovement = forward * speed * Time.deltaTime * Input.GetAxis("Vertical");
Vector3 heading = Vector3.Normalize(rightMovement + upMovement);
transform.forward += heading;
transform.position += rightMovement;
transform.position += upMovement;
}
I want the players move direction to reflect the direction of the camera. For example, using W (from WASD) will always move the player up. Could I edit the script to pick up the direction of each of my virtual cameras and add that to my player controller or is there a better way?
To solve this problem you have to change the movement of the keys according to the angle of the camera. This is done as follows with transform.TransformDirection. When the movement is synchronized with the direction of the camera, it causes the W key to press the character towards the ground, because the angle in front of the camera is inside the ground. To solve the problem, we set y to zero and then normalize the axis.
public float speed = 10f;
void Update()
{
var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f , Input.GetAxis("Vertical"));
moveInput = Camera.main.transform.TransformDirection(moveInput);
moveInput.y = 0;
moveInput = moveInput.normalized;
transform.position += moveInput * Time.deltaTime * speed;
}

How do I Detect if the Mouse is Moving on Screen in Unity?

I am making a 360 camera movement for my game called PROTOTYPE. I need a function or something to detect if the mouse is moving and in which direction on the x axis it is, to set an offset for the Camera Smoothing script, but I don't know any. Could somebody plz help me? Here is the Camera Smoothing script if u need it:
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothSpeed = 0.125f;
public Vector3 offset;
void FixedUpdate()
{
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
I suppose you want to move your camera with your mouse, 360° around your character and also that script is attached to your player.
In order to do that, your FixedUpdate should look like this:
void FixedUpdate()
{
float horizontalAxis = Input.GetAxis("Mouse X"); // Getting the current mouse axis (left-right)
float verticalAxis = Input.GetAxis("Mouse Y"); // Getting the current mouse axis (up-down)
transform.RotateAround(player.transform.position, -Vector3.up, horizontalAxis * smoothSpeed);
transform.RotateAround(Vector3.zero, transform.right, verticalAxis * smoothSpeed);
}

Rigidbody GameObject is restricted in movement while moving

So I'm pretty new to Unity, but I managed to put together a script that moves the player around a plane. Problem is, after moving a certain distance, it won't move any further. I want the movement to be unrestricted.
using UnityEngine;
public class Movement_Player : MonoBehaviour
{
public Rigidbody rb;
public float default_speed;
public float sprint_multiplier;
private float speed;
private void Update()
{
speed = default_speed;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0.0f, vertical);
if (Input.GetKey(KeyCode.LeftShift))
speed = speed * sprint_multiplier;
else
speed = default_speed;
rb.MovePosition(movement * speed);
}
}
You need to move your MovePosition outside of Update to FixedUpdated.
FixedUpdate is the right place to put physic code.
You need too to reset your movement vector on each update if you like to get the new displacement vector to skip a drag movement and need to add timefactor * Time.fixedDeltaTime
using UnityEngine;
public class Movement_Player : MonoBehaviour
{
public Rigidbody rb;
public float default_speed;
public float sprint_multiplier;
private float speed;
private void Update()
{
Vector3 movement = Vector3.zero
speed = default_speed;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0.0f, vertical);
if (Input.GetKey(KeyCode.LeftShift))
speed = speed * sprint_multiplier;
else
speed = default_speed;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * speed * Time.fixedDeltaTime);
}
}

How to Rotate a GameObject?

I'm watching unity tutorials and in the control code of the ship I would like to make it rotate on its axis, that is, it can rotate 360 ​​degrees continuously while I press the right key for example.
playerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour {
[Header("Movement")]
public float speed;
public float tilt;
public Boundary boundary;
private Rigidbody rig;
[Header("Shooting")]
public GameObject shot;
public Transform shotSpawn;
public float fireRate;
private float nextFire;
void Awake () {
rig = GetComponent<Rigidbody>();
}
void Update () {
if (Input.GetButton ("Fire1") && Time.time > nextFire) {
nextFire = Time.time + fireRate;
Instantiate (shot, shotSpawn.position, Quaternion.identity);
}
}
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical);
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
rig.rotation = Quaternion.Euler (0f, 0f, rig.velocity.x * -tilt);
}
}
How can I edit it to do what I want?
example:
You can use Transform.Rotate()
Your code would look like this, with the example you provided:
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical);
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
if(moveHorizontal > 0){ //if your "right key" is pressed
// Rotate the object around its local X axis at 1 degree per second
transform.Rotate(Vector3.right * Time.deltaTime);
}
}
For faster Rotation you can simply multiply the Vector3.right with some value.
To Rotate around another Axis, use other Vector directions, like Vector3.up.
For example:
transform.Rotate(Vector3.Up * moveHorizontal * Time.deltaTime);
transform.Rotate(Vector3.Forward * moveHorizontal * Time.deltaTime);
When you multiply the Vector3.Right with your moveHorizontal it should also work when you press the "left key" and that should result in rotating in the other direction.
transform.Rotate(Vector3.right * moveHorizontal * Time.deltaTime);
Notes:
That only works if your PlayerController is attached to your ship gameobject. If it is not attached you have to use the transform of your ship of course.
World Space vs Local Space
When you click on your object in the scene view, you should see the transform and the 3 arrows (red, green, blue) pointing on different directions (the 3 axis). When you use the method with the parameters provided above, you are using these arrows as rotation axis.
You can also rotate arround the WorldSpace axis.
transform.Rotate(Vector3.up, Time.deltaTime, Space.World);
When to use transform.Rotate?
When you change position or rotation of a transform, using the transforms
methods, it will be applied at the end of the frame. These changes ignore physics.
-> Use transforms methods if you don't care about collisions
When to use rigidbody.MoveRotation?
When you change rigidbody.position or rigidbody.MoveRotation using rigidbodies methods, it will be applied at the end of the next physics step. These changes care about physics (collisions and stuff)
-> Use rigidbodies methods if you care about collisions
Thanks to Helium for that hint.
The third possibility:
Instead of directly calling transform.Rotate or rigidbody.MoveRotation, you can also rotate your Object, using an animation, which changes the transforms rotation.
Example of Transform.Rotate()
You can clearly see, that the collision checks are ignored on that object while it's rotating through the ground. (I packed that gif into a spoiler to reduce noise. You'll need to hover over it, if you want to see it)
This will be the speed and axis of your rotation.
public Vector3 eulerAngleVelocity = new Vector3(0f,0f,1000f);
Since you want to rotate a rigidbody so use MoveRotation
Quaternion deltaRotation = Quaternion.Euler(-moveHorizontal * eulerAngleVelocity * Time.deltaTime);
rig.MoveRotation(rig.rotation * deltaRotation);
Final code will look like this
// NEW CODE BEGIN------
public Vector3 eulerAngleVelocity = new Vector3(0f,0f,1000f);
// NEW CODE END------
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
// NEW CODE BEGIN------
Vector3 movement = new Vector3(0f, 0f, moveVertical); // Notice I have removed moveHorizontal, this will make sure your gameobject doesnt go left and right. We will use move horizontal for rotating the gameobject.
// NEW CODE END------
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
// NEW CODE BEGIN------
Quaternion deltaRotation = Quaternion.Euler(-moveHorizontal * eulerAngleVelocity * Time.deltaTime);
rig.MoveRotation(rig.rotation * deltaRotation);
// NEW CODE END------
}
You can play with eulerAngleVelocity to get the desired speed. Hope this helps. ;)

Camera always behind player in Unity3d

I'm struggling with this for quit some time now. I have GameObject, being a sphere, which is my player on a 3d Terrain. I have a Camera which is always on a fixed distance from the player, follows it where it goes with below script:
public GameObject player;
private Vector3 offset;
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
}
void LateUpdate () {
transform.position = player.transform.position + offset;
}
So far so good. However what I actually want is that the camera rotates with the player, so it always looks into the direction where the sphere is moving, but always stays behind the player at the same fixed distance, so that the player is always visible in the camera view.
There are a lot of scripts available, but the problem with the onces I've seen so far is that the camera indeed rotate with the player, but because the player actually is a rolling sphere the camera view is rolling and turning as well.
The best script I found so far is below, but this one has the same problem as the other onces, the camera rolls with the player.
public Transform target;
public float distance = 3.0f;
public float height = 3.0f;
public float damping = 5.0f;
public bool smoothRotation = true;
public bool followBehind = true;
public float rotationDamping = 10.0f;
void Update () {
Vector3 wantedPosition;
if(followBehind)
wantedPosition = target.TransformPoint(0, height, -distance);
else
wantedPosition = target.TransformPoint(0, height, distance);
transform.position = Vector3.Lerp (transform.position, wantedPosition, Time.deltaTime * damping);
if (smoothRotation) {
Quaternion wantedRotation = Quaternion.LookRotation(target.position - transform.position, target.up);
//Quaternion ownRotation = Quaternion.RotateTowards;
transform.rotation = Quaternion.Slerp (transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
}
else transform.LookAt (target, target.up);
}
Can anyone help me with this please?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public GameObject player;
public float cameraDistance = 10.0f;
// Use this for initialization
void Start () {
}
void LateUpdate ()
{
transform.position = player.transform.position - player.transform.forward * cameraDistance;
transform.LookAt (player.transform.position);
transform.position = new Vector3 (transform.position.x, transform.position.y + 5, transform.position.z);
}
}
My solution (based on #brennon-provencher answer) with smoothness and auto offset:
public class CameraFollow : MonoBehaviour
{
public GameObject target;
public float speed = 5;
Vector3 offset;
void Start()
{
offset = target.transform.position - transform.position;
}
void LateUpdate()
{
// Look
var newRotation = Quaternion.LookRotation(target.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, speed * Time.deltaTime);
// Move
Vector3 newPosition = target.transform.position - target.transform.forward * offset.z - target.transform.up * offset.y;
transform.position = Vector3.Slerp(transform.position, newPosition, Time.deltaTime * speed);
}
}
You need to move your camera position based on sphere movement direction -
public GameObject player;
private Vector3 offset;
float distance;
Vector3 playerPrevPos, playerMoveDir;
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
distance = offset.magnitude;
playerPrevPos = player.transform.position;
}
void LateUpdate () {
playerMoveDir = player.transform.position - playerPrevPos;
playerMoveDir.normalize();
transform.position = player.transform.position - playerMoveDir * distance;
transform.LookAt(player.transform.position);
playerPrevPos = player.transform.position;
}
Edit 2: To fix flickering camera, try this -
void LateUpdate () {
playerMoveDir = player.transform.position - playerPrevPos;
if (playerMoveDir != Vector3.zero)
{
playerMoveDir.normalize();
transform.position = player.transform.position - playerMoveDir * distance;
transform.position.y += 5f; // required height
transform.LookAt(player.transform.position);
playerPrevPos = player.transform.position;
}
}

Categories