Rotate GameObject based on key presses and based on Terrain slope/curvature - c#

I have code in C# in a game in Unity that needs to rotate the player based on the slope of the terrain but the RotateTowards function(calculates the slope and angle) doesn't allow the object to be rotated sideway to move it in different directions. If I take out the rotateTowards function, rotations sideways work. If I dont, the correct slope rotation works but player won'r rotate sideways when buttons are pressed.
How could I fix this so the player could rotate in both ways?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController1 : MonoBehaviour
{
[System.Serializable]
public class MoveSettings
{
public float forwardVel = 10f; // walk speed
public float rotateVel = 100; // character rotation speed, character can walk 360 degree
public float jumpVel = 25f;
public LayerMask ground;
public Transform backLeft; // back left feet
public Transform backRight; // back right feet
public Transform frontLeft; // front left feet
public Transform frontRight; // front left feet
}
[System.Serializable]
public class PhysicsSettings
{
public float downAccel = 0.75f; // down speed when not grounded
}
public GameObject Model;
public GameObject Origin;
public MoveSettings moveSettings = new MoveSettings();
public PhysicsSettings physicsSettings = new PhysicsSettings();
private Vector3 velocity = Vector3.zero;
private Quaternion targetRotation;
private CharacterController cc;
private float forwardInput, turnInput, jumpInput = 0;
private RaycastHit lr;
private RaycastHit rr;
private RaycastHit lf;
private RaycastHit rf;
private Vector3 upDir;
private Animator Anim; // global private variable
private void Start()
{
Anim = GetComponent<Animator>(); // in the Start function
targetRotation = transform.rotation;
cc = GetComponent<CharacterController>();
}
public bool Grounded()
{
return cc.isGrounded;
}
private void FixedUpdate()
{
Run(); // calculate the velocity to be applied on character controller, stored in the velocity variable
Jump(); // code for jumping
GetInput(); // movement input keys
Turn(); // character movement direction input
cc.Move(transform.TransformDirection(velocity) * Time.deltaTime);
RotateTowardsGround();
}
private void GetInput()
{
Anim.SetFloat("vSpeed", forwardInput); // in the GetInput() function
Anim.SetFloat("Direction", 1f);
forwardInput = Input.GetAxis("Vertical");
turnInput = Input.GetAxis("Horizontal");
jumpInput = Input.GetAxisRaw("Jump");
}
private void Turn()
{
targetRotation *= Quaternion.AngleAxis(moveSettings.rotateVel * turnInput * Time.deltaTime, Vector3.up);
transform.rotation = targetRotation;
}
public void Jump()
{
if (jumpInput > 0 && Grounded())
{
velocity.y = moveSettings.jumpVel;
}
else if (jumpInput == 0 && Grounded())
{
velocity.y = 0;
}
else
{
velocity.y -= physicsSettings.downAccel;
}
}
private void Run()
{
velocity.z = moveSettings.forwardVel * forwardInput;
}
public void RotateTowardsGround()
{
// we have four feet
Physics.Raycast(moveSettings.backLeft.position + Vector3.up, Vector3.down, out lr);
Physics.Raycast(moveSettings.backRight.position + Vector3.up, Vector3.down, out rr);
Physics.Raycast(moveSettings.frontLeft.position + Vector3.up, Vector3.down, out lf);
Physics.Raycast(moveSettings.frontRight.position + Vector3.up, Vector3.down, out rf);
upDir = (Vector3.Cross(rr.point - Vector3.up, lr.point - Vector3.up) +
Vector3.Cross(lr.point - Vector3.up, lf.point - Vector3.up) +
Vector3.Cross(lf.point - Vector3.up, rf.point - Vector3.up) +
Vector3.Cross(rf.point - Vector3.up, rr.point - Vector3.up)
).normalized;
Debug.DrawRay(rr.point, Vector3.up);
Debug.DrawRay(lr.point, Vector3.up);
Debug.DrawRay(lf.point, Vector3.up);
Debug.DrawRay(rf.point, Vector3.up);
Model.transform.up = upDir;
}
}

The proper way to rotate object based on Terrain slope/curvature is to first throw raycast then obtain the returned RaycastHit.normal value and assign it your to the object's transform.up. It's better to use Lerp or Slerp to do this form smooth ration.
As for the position of the object, you can calculate that with Terrain.activeTerrain.SampleHeight as described in this post or you can use RaycastHit.point like you did in the code from your question.
Below is an example of what I described above. It is a minimal code to move/rotate object over a terrain. You can modify it to fit your four character legs scenario.
public class Hover : MonoBehaviour
{
public Transform objectToMove;
public float maxSpeed = 10f;
public float angleSpeed = 5f;
public float groundDistOffset = 2f;
private Vector3 toUpPos = Vector3.zero;
void Update()
{
float hInput = Input.GetAxis("Horizontal");
float vInput = Input.GetAxis("Vertical");
Vector3 objPos = objectToMove.position;
objPos += objectToMove.forward * vInput * maxSpeed * Time.deltaTime;
objPos += objectToMove.right * hInput * maxSpeed * Time.deltaTime;
RaycastHit hit;
if (Physics.Raycast(objectToMove.position, -Vector3.up, out hit))
{
//Get y position
objPos.y = (hit.point + Vector3.up * groundDistOffset).y;
//Get rotation
toUpPos = hit.normal;
}
//Assign position of the Object
objectToMove.position = objPos;
//Assign rotation/axis of the Object
objectToMove.up = Vector3.Slerp(objectToMove.up, toUpPos, angleSpeed * Time.deltaTime);
}
}

Related

Cant change transform.position player on Unity

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class teleporttospawn : MonoBehaviour
{
public GameObject player; /// player
public Transform fps; /// also player
private void OnTriggerEnter(Collider other)
{
Debug.Log("teleport succes.");
fps.transform.position = new Vector3(-3.82f, 1.08f, -1.69f); // DONT WORK
player.transform.position = new Vector3(-3.82f, 1.08f, -1.69f); //DONT WORK
}
}
I have two players in the script above because I tried to move it in two ways but nothing worked
So I tried to set the object to vector3 and try to move the player to the object, so nothing comes out
I need teleport player when he triger the collider. Debug.Log work but transform.position dont work.
Its dosent work from this script -> fpscontroller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class fpscontroller : MonoBehaviour
{
public float walkingSpeed = 7.5f;
public float runningSpeed = 11.5f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
public Camera playerCamera;
public float lookSpeed = 2.0f;
public float lookXLimit = 45.0f;
CharacterController characterController;
Vector3 moveDirection = Vector3.zero;
float rotationX = 0;
[HideInInspector]
public bool canMove = true;
public GameObject tp;
private void OnTriggerEnter(Collider collision)
{
if (collision.gameObject.CompareTag("tp"))
{
while(transform.position != tp.transform.position)
{
Debug.Log("teleport succes.");
gameObject.transform.position = tp.transform.position;
}
}
}
void Start()
{
transform.position = gameObject.transform.position;
characterController = GetComponent<CharacterController>();
// Lock cursor
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
// We are grounded, so recalculate move direction based on axes
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 right = transform.TransformDirection(Vector3.right);
// Press Left Shift to run
bool isRunning = Input.GetKey(KeyCode.LeftShift);
float curSpeedX = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Vertical") : 0;
float curSpeedY = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Horizontal") : 0;
float movementDirectionY = moveDirection.y;
moveDirection = (forward * curSpeedX) + (right * curSpeedY);
if (Input.GetButton("Jump") && canMove && characterController.isGrounded)
{
moveDirection.y = jumpSpeed;
}
else
{
moveDirection.y = movementDirectionY;
}
// Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
// when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
// as an acceleration (ms^-2)
if (!characterController.isGrounded)
{
moveDirection.y -= gravity * Time.deltaTime;
}
// Move the controller
characterController.Move(moveDirection * Time.deltaTime);
// Player and Camera rotation
if (canMove)
{
rotationX += -Input.GetAxis("Mouse Y") * lookSpeed;
rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit);
playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0);
transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0);
}
}
}

Jittering movement Unity C# follow script

I'm creating a simple movement/following script in C#. I have a prefab (ball) spawn randomly within the Awake() method, at a random area in my scene. I then have another script attached to a different game object (robot) that at the start of the game shall move towards the ball.
Now the movement works but when the game object has come into the the minDistanceToTarget it begins to "jitter" and move around.
Here's the movement script:
public class RobotMovement : MonoBehaviour {
// Movement
private Transform target;
private float speed = 2f;
private float distance;
private float minDistanceToTarget = 1f;
// Rotation
private Vector3 targetDirection;
private Quaternion lookAtRotation;
private float RotationSpeed = 2f;
void Start() {
target = GameObject.FindGameObjectWithTag("Ball").transform;
}
void Update() {
targetDirection = target.position - transform.position;
lookAtRotation = Quaternion.LookRotation(targetDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, lookAtRotation, RotationSpeed * Time.deltaTime);
distance = Vector3.Distance(transform.position, target.position);
if (distance >= minDistanceToTarget) {
transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
}
}
Edit I tried to change the affect to use FixedUpdate and affect the RigidBodies instead.
public class RobotMovement : MonoBehaviour {
private Rigidbody robot;
public Rigidbody target;
// Movement
private float speed = 2f;
private float minDistanceToTarget = 2f;
void Start() {
robot = GetComponent<Rigidbody>();
target = target.GetComponent<Rigidbody>();
}
void FixedUpdate() {
if (Vector3.Distance(robot.position, target.position) > minDistanceToTarget) {
robot.MovePosition(target.position * speed * Time.deltaTime);
}
}
}
Edit I now use a new movement method and include a rotation calculation. But it still jumps and jitters
public class RobotMovement : MonoBehaviour {
private Rigidbody robot;
private Transform ball;
// Movement
private float robotMovSpeed = 2f;
private float distanceToTarget;
private float distanceToStop = 2f;
// Rotation
private Vector3 targetDirection;
private Quaternion lookAtTarget;
private float rotationSpeed = 2f;
void Start() {
robot = GetComponent<Rigidbody>();
ball = GameObject.FindGameObjectWithTag("Ball").transform;
}
void FollowTarget(Transform target, float distanceToStop, float speed) {
distanceToTarget = Vector3.Distance(robot.position, target.position);
// Rotation
targetDirection = target.position - robot.position;
lookAtTarget = Quaternion.LookRotation(targetDirection);
if (distanceToTarget >= distanceToStop) {
transform.rotation = Quaternion.Slerp(transform.rotation, lookAtTarget, rotationSpeed * Time.deltaTime);
robot.MovePosition(robot.position + (target.position - robot.position).normalized * speed * Time.deltaTime);
}
}
void FixedUpdate() {
FollowTarget(ball, distanceToStop, robotMovSpeed);
}
}

Why does my character only rotate to the target one time every time it doesn't move?

My question might sound confusing but I want to make my code so when my character doesn't move, he looks directly towards the closest enemy. The problem is that when I stop moving my character, it only does the command once and doesn't redirect to the enemy's new position. I tested out many things like making it so when i move, it looks at the enemy and it seems to work but whenever I set it to not move, it doesn't work.
using System.Collections.Generic;
using UnityEngine;
namespace work.working.worked
{
public class Movement : MonoBehaviour
{
public float moveSpeed;
public float rotationSpeed;
public static bool ismoving;
public Rigidbody2D rb;
Vector2 movement;
// Update is called once per frame
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
if (Input.anyKey)
{
ismoving = true;
}
else
{
ismoving = false;
}
if (ismoving == true)
{
Vector2 direction = new Vector2(movement.x, movement.y);
direction.Normalize();
if (direction != Vector2.zero)
{
Quaternion toRotation = Quaternion.LookRotation(Vector3.forward, direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
if (ismoving == false)
{
Vector3 direction = FindClosest.closestEnemy.position - transform.position;
direction.Normalize();
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 85f;
rb.rotation = angle;
}
}
}
}
Instead of Input.anyKey you could check that the magnitude of movement vector to see if character is moving.
ismoving = movement.magnitude > 0.0f;
using System.Collections.Generic;
using UnityEngine;
namespace work.working.worked
{
public class Movement : MonoBehaviour
{
public float moveSpeed;
public float rotationSpeed;
public bool ismoving;
public Rigidbody2D rb;
Vector2 movement;
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
ismoving = movement.magnitude > 0.0f;
if (ismoving)
{
Vector2 direction = new Vector2(movement.x, movement.y);
direction.Normalize();
if (direction != Vector2.zero)
{
Quaternion toRotation = Quaternion.LookRotation(Vector3.forward, direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
else
{
Vector3 direction = FindClosest.closestEnemy.position - transform.position;
direction.Normalize();
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 85f;
rb.rotation = angle;
}
}
}
Also don't make ismoving variable static or it gets set by every active Movement component in loaded scenes which can lead to unexpected behavior down the line. If its public, you can see it's state in Unity inspector by selecting the GameObject with Movement component.

Unity jump script delay

Im making a 3d game in unity, and so I made a cs script for movement of my charecter, walking and moveing the camera works fine, however when i added the jump function, it had a delay. You could press the jump button 5 times, with no result. Then you press it again, and it jumps. I cant figure out why this does this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public int speed = 6;
public float gravity = 9.87f;
private float verticalspeed = 0;
private Vector3 moveDirection = Vector3.zero;
public Transform Camera;
public float Sensitivity = 2f;
public float uplimit = -50;
public float downlimit = -50;
public float jumpspeed = 5.0f;
void Update()
{
move();
cameramove();
void cameramove()
{
float horizontal = Input.GetAxis("Mouse X");
float vertical = Input.GetAxis("Mouse Y");
transform.Rotate(0, horizontal * Sensitivity, 0);
Camera.Rotate(-vertical * Sensitivity, 0, 0);
Vector3 currentRotation = Camera.localEulerAngles;
if (currentRotation.x > 180) currentRotation.x -= 360;
currentRotation.x = Mathf.Clamp(currentRotation.x, uplimit, downlimit);
Camera.localRotation = Quaternion.Euler(currentRotation);
}
void move()
{
float horizontalMove = Input.GetAxis("Horizontal");
float verticalMove = Input.GetAxis("Vertical");
if (characterController.isGrounded) verticalspeed = 0;
else verticalspeed -= gravity * Time.deltaTime;
Vector3 gravityMove = new Vector3(0, verticalspeed, 0);
Vector3 move = transform.forward * verticalMove + transform.right * horizontalMove;
characterController.Move(speed * Time.deltaTime * move + gravityMove * Time.deltaTime);
if (characterController.isGrounded && Input.GetButton("Jump"))
{
moveDirection.y = jumpspeed;
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
}
}
}
Assuming your character has a RigidBody assigned to it, you can refer it on your script as,
public class PlayerMovement : MonoBehaviour
{
private Rigidbody myrigidbody;
void Start () {
myrigidbody = GetComponent<Rigidbody>();
}
}
Then you can pass the jumpspeed as a Vector3, and probably you might have to trigger your animation here as well.
if (characterController.isGrounded && Input.GetButton("Jump"))
{
characterController.isGrounded = false;
myrigidbody.AddForce(new Vector3(0, jumpspeed, 0));
// Trigger your animation, myanimator.SetTrigger("jump");
}
Unity character controller move documentation also contains jump function.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Example : MonoBehaviour
{
private CharacterController controller;
private Vector3 playerVelocity;
private bool groundedPlayer;
private float playerSpeed = 2.0f;
private float jumpHeight = 1.0f;
private float gravityValue = -9.81f;
private void Start()
{
controller = gameObject.AddComponent<CharacterController>();
}
void Update()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
controller.Move(move * Time.deltaTime * playerSpeed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
// Changes the height position of the player..
if (Input.GetButtonDown("Jump") && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
}

Unity 2018 C# - Fbx Running animation scaling with Input?

I have figured out how to get fbx animations working in Unity for my character in my adventure game, but now I wish to have my character's running animation move with its speed of motion being in relation to the input of the control stick on an xbox controller.
In addition, when I add a walking animation in the future I wish to make a threshold for the control stick input so that the character walks when there is minimal input from the control stick and running when there is more input from the control stick. Any advice?
Here is my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCharacterController : MonoBehaviour {
static Animator anim;
public bool walking;
public GameObject playerModel, Hero;
//Transforms
public Transform playerCam, character, centerPoint;
private Vector3 moveDirection;
//character controller declaration
CharacterController player;
//Mouse Rotation
private float rotX, rotY;
//Mouse Y Position
public float mouseYPosition = 1f;
//Mouse Sensitivity
public float Sensitivity = 10f;
//Mouse Zoom
private float zoom;
public float zoomSpeed = 2;
//Clamping Zoom
public float zoomMin = -2f;
public float zoomMax = -10f;
public float rotationSpeed = 5f;
//Move Front Back left & Right
private float moveFB, moveLR;
//Movement Speed
public float Speed = 2f;
//Velocity of Gravity
public float verticalVelocity;
//Jump Distance
public float jumpDist = 5f;
//Multiple Jumps
int jumpTimes;
//To use with Dialogue Manager
public DialogueManager DiagM;
public AudioClip jumpSound;
public AudioClip HurtSound;
AudioSource audioSource;
//knockback
public float knockBackForce;
public float knockBackTime;
private float knockBackCounter;
// Use this for initialization
void Start ()
{
//character controller
player = GameObject.Find("Player").GetComponent<CharacterController> ();
anim = GetComponent<Animator>();
//mouse zoom
zoom = -3;
centerPoint.transform.position = playerCam.transform.position;
centerPoint.transform.parent = null;
audioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update ()
{
//if (DiagM.StartDialogue)
//{ return; }
//Mouse Zoom Input
zoom += Input.GetAxis ("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
//Mouse Camera Input
playerCam.transform.localPosition = new Vector3 (0, 0, zoom);
//Mouse Rotation
rotX += Input.GetAxis ("Mouse X") * Sensitivity;
rotY -= Input.GetAxis ("Mouse Y") * Sensitivity;
//Clamp Camera
rotY = Mathf.Clamp (rotY, -60f, 60f);
playerCam.LookAt (centerPoint);
centerPoint.localRotation = Quaternion.Euler (rotY, rotX, 0);
//Movement Speed
if (knockBackCounter <= 0)
{
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection * Speed;
moveDirection.y = verticalVelocity;
player.Move(moveDirection * Time.deltaTime);
//Movement Rotation
centerPoint.position = new Vector3 (character.position.x, character.position.y + mouseYPosition, character.position.z);
//knockback disable
//Movement Input
if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
{
transform.rotation = Quaternion.Euler(0f, centerPoint.rotation.eulerAngles.y, 0f);
Quaternion turnAngle = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
playerModel.transform.rotation = Quaternion.Slerp(playerModel.transform.rotation, turnAngle, Time.deltaTime * rotationSpeed);
if (player.isGrounded == true)
{
anim.Play("Running");
}
}
else
{
if (player.isGrounded == true)
{ anim.Play("Idle"); }
}
if (player.isGrounded == true)
{
jumpTimes = 0;
verticalVelocity = -Physics.gravity.y * Time.deltaTime;
}
else
{
verticalVelocity += Physics.gravity.y * Time.deltaTime;
}
if (Input.GetButtonDown("Submit"))
{
anim.Play("Hello");
}
if (jumpTimes < 1)
{
if (Input.GetButtonDown("Jump"))
{
verticalVelocity += jumpDist;
anim.Play("Jump");
audioSource.PlayOneShot(jumpSound, 1F);
jumpTimes += 1;
}
}
}
else
{
knockBackCounter -= Time.deltaTime;
}
}
public void Knockback(Vector3 direction)
{
knockBackCounter = knockBackTime;
anim.SetTrigger("isJumping");
audioSource.PlayOneShot(HurtSound, 50F);
moveDirection = direction * knockBackForce;
moveDirection.y = knockBackForce;
}
}

Categories

Resources