Unity 3D Aerial movement and jumping problem - c#

Aerial Movement Problem
I've followed a few tutorials and I've set up a decent base for a game, - basic player movement, entity animation, health, HUD UI, etc. - but I wanted to make the movement a bit smoother, less snappy, more physics-based, you get the gist. I made it a bit better and it definitely meets all the requirements for terrain-based movement (i.e: movement across physical surfaces - while the player is on the ground), but I want jumping to be a bit more dynamic, and I know what I want to do but I'm having trouble doing it.
Here's the issue:
If the player moves (regardless of whether sprintActive is toggled or not) and they jump after moving, the player gains speed in the air way too fast, and they can't move in any direction other than forward (relative to their rotation).
Here's the objective:
I set it up so the velocity is simply redirected to whatever direction is forward from the playerRB, but I think I would prefer if the velocity didn't immediately change direction, but rather gradually curve as the player tries to move a certain direction? I know I may be asking for a lot, but some advice on how to do this, or if I should try a different approach, would be very much appreciated.
Code used:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RFPSPlayerMovement : MonoBehaviour
{
public float speedForce;
public float jumpForce;
public float diveForce;
public Transform groundCheck;
public float groundDistance = 0.25f;
public LayerMask groundMask;
private Transform playerBody;
private Rigidbody playerRB;
private bool isGrounded;
private bool sprintActive = false;
private bool delay = false;
private float lateralSpeed;
private Vector3 velocity;
float xMov, zMov;
float xSpeed, zSpeed;
IEnumerator DelayTimer(float duration)
{
delay = true;
yield return new WaitForSeconds(duration);
delay = false;
}
void Start()
{
playerBody = GetComponent<Transform>();
playerRB = GetComponent<Rigidbody>();
}
void Update()
{
xMov = Input.GetAxisRaw("Horizontal") * Time.deltaTime;
zMov = Input.GetAxisRaw("Vertical") * Time.deltaTime;
if(Input.GetKey(KeyCode.LeftShift))
{
sprintActive = true;
}
else
{
sprintActive = false;
}
if(Input.GetKey(KeyCode.W))
{
Movement(0, speedForce);
}
if(Input.GetKey(KeyCode.S))
{
Movement(0, -speedForce);
}
if(Input.GetKey(KeyCode.A))
{
Movement(-speedForce, 0);
}
if(Input.GetKey(KeyCode.D))
{
Movement(speedForce, 0);
}
if(Input.GetKey(KeyCode.Space))
{
if(delay == false)
{
if(isGrounded)
{
StartCoroutine(DelayTimer(0.05f));
Jump(jumpForce);
}
}
}
}
void FixedUpdate()
{
velocity = playerRB.velocity;
lateralSpeed = new Vector2(playerRB.velocity.x, playerRB.velocity.z).magnitude;
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if(isGrounded)
{
velocity = new Vector3(
xMov + (float) (playerRB.velocity.x * 0.90),
playerRB.velocity.y,
zMov + (float) (playerRB.velocity.z * 0.90)
);
}
else
{
velocity.x = (float) (playerBody.forward.x * lateralSpeed);
velocity.y = playerRB.velocity.y;
velocity.z = (float) (playerBody.forward.z * lateralSpeed);
}
playerBody.eulerAngles = new Vector3(0, playerBody.eulerAngles.y, 0);
playerRB.velocity = velocity;
}
void Movement(float xAmount, float zAmount)
{
if(sprintActive)
{
xSpeed = (float) (xAmount * 2);
zSpeed = (float) (zAmount * 2);
}
else
{
xSpeed = xAmount;
zSpeed = zAmount;
}
playerRB.AddRelativeForce(new Vector3(xSpeed, 0, zSpeed), ForceMode.Impulse);
}
void Jump(float yAmount)
{
playerRB.AddRelativeForce(new Vector3(0, yAmount, 0), ForceMode.Impulse);
}
}

Related

How to make an FPS Camera using Netcode for gameobjects and FPS Starter Assets?

All I know is that every time a new client joins, all the player set their main camera to that ones.
I use the starter assets but I changed few things to solve this and do the networking:
using Unity.Netcode;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
using UnityEngine.InputSystem;
#endif
namespace StarterAssets
{
[RequireComponent(typeof(CharacterController))]
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
[RequireComponent(typeof(PlayerInput))]
#endif
public class FirstPersonController : NetworkBehaviour
{
[Header("Player")]
[Tooltip("Move speed of the character in m/s")]
public float MoveSpeed = 4.0f;
[Tooltip("Sprint speed of the character in m/s")]
public float SprintSpeed = 6.0f;
[Tooltip("Rotation speed of the character")]
public float RotationSpeed = 1.0f;
[Tooltip("Acceleration and deceleration")]
public float SpeedChangeRate = 10.0f;
[Space(10)]
[Tooltip("The height the player can jump")]
public float JumpHeight = 1.2f;
[Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
public float Gravity = -15.0f;
[Space(10)]
[Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
public float JumpTimeout = 0.1f;
[Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
public float FallTimeout = 0.15f;
[Header("Player Grounded")]
[Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
public bool Grounded = true;
[Tooltip("Useful for rough ground")]
public float GroundedOffset = -0.14f;
[Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
public float GroundedRadius = 0.5f;
[Tooltip("What layers the character uses as ground")]
public LayerMask GroundLayers;
[Header("Cinemachine")]
[Tooltip("The follow target set in the Cinemachine Virtual Camera that the camera will follow")]
public GameObject CinemachineCameraTarget;
[Tooltip("How far in degrees can you move the camera up")]
public float TopClamp = 90.0f;
[Tooltip("How far in degrees can you move the camera down")]
public float BottomClamp = -90.0f;
// cinemachine
private float _cinemachineTargetPitch;
// player
private float _speed;
private float _rotationVelocity;
private float _verticalVelocity;
private float _terminalVelocity = 53.0f;
// timeout deltatime
private float _jumpTimeoutDelta;
private float _fallTimeoutDelta;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
private PlayerInput _playerInput;
#endif
private CharacterController _controller;
private StarterAssetsInputs _input;
[SerializeField] private GameObject _mainCamera;
private const float _threshold = 0.01f;
private bool IsCurrentDeviceMouse
{
get
{
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
return _playerInput.currentControlScheme == "KeyboardMouse";
#else
return false;
#endif
}
}
public override void OnNetworkSpawn()
{
// get a reference to our main camera
if (_mainCamera == null)
{
foreach (Transform child in gameObject.transform)
{
if (child.name == "PlayerCameraRoot")
{
foreach (Transform granchild in child.transform)
{
if (granchild.tag == "MainCamera")
_mainCamera = granchild.gameObject;
}
}
}
}
}
private void Start()
{
if(!IsOwner) return;
_controller = GetComponent<CharacterController>();
_input = GetComponent<StarterAssetsInputs>();
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
_playerInput = GetComponent<PlayerInput>();
#else
Debug.LogError( "Starter Assets package is missing dependencies. Please use Tools/Starter Assets/Reinstall Dependencies to fix it");
#endif
// reset our timeouts on start
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
Cursor.visible = false;
}
private void Update()
{
if(!IsOwner) return;
JumpAndGravity();
GroundedCheck();
Move();
}
private void LateUpdate()
{
CameraRotation();
}
private void GroundedCheck()
{
// set sphere position, with offset
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
}
private void CameraRotation()
{
// if there is an input
if (_input.look.sqrMagnitude >= _threshold)
{
//Don't multiply mouse input by Time.deltaTime
float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
_cinemachineTargetPitch += _input.look.y * RotationSpeed * deltaTimeMultiplier;
_rotationVelocity = _input.look.x * RotationSpeed * deltaTimeMultiplier;
// clamp our pitch rotation
_cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
// Update Cinemachine camera target pitch
CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f);
// rotate the player left and right
transform.Rotate(Vector3.up * _rotationVelocity);
}
}
private void Move()
{
// set target speed based on move speed, sprint speed and if sprint is pressed
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
// a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
// note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is no input, set the target speed to 0
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
// a reference to the players current horizontal velocity
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
// accelerate or decelerate to target speed
if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
{
// creates curved result rather than a linear one giving a more organic speed change
// note T in Lerp is clamped, so we don't need to clamp our speed
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
// round speed to 3 decimal places
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
else
{
_speed = targetSpeed;
}
// normalise input direction
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is a move input rotate player when the player is moving
if (_input.move != Vector2.zero)
{
// move
inputDirection = transform.right * _input.move.x + transform.forward * _input.move.y;
}
// move the player
_controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
}
private void JumpAndGravity()
{
if (Grounded)
{
// reset the fall timeout timer
_fallTimeoutDelta = FallTimeout;
// stop our velocity dropping infinitely when grounded
if (_verticalVelocity < 0.0f)
{
_verticalVelocity = -2f;
}
// Jump
if (_input.jump && _jumpTimeoutDelta <= 0.0f)
{
// the square root of H * -2 * G = how much velocity needed to reach desired height
_verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
}
// jump timeout
if (_jumpTimeoutDelta >= 0.0f)
{
_jumpTimeoutDelta -= Time.deltaTime;
}
}
else
{
// reset the jump timeout timer
_jumpTimeoutDelta = JumpTimeout;
// fall timeout
if (_fallTimeoutDelta >= 0.0f)
{
_fallTimeoutDelta -= Time.deltaTime;
}
// if we are not grounded, do not jump
_input.jump = false;
}
// apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
if (_verticalVelocity < _terminalVelocity)
{
_verticalVelocity += Gravity * Time.deltaTime;
}
}
private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
{
if (lfAngle < -360f) lfAngle += 360f;
if (lfAngle > 360f) lfAngle -= 360f;
return Mathf.Clamp(lfAngle, lfMin, lfMax);
}
private void OnDrawGizmosSelected()
{
Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
if (Grounded) Gizmos.color = transparentGreen;
else Gizmos.color = transparentRed;
// when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
}
}
}
And this is my Prefab for the player:
enter image description here
My Network Manager:
enter image description here
Note: I don't know if it matters. It probably does not but I am raycasting with the cameras.
I've had some experience with a 2d game but it should also work for 3d fps make a empty gameobject then use that as a parent for the camera then using a new script you can disable it if IsOwner is false (make sure your using Unity.Netcode and instead of a MonoBehaviour you use a NetworkBehaviour otherwise you cant use IsOwner)

Unity3D go down on slopes with a animated character

I'm developping a 3D game Unity with a squirrel as the player.
I'm struggling with a problem of slopes. I know, there are a bunch of tutorial to go down a slope whithout 'floating in the air while walking' but I didn't find a fine solution. I think it's because of the horizontal animations of the squirrel (maybe). I have tried with addForce, with a modified speed, with gravity... (maybe I implemented it wrong). I know I can check if I'm in the air or not with CharacterController.isGrounded but I can't force the squirrel to stick on the slope while running or walking. I'm sorry by advance if my question is too vague or simple.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;
public class Squirrel : MonoBehaviour {
Animator squirrel;
public float gravity = 1.0f;
private Vector3 moveDirection = Vector3.zero;
float axisH, axisV;
public static int munitions = 0;
Rigidbody rb;
[SerializeField]
float walkSpeed = 2f, runSpeed = 8f, rotSpeed = 100f, jumpForce = 350;
private bool isJumpKeyDown = false;
[SerializeField] bool isJumping = false;
Animator characterAnimator;
int JumpCount = 0;
public int MaxJumps = 1; //Maximum amount of jumps (i.e. 2 for double jumps)
[SerializeField] GameObject nb_munitions;
CharacterController characterController;
// Use this for initialization
void Start () {
munitions = 0;
squirrel = GetComponent<Animator>();
rb = GetComponentInChildren<Rigidbody>();
characterAnimator = GetComponent<Animator>();
JumpCount = MaxJumps;
characterController = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
GetInput();
nb_munitions.GetComponent<Text>().text = "Glands : " + munitions; //Affichage du score
Move();
}
private void FixedUpdate()
{
if (isJumpKeyDown)
{
squirrel.SetTrigger("jump");
JumpCount -= 1;
isJumpKeyDown = false;
}
}
public void GetInput()
{
axisV = Input.GetAxis("Vertical");
axisH = Input.GetAxis("Horizontal");
}
private void Move()
{
if (characterController.isGrounded)
{
//On the ground
}
else
{
//on the air
}
if (axisV > 0)
{
if (Input.GetKeyDown(KeyCode.LeftControl))
{
transform.position += Vector3.forward * walkSpeed * Time.deltaTime;
squirrel.SetBool("walk", true);
}
else
{
transform.position += Vector3.forward * runSpeed * Time.deltaTime;
squirrel.SetFloat("run", axisV);
squirrel.SetBool("walk", false);
}
}
else
{
squirrel.SetFloat("run", 0);
}
if (axisH != 0 && axisV == 0)
{
squirrel.SetFloat("h", axisH);
}
else
{
squirrel.SetFloat("h", 0);
}
if (axisH != 0)
{
transform.Rotate(Vector3.up * rotSpeed * Time.deltaTime * axisH);
}
if (Input.GetKeyDown(KeyCode.Space))
{
if (JumpCount > 0)
{
isJumpKeyDown = true;
}
}
//Call munitions
if (Input.GetKeyDown(KeyCode.LeftShift))
{
if (Squirrel.munitions > 0)
{
SpawnerScript.Instance.NewSpawnRequest();
munitions--;
}
}
}
}
You can try to get the angle of the slope and make it the pitch for the mesh of the squirrel.
I finally found the problem. My C# script "overwrited" the CharacterController and did not allow the squirrel to go down the slopes. Make sure you follow a move script that "respects" the CharacterController (if you pick one or you'll be fighting windmills).

Character rotation relative with camera forward?

I spent some time already and still cant figure it out by myself.
The problem is i can"t rotate character forward to move the way i pointing my camera.
To move camera i use cinemachine with Orbital Transposer and normal Composer.
My Movement script to let you know with what I work :
public class PlayerMovement : MonoBehaviour
{
public float m_Impulse = 1f;
public bool grounded = false;
public float groundCheckDistance;
private float bufferCheckDistance = 0.02f;
public float airMultiplier = 0.2f;
float horizontalInput;
float verticalInput;
public float groundDrag;
Rigidbody m_Rigidbody;
Vector3 moveDirection;
public float m_Speed = 5f;
public float m_runSpeed = 7f;
void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
m_Rigidbody.freezeRotation = true;
}
void FixedUpdate()
{
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
if (Input.GetKey(KeyCode.Space) & grounded)
{
m_Rigidbody.AddForce(Vector3.up * m_Impulse * 2);
}
if (Input.GetKey(KeyCode.LeftShift))
{
m_Rigidbody.AddForce(moveDirection * m_runSpeed, ForceMode.Force);
}
else
{
m_Rigidbody.AddForce(moveDirection * m_Speed, ForceMode.Force);
}
}
void Update()
{
groundCheckDistance = (GetComponent<CapsuleCollider>().height / 2) + bufferCheckDistance;
RaycastHit hit;
if (Physics.Raycast(transform.position, -transform.up, out hit, groundCheckDistance))
{
grounded = true;
}
else
{
grounded = false;
}
if (grounded)
{
m_Rigidbody.drag = groundDrag;
}
else if (!grounded)
{
moveDirection *= airMultiplier;
m_Rigidbody.drag = 2;
}
}
Hope you know how to make it works, Thank You in advance.
P.S. My camera script was left with Cursor.LockMode only cuz i messed something up rly bad and my camera was bugged.

Unity - how to make an object face the direction of its movement?

I'm trying to make a character prefab face the direction in which its moving. I've tired all sorts of things, with and without rigidbodies but nothing seems to work. The thing is, it does actually face in the correct direction. But once its there, it starts to rotate the whole prefab and it goes down into the ground.
The character holds a 3D shield, and goes towards a tower. So once it reaches the tower it raises the shield which in turn rotates the whole character down into the ground. I would like it to just rotate in the X and Z axis and never change the Y axis.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BlockRadar : MonoBehaviour
{
// Start is called before the first frame update
public Transform Tower;
private GameObject[] multipleBlocks;
public Transform closestBlock;
public bool blockContact;
public float currentDistance;
public float stopDistance;
public Animator animator;
public int damage;
public float attackspeed;
private float canAttack;
public float moveSpeed = 5f;
public Vector3 distance;
private Vector3 movement;
void Start()
{
closestBlock = null;
blockContact = false;
}
// Update is called once per frame
void Update()
{
Vector3 pos = transform.position;
pos.y = 0;
pos.x = 0;
transform.position = pos;
closestBlock = getClosestBlock();
closestBlock.gameObject.GetComponent<Renderer>().material.color = new Color(1, 0.7f, 0, 1);
Vector3 direction = closestBlock.position - transform.position;
direction.Normalize();
movement = direction;
float dist = Vector3.Distance(closestBlock.position, transform.position);
if (dist <= 1.5f)
{
{
blockContact = true;
animator.SetBool("Moving", false);
Debug.Log("Now touching block");
if (attackspeed <= canAttack)
{
Attack();
canAttack = 0f;
}
else
{
canAttack += Time.deltaTime;
}
}
}
if (dist > 1.5f)
{
transform.forward = movement;
blockContact = false;
Debug.Log("Lost contact with block");
animator.SetBool("Moving", true);
moveCharacter(movement);
}
}
public void Attack()
{
Debug.Log("ATTACKING!");
Damage(closestBlock.transform);
animator.SetTrigger("Attacking");
}
private void FixedUpdate()
{
}
void moveCharacter(Vector3 direction)
{
transform.Translate(direction * moveSpeed * Time.deltaTime, Space.World);
}
void DistanceToTower()
{
if (Tower)
{
float dist = Vector3.Distance(Tower.position, transform.position);
if (dist <= 1)
{
{
blockContact = true;
Debug.Log("Now touching block");
if (attackspeed <= canAttack)
{
Attack();
canAttack = 0f;
}
else
{
canAttack += Time.deltaTime;
}
}
}
}
}
//when the object carrying this script is destroyed
private void OnDestroy()
{
if (closestBlock !=null)
{
closestBlock.gameObject.GetComponent<Renderer>().material.color = new Color(0, 0, 0, 0);
}
}
public Transform getClosestBlock()
{
multipleBlocks = GameObject.FindGameObjectsWithTag("Block");
float closestDistance = Mathf.Infinity;
Transform trans = null;
//finds all blocks in the scene
foreach (GameObject go in multipleBlocks)
{
currentDistance = Vector3.Distance(transform.position, go.transform.position);
if (currentDistance < closestDistance)
{
closestDistance = currentDistance;
trans = go.transform;
}
}
return trans;
}
void Damage(Transform block)
{
Tower_Stats e = block.GetComponent<Tower_Stats>();
if (e != null)
{
e.TakeDamage(damage);
}
}
}
I would be really, really grateful for any help. As I said before I used to have rigidbodies on the character, but I removed them since I thought maybe they were the fault. But doesnt seem like it. One other thing I've noticed is that when the prefab is instantiated, its children doesnt have the correct position values. Not sure why. But if that could be a clue I just thought I'd let you know.

Unity3D smooth camera movement and lookAt

Got stuck with camera movement in my Unity3D C# project.
What I have:
some objects on the scene
a camera, which would fly from any object's poition or from it's own current position
What I need:
smooth rotare camera to one of the object's origin
fly to the spot near the object (there is an empty, so I fly to empty's coords)
Algorithm: rotate to the object's origin, when rotation finishes, start to fly to the empty's position. while flying, look at object's origin.
The problem is that it's not smooth, the camera "jumps" at the end of the movement.
My C# code (attached to the camera):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testMove : MonoBehaviour {
public GameObject startObj;
public GameObject endObj;
public float speed = 1.0F;
private float startTime;
private float journeyLength;
private string endObjName;
private GameObject endObjLookAt;
void Start () {
startTime = Time.time;
if (startObj) {
} else {
startObj = this.gameObject;
}
journeyLength = Vector3.Distance(startObj.transform.position, endObj.transform.position);
endObjName = endObj.name;
endObjLookAt = GameObject.Find(endObjName + "LookAt");
}
void Update () {
if (endObj) {
float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
tweenLook(endObjLookAt, fracJourney);
float angle = Quaternion.Angle(transform.rotation, Quaternion.LookRotation(endObjLookAt.transform.position - transform.position));
if (angle <= 0.0001) {
Debug.Log("rotation finished");
tweenPos(startObj, endObj, fracJourney);
transform.LookAt(endObjLookAt.transform.position);
}
}
}
private void tweenPos(GameObject startObj, GameObject endObj, float fracJourney) {
Vector3 newposition = Vector3.Lerp(startObj.transform.position, endObj.transform.position, fracJourney);
transform.position = newposition;
}
private void tweenLook(GameObject endObjLookAt, float fracJourney) {
Quaternion newrotation = Quaternion.LookRotation(endObjLookAt.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, newrotation, fracJourney);
}
}
Since what you're trying to achieve implies doing actions one after another, I'd recommend using a Coroutine:
public class testMove : MonoBehaviour
{
public Transform startObj;
public Transform endObj;
private Transform endObjLookAt;
public float rotationDuration;
public AnimationCurve rotationCurve;
public float movementDuration;
public AnimationCurve movementCurve;
private IEnumerator moveAndRotateCameraIEnumerator;
void Start()
{
// If you want to do it on start just call MoveAndRotateCamera() here, else call if from anywhere you want (a script, a game button, ...)
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
MoveAndRotateCamera();
}
}
public void MoveAndRotateCamera(Transform startTransform = null, Transform endTransform = null)
{
if(startTransform)
{
startObj = startTransform;
}
else
{
startObj = this.transform;
}
if(endTransform)
{
endObj = endTransform;
}
endObjLookAt = GameObject.Find(endObj.name + "LookAt").transform;
if(moveAndRotateCameraIEnumerator != null)
{
StopCoroutine(moveAndRotateCameraIEnumerator);
}
moveAndRotateCameraIEnumerator = MoveAndRotateCameraCoroutine();
StartCoroutine(moveAndRotateCameraIEnumerator);
}
private IEnumerator MoveAndRotateCameraCoroutine()
{
//ROTATION
Vector3 startEulerAngles = transform.eulerAngles;
transform.LookAt(endObjLookAt);
Vector3 deltaEulerAngles = new Vector3(Mathf.DeltaAngle(startEulerAngles.x, transform.eulerAngles.x), Mathf.DeltaAngle(startEulerAngles.y, transform.eulerAngles.y), Mathf.DeltaAngle(startEulerAngles.z, transform.eulerAngles.z));
Debug.Log("Starting rotation...");
float timer = 0.0f;
while(timer < rotationDuration)
{
timer += Time.deltaTime;
transform.eulerAngles = startEulerAngles + deltaEulerAngles * rotationCurve.Evaluate(timer / rotationDuration);
yield return new WaitForEndOfFrame();
}
transform.eulerAngles = startEulerAngles + deltaEulerAngles;
Debug.Log("Rotation done!");
//----
//MOVEMENT
Vector3 startPosition = transform.position;
Debug.Log("Starting movement...");
timer = 0.0f;
while(timer < movementDuration)
{
timer += Time.deltaTime;
transform.position = Vector3.Lerp(startPosition, endObj.position, movementCurve.Evaluate(timer / movementDuration));
transform.LookAt(endObjLookAt);
yield return new WaitForEndOfFrame();
}
transform.position = endObj.position;
transform.LookAt(endObjLookAt);
Debug.Log("Movement done!");
//----
}
}
Please note a few things here:
Changed your GameObject variables to Transform ones because you always used them to get to the Transform component so you can use it directly instead
Added a time notion instead of a speed notion for rotation and movement (you can also use speed instead: simply multiply the Time.deltaTime by your speed factor)
Using AnimationCurve allows you to adjust the way the rotation/movement will occur: simply set the curve in Inspector (curve must start at (0, 0) and end at (1, 1))
Hope this helps,

Categories