bool flying = false; // shows when FlyTo is running
// coroutine that moves to the specified point:
IEnumerator FlyTo(Vector3 targetPos)
{
flying = true; // flying is true while moving to the target
Vector3 startPos = transform.position;
Vector3 dir = targetPos - startPos;
float distTotal = dir.magnitude;
dir /= distTotal; // normalize vector dir
// calculate accDist even for short distances
float accDist = Mathf.Min(accDistance, distTotal / 2);
do
{
float dist1 = Vector3.Distance(transform.position, startPos);
float dist2 = distTotal - dist1;
float speed = maxVel; // assume cruise speed
if (dist1 < accDist)
{ // but if in acceleration range...
// accelerate from startVel to maxVel
speed = Mathf.Lerp(startVel, maxVel, dist1 / accDist);
}
else
if (dist2 < accDist)
{ // or in deceleration range...
// fall from maxVel to stopVel
speed = Mathf.Lerp(stopVel, maxVel, dist2 / accDist);
}
// move according to current speed:
transform.position = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
yield return 0; // let Unity breathe till next frame
} while (transform.position != targetPos); // finish when target reached
flying = false; // shows that flight has finished
}
The problem is if for example the transform is at height 200 in the start when it's getting to the targetPos it's in height 0.
But i want it to get to the targetPos above it in the same height not on height 0. It does not matter what it will do when it's getting to the targetPos but what i want is that it will get there at the same height level.
This is the full script:
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour
{
public float maxVel = 30; // cruise speed
public float startVel = 5; // speed at the starting point
public float stopVel = 0.5f; // speed at the destination
public float accDistance = 20; // acceleration/deceleration distance
public float factor = 0.25f; // max inclination
public float turnSpeed = 0.8f; // speed to turn/bank in the target direction
Vector3 lastPos; // used to calculate current velocity
Transform baseTarget;
private Rigidbody _rigidbody;
void Start()
{
_rigidbody = GetComponent<Rigidbody>();
baseTarget = GameObject.Find("Base").transform;
lastPos = transform.position;
StartCoroutine(Fly()); // demo routine
}
// calculate bank/turn rotation at Update
void Update()
{
// calculate the displacement since last frame:
Vector3 dir = transform.position - lastPos;
lastPos = transform.position; // update lastPos
float dist = dir.magnitude;
if (dist > 0.001f)
{ // if moved at least 0.001...
dir /= dist; // normalize dir...
float vel = dist / Time.deltaTime; // and calculate current velocity
// bank in the direction of movement according to velocity
Quaternion bankRot = Quaternion.LookRotation(dir + factor * Vector3.down * vel / maxVel);
Vector3 rotation = Quaternion.Lerp(transform.rotation, bankRot, turnSpeed * Time.deltaTime).eulerAngles;
rotation.x = 0;
transform.rotation = Quaternion.Euler(rotation);
}
}
bool flying = false; // shows when FlyTo is running
// coroutine that moves to the specified point:
IEnumerator FlyTo(Vector3 targetPos)
{
flying = true; // flying is true while moving to the target
Vector3 startPos = transform.position;
Vector3 dir = targetPos - startPos;
float distTotal = dir.magnitude;
dir /= distTotal; // normalize vector dir
// calculate accDist even for short distances
float accDist = Mathf.Min(accDistance, distTotal / 2);
do
{
float dist1 = Vector3.Distance(transform.position, startPos);
float dist2 = distTotal - dist1;
float speed = maxVel; // assume cruise speed
if (dist1 < accDist)
{ // but if in acceleration range...
// accelerate from startVel to maxVel
speed = Mathf.Lerp(startVel, maxVel, dist1 / accDist);
}
else
if (dist2 < accDist)
{ // or in deceleration range...
// fall from maxVel to stopVel
speed = Mathf.Lerp(stopVel, maxVel, dist2 / accDist);
}
// move according to current speed:
Vector3 pos = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
pos.y = lastPos.y;
transform.position = pos;
yield return 0; // let Unity breathe till next frame
} while (transform.position != targetPos); // finish when target reached
flying = false; // shows that flight has finished
}
// example routine: fly to 3 different points in sequence
IEnumerator Fly()
{
Vector3 p0 = baseTarget.position;
while (true)
{
StartCoroutine(FlyTo(p0));
while (flying)
{
yield return 0;
}
yield return new WaitForSeconds(5);
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "Base")
{
}
}
}
As stated in my comments, don't update the position twice, this will cause an overhead, easily avoidable by changing the Target's Y coordinate BEFORE the loop.
IEnumerator FlyTo(Vector3 targetPos)
{
flying = true; // flying is true while moving to the target
Vector3 startPos = transform.position;
//Insert this line right here.
targetPos.y = startPos.y;
Vector3 dir = targetPos - startPos;
//The rest of your code remains the same...
Find this line, inside your DO, near the end and remove it
Vector3 pos = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
//pos.y = lastPos.y; ~ REMOVE THIS LINE~
assuming that Y is the height axis, maybe its actually Z axis,try it out.
Related
I'm working on a 3D fps, and want a dash. The player uses a character controller, and no rigidbody. My original implementation:
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength ) //dashes for a set time period
{
currentDashLength += Time.deltaTime;
velocity.y = 0; //keeps you up in the air
controller.Move(move * Time.deltaTime * dashSpeed);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
This dash works fine, but I realized that if you had pressed shift right after starting to move, the dash would be significantly weaker. I assumed this was due to the fact that my current velocity was low, so the acceleration from the Move function didn't make me reach the speed I would when already moving at terminal velocity. I tried to fix this by multiplying the Move function inputs by 1/(the horizontal velocity of the player) but this didn't fix the issue. My full dashing code:
float dispX = transform.position.x - posX; //gets chnage in position since last frame, this is important to caluclate velocity, since the player isnt using a rigidbody
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
if(horizontalVelocity == 0)
{
Debug.Log("Cannot dash while standing still");
}
else
{
controller.Move(move * Time.deltaTime * dashSpeed * (1 / horizontalVelocity));
}
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
How would I go about ensuring that the dash speed is constant?
(I tried to post this on unity answers, but the website isn't responding to me)
To get the desired behaviour I have re-written your original script by quite a lot, hope that is okay! This code only give you movement and dash control, and nothing else. You'll have to add your crouch check and health stuff back in.
Essentially, we check if the player is dashing before applying any movement, this way we don't add the dash to the current movement. If the player is dashing, we ignore their forward input and apply forward movement based on the predetermined dash. If we aren't dashing then we apply the calculated movement as usual.
private CharacterController controller;
public float speed = 10.0f;
public float dashSpeed = 20.0f;
public float dashLength = 0.5f;
private float currentDashLength = 0;
private bool isDashing = false;
private void Start()
{
controller = GetComponent<CharacterController>();
}
private void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
// Same as before
Vector3 move = new Vector3(x, 0, z);
// gets the move direction
// before we move, check if dashing
if (isDashing)
{
currentDashLength += Time.deltaTime;
move = new Vector3(move.x * dashSpeed, move.y, 1 * dashSpeed);
// this gets the current player movement, and replaces the forward velocity rather than adding to it. We add to the sideways velocity to allow for slight directional control.
// do this instead if you want the dash to only move the player in the forward direction, and prevent strafing: move = new Vector3(move.x, move.y, 1 * dashSpeed);
if (currentDashLength >= dashLength) // when we run out of time, set dash to false
{
isDashing = false;
}
}
else // if we are not dashing then move as normal
{
move *= speed;
if (Input.GetKeyDown(KeyCode.LeftShift) && move.magnitude > 0) // stops the dash ability being used when stationary
{
isDashing = true;
currentDashLength = 0;
}
}
controller.Move(move * Time.deltaTime);
}
float dispX = transform.position.x - posX;
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
Vector3 dashMove = move * Time.deltaTime * dashSpeed; // Calculates the dash movement vector
// Move the player based on the dash movement vector
controller.Move(dashMove);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
By calculating the dash movement vector independently from the player's horizontal velocity, you can ensure that the dash speed remains constant regardless of whether the player is moving before dashing or not.
I think this is what you were trying to achieve? Hope it helps!
How to make a bullet fly in an arc when shooting and hit the player.
As in this picture . I tried to use formulas from physics, the body is thrown at an angle to the horizon, that's what came of it . But the bullet flies away into the void
velocity = Mathf.Round(Vector3.Distance(lastpos, transform.position) / Time.deltaTime);
lastpos = transform.position;
Vector3 direction = PlayeCar.position - Vector3.zero;
float angle = Mathf.Atan2(direction.y, direction.x); // радианы
float x = velocity * Mathf.Cos(angle) + gravity * (time* time) / 2;
float y = velocity * Mathf.Sin(angle);
transform.position = new Vector2(x, y)
;
Sample orientative method could be (The script would be attached to the gun that shots, so when the code referes to transform, refers to the gun's transfom):
public void LaunchTarget()
{
Vector3 initialSpeed = transform.forward; //shot direction, gun's forward
GameObject go = GameObject.Instantiate(m_bullet);//reference to bullet prefab
//in case you need to randomize the shot speed
initialSpeed = transform.forward * Random.Range(m_minLaunchSpeed, m_maxLaunchSpeed);
//set the initial position of the bullet in the gun
go.transform.position = transform.position;
// shoot (give speed to the bullets rigidbody)
go.GetComponent<Rigidbody>().velocity = initialSpeed;
//initially disabled soas to see the bullet when shot
go.SetActive(true);
}
Hope that helps
I did it !!!! at the time of the bullet’s flight, I turn it toward the player in an intermittent manner. And after a while I delete it
void Start()
{
rigidbodyBullet = GetComponent<Rigidbody2D>();
Player = GameObject.Find("carPlayer").GetComponent<Transform>();
_distance = Vector3.Distance(Player.position, transform.position);
Invoke("DestroyArcBullet", 1.5f);
limitDistance = _distance / 1.3f;
}
void Update()
{
transform.position += transform.up * Time.deltaTime * 5f;
_distance = Vector3.Distance(Player.position, transform.position);
if (_distance < limitDistance)
{
var turn = Quaternion.Lerp(transform.rotation,
Quaternion.LookRotation(Vector3.forward, Player.position - transform.position), Time.deltaTime * 2);
rigidbodyBullet.MoveRotation(turn.eulerAngles.z);
}
if (this.transform.position.y + this.transform.position.y <= -10 || this.transform.position.y + this.transform.position.y >= 10
|| this.transform.position.x + this.transform.position.x <= -10 || this.transform.position.x + this.transform.position.x >= 10)
{
Destroy(gameObject);
}
}
I am trying to rotate a GameObject along z-axis using Joystick, but its rotating y-axis. I might missed some math calculation. Any Help??
Reference Image
void FixedUpdate()
{
// get input from joystick
// get input from joystick
rightJoystickInput = rightJoystick.GetInputDirection();
float xMovementRightJoystick = rightJoystickInput.x; // The horizontal movement from joystick 02
float zMovementRightJoystick = rightJoystickInput.y; // The vertical movement from joystick 02
// if there is only input from the right joystick
if (rightJoystickInput != Vector3.zero)
{
// calculate the player's direction based on angle
float tempAngle = Mathf.Atan2(zMovementRightJoystick, xMovementRightJoystick);
xMovementRightJoystick *= Mathf.Abs(Mathf.Cos(tempAngle));
zMovementRightJoystick *= Mathf.Abs(Mathf.Sin(tempAngle));
// rotate the player to face the direction of input
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
if (lookDirection != Vector3.zero)
{
rotationTarget.localRotation = Quaternion.Slerp(rotationTarget.localRotation, Quaternion.LookRotation(lookDirection) * Quaternion.Euler(0, 45f, 0), rotationSpeed * Time.deltaTime);
}
}
}
You don't need most of the code in your question and this is really simple.
1.Find the angle with Mathf.Atan2 then multiple it with Mathf.Rad2Deg.
2.Use Quaternion.Euler(new Vector3(0, 0, angle)) to get the rotation then apply it to the Object.
This should be one in the Update function not FixedUpdate because FixedUpdate is used to move Rigidbody Objects.
public Transform rotationTarget;
public bool flipRot = true;
void Update()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
If using Rigidbody2D then use Rigidbody2D.MoveRotation in the FixedUpdate function. The rest of the code stays the-same.
public Rigidbody2D rg2d;
public bool flipRot = true;
void FixedUpdate()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
EDIT:
But only the problem is when i leave joystick its rotation is setting
to 0 instantly which looks too odd. How can i fix it?
You have to detect when you release the joystick in OnPointerUp then slowly lerp the joystick thump back to the Zero position. You also have to lerp the current target object angle to zero or to its default value and this should be done in a coroutine function. When OnPointerDown is called, stop the current coroutine function. Prevent the code in FixedUpdate from running when finger is released so that it won't interfere with the coroutine function.
For the sake of completeness, below is the combination of a Joystick code and the Rigidbody answer above:
public class VirtualJoystickController : MonoBehaviour,
IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
public float mas_distance = 7f;
void Start()
{
bgImg = GameObject.Find("JoystickBGImage").GetComponent<Image>(); // the joysticks background
joystickImg = GameObject.Find("Joystickthumb").GetComponent<Image>(); // the joystick object to use
}
private Vector3 _inputDirection = Vector3.zero;
//the movementDirection
public Vector3 joystickInputDirection
{
set
{
//Change only if value is different from old one
if (_inputDirection != value)
{
_inputDirection = value;
Debug.Log("Dir: " + _inputDirection);
}
}
get
{
return _inputDirection;
}
}
public void OnDrag(PointerEventData eventData)
{
dragJoyStick(eventData);
}
void dragJoyStick(PointerEventData eventData)
{
Vector3 tempDir = Vector3.zero;
Vector2 pos = Vector2.zero;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle
(bgImg.rectTransform,
eventData.position,
eventData.pressEventCamera,
out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y);
float x = (bgImg.rectTransform.pivot.x == 1) ? pos.x * 2 + 1 : pos.x * 2 - 1;
float y = (bgImg.rectTransform.pivot.y == 1) ? pos.y * 2 + 1 : pos.y * 2 - 1;
tempDir = new Vector3(x, y, 0);
if (tempDir.magnitude > 1)
{
tempDir = tempDir.normalized;
}
joystickImg.rectTransform.anchoredPosition = new Vector3(
tempDir.x * (bgImg.rectTransform.sizeDelta.x / mas_distance),
tempDir.y * (bgImg.rectTransform.sizeDelta.y / mas_distance));
joystickInputDirection = tempDir;
}
}
public void OnPointerDown(PointerEventData eventData)
{
released = false;
//Stop current coroutine
if (retCoroutine != null)
StopCoroutine(retCoroutine);
if (eventData.pointerCurrentRaycast.gameObject == bgImg.gameObject ||
eventData.pointerCurrentRaycast.gameObject == joystickImg.gameObject)
{
OnDrag(eventData);
}
}
public void OnPointerUp(PointerEventData eventData)
{
released = true;
//Stop current coroutine then start a new one
if (retCoroutine != null)
StopCoroutine(retCoroutine);
retCoroutine = StartCoroutine(SlowReturn(returnTime));
}
IEnumerator SlowReturn(float duration)
{
RectTransform thumbstickTransform = joystickImg.rectTransform;
Vector3 toPosition = Vector3.zero;
float counter = 0;
//Get the current position of the object to be moved
Vector2 currentThumb = thumbstickTransform.anchoredPosition;
while (counter < duration)
{
counter += Time.deltaTime;
//Slowly returns thumbstick
Vector2 tempThumbStickVal = Vector2.Lerp(currentThumb, toPosition, counter / duration);
joystickInputDirection = tempThumbStickVal;
thumbstickTransform.anchoredPosition = tempThumbStickVal;
//Slowly returns the target Object to original pos
float tempTargetObjAngle = Mathf.Lerp(angle, originalAngle, counter / duration);
rg2d.MoveRotation(tempTargetObjAngle);
yield return null;
}
}
public float returnTime = 1.0f;
public Rigidbody2D rg2d;
public bool flipRot = true;
const float originalAngle = 0;
bool released = true;
float angle;
Coroutine retCoroutine;
void FixedUpdate()
{
if (released)
return;
float horizontal = joystickInputDirection.x;
float vertical = joystickInputDirection.y;
angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
}
your function calculates a point where you want to look at:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
this point is on the XZ plane, that is why the car rotates on Y axis
if you want to rotate on Z axis, calculate a point on XY plane like this:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.y += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
PS: i don't know why you multiply with Quaternion.Euler(0, 45f, 0) - that is a constant angle on Y axis, it just means that each lookDirection will be rotated for 45 degrees - i would have to see your scene to know why you need this...
This is my previous question: Previous question
The answer there was right and working.
Once the gameobject start entering the other gameobject area it does something.
This is the script i attached to the moving gameobject that check for colliding:
using UnityEngine;
public class CheckBaseCollider : MonoBehaviour
{
public GameObject baseCollider;
public GameObject objectToRotate;
public bool rotate = false;
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == baseCollider)
{
Debug.Log("Entered");
rotate = true;
}
}
private void Update()
{
if (rotate == true)
{
var str = Mathf.Min(.5f * Time.deltaTime, 1);
objectToRotate.transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.identity, str);
}
}
}
I have two gameobjects. One is the Base(A Cube it's variable is baseTarget).
The "Base" is on the terrain.
I want that when the other GameObject that move start entering the "Base" it will also start to rotate. But for some reason the rotation start then stop and then after some seconds resume and finish. Not sure why it stop.
This is the script of the moving gameobject also attached to the moving gameobject:
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour
{
public float maxVel = 30; // cruise speed
public float startVel = 5; // speed at the starting point
public float stopVel = 0.5f; // speed at the destination
public float accDistance = 20; // acceleration/deceleration distance
public float factor = 0.25f; // max inclination
public float turnSpeed = 0.8f; // speed to turn/bank in the target direction
Vector3 lastPos; // used to calculate current velocity
Transform baseTarget;
private Rigidbody _rigidbody;
void Start()
{
_rigidbody = GetComponent<Rigidbody>();
baseTarget = GameObject.Find("Base").transform;
lastPos = transform.position;
StartCoroutine(Fly()); // demo routine
}
// calculate bank/turn rotation at Update
void Update()
{
// calculate the displacement since last frame:
Vector3 dir = transform.position - lastPos;
lastPos = transform.position; // update lastPos
float dist = dir.magnitude;
if (dist > 0.001f)
{ // if moved at least 0.001...
dir /= dist; // normalize dir...
float vel = dist / Time.deltaTime; // and calculate current velocity
// bank in the direction of movement according to velocity
Quaternion bankRot = Quaternion.LookRotation(dir + factor * Vector3.down * vel / maxVel);
Vector3 rotation = Quaternion.Lerp(transform.rotation, bankRot, turnSpeed * Time.deltaTime).eulerAngles;
rotation.x = 0;
transform.rotation = Quaternion.Euler(rotation);
}
}
bool flying = false; // shows when FlyTo is running
// coroutine that moves to the specified point:
IEnumerator FlyTo(Vector3 targetPos)
{
flying = true; // flying is true while moving to the target
Vector3 startPos = transform.position;
targetPos.y = startPos.y;
Vector3 dir = targetPos - startPos;
float distTotal = dir.magnitude;
dir /= distTotal; // normalize vector dir
// calculate accDist even for short distances
float accDist = Mathf.Min(accDistance, distTotal / 2);
do
{
float dist1 = Vector3.Distance(transform.position, startPos);
float dist2 = distTotal - dist1;
float speed = maxVel; // assume cruise speed
if (dist1 < accDist)
{ // but if in acceleration range...
// accelerate from startVel to maxVel
speed = Mathf.Lerp(startVel, maxVel, dist1 / accDist);
}
else
if (dist2 < accDist)
{ // or in deceleration range...
// fall from maxVel to stopVel
speed = Mathf.Lerp(stopVel, maxVel, dist2 / accDist);
}
// move according to current speed:
Vector3 pos = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
//pos.y = lastPos.y;
transform.position = pos;
yield return 0; // let Unity breathe till next frame
} while (transform.position != targetPos); // finish when target reached
flying = false; // shows that flight has finished
}
// example routine: fly to 3 different points in sequence
IEnumerator Fly()
{
Vector3 p0 = baseTarget.position;
while (true)
{
StartCoroutine(FlyTo(p0));
while (flying)
{
yield return 0;
}
yield return new WaitForSeconds(5);
}
}
}
This is what I try to do, When I click on a UI Element, the camera smoothly rotate (to look at the target) and simultaneously move on top of the target.
To perform that I use a two Coroutine one for the Lerp Position and the other one for the Slerp Rotation.
The issue is that the rotation doesn't work correctly, normally the camera should look down to see the top of the target but instead of doing this it look like the Camera first look at the target and after that move to his position.
I hope this is understandable ;)
Here is the code c#
Vector3 LocationProjectForPos = new Vector3(Loc_X, 100, Loc_Z);
Vector3 LocationProjectForRot = new Vector3(Loc_X, Loc_Y, Loc_Z);
Vector3 MainCameraPos = MainCamera.transform.position;
if(!IsCameraMoving & LocationProjectForPos != MainCameraPos)
{
StartCoroutine (CoroutineMovePositionCamera(LocationProjectForPos));
StartCoroutine (CoroutineMoveRotationCamera(LocationProjectForRot));
}
}
Moving the position of the Camera with Lerp
public IEnumerator CoroutineMovePositionCamera(Vector3 LocationProject)
{
float lerpTime = 5f;
float currentLerpTime = 0f;
IsCameraMoving = true;
Vector3 startPos = MainCamera.transform.localPosition;
Vector3 endPos = LocationProject;
while (lerpTime > 0)
{
lerpTime -= Time.deltaTime;
currentLerpTime += Time.deltaTime;
if (currentLerpTime > lerpTime)
{
currentLerpTime = lerpTime;
}
float t = currentLerpTime / lerpTime;
t = t*t*t * (t * (6f*t - 15f) + 10f);
//t = t*t * (3f - 2f*t);
//t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f);
MainCamera.transform.localPosition = Vector3.Lerp(startPos, endPos, t);
yield return null;
}
IsCameraMoving = false;
}
Rotate the Camera with Slerp
public IEnumerator CoroutineMoveRotationCamera(Vector3 LocationProject)
{
float lerpTime = 5f;
float currentLerpTime = 0f;
IsCameraMoving = true;
Vector3 relativePos = LocationProject - MainCamera.transform.localPosition;
Quaternion rotation = Quaternion.LookRotation(relativePos);
Quaternion current = MainCamera.transform.localRotation;
while (lerpTime > 0)
{
lerpTime -= Time.deltaTime;
currentLerpTime += Time.deltaTime;
if (currentLerpTime > lerpTime)
{
currentLerpTime = lerpTime;
}
float t = currentLerpTime / lerpTime;
t = t*t*t * (t * (6f*t - 15f) + 10f);
//t = t*t * (3f - 2f*t);
//t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f);
MainCamera.transform.localRotation = Quaternion.Slerp(current, rotation, t);
yield return null;
}
IsCameraMoving = false;
}
Thanks for your help.
In CoroutineMoveRotationCamera, you need to update the relativePostion and rotation inside the while loop.
The relative position is changing while the camera is moving. Right now, your camera rotates based on the vector snapshot you took before the while loop started.
Add the following code after yield statement.
relativePos = LocationProject - Camera.main.transform.position;
rotation = Quaternion.LookRotation(relativePos);
before start coroutine, you should save the initial vars with member vars instead of function local vars