Now it's rotating twice 360 degrees.
I want it to rotate 360 degrees but only once when clicking with the mouse button.
private void OnMouseDown()
{
if (isRotating == false)
StartCoroutine(Rotate(5));
}
And
IEnumerator Rotate(float duration)
{
Quaternion startRot = transform.rotation;
float t = 0.0f;
while (t < duration)
{
isRotating = true;
t += Time.deltaTime;
transform.rotation = startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up);
yield return null;
}
transform.rotation = startRot;
isRotating = false;
}
Related
I am rotating my camera to lookat a target object using Quaternion. I am using Quaternion.LookRotation and Quaternion.Slerp to make the camera rotate smoothly inside coroutine. Unfortunately the camera jitters a lot when rotating. How do I make the rotation smooth with my current code?
Quaternion targetRotation;
public Transform lookAtObject;
IEnumerator RotateTowardsTarget () {
var duration = 2.0f;
for (float t = 0.0f; t < duration; t += Time.deltaTime) {
targetRotation = Quaternion.LookRotation (lookAtObject.position - transform.position);
transform.rotation = Quaternion.Slerp (transform.rotation, targetRotation, t / duration);
yield return null;
}
}
You currently always start the lerp at the current rotation towards the target.
In your usecase what you rather want to do is store the initial rotation and rather interpolate between the initial and target rotation like
IEnumerator RotateTowardsTarget ()
{
var duration = 2.0;
// store the initial and target rotation once
var startRotation = transform.rotation;
var targetRotation = Quaternion.LookRotation (lookAtObject.position - transform.position);
for (var timePassed = 0.0f; timePassed < duration; timePassed += Time.deltaTime)
{
var factor = timePassed / duration;
// optionally add ease-in and -out
//factor = Mathf.SmoothStep(0, 1, factor);
transform.rotation = Quaternion.Slerp (startRotation, targetRotation, factor);
yield return null;
}
// just to be sure to end up with clean values
transform.rotation = targetRotation;
}
This will make the camera go from the current to the new rotation linear within 2 seconds
Slerp takes third parameter as progress not as actual time you can do this
void Update () {
StartCoroutine(RotateOverTime(transform.rotation,
lookAtObject.rotation, 1f / speed));
}
IEnumerator RotateOverTime (Quaternion originalRotation, Quaternion
finalRotation, float duration) {
if (duration > 0f) {
float startTime = Time.time;
float endTime = startTime + duration;
transform.rotation = originalRotation;
yield return null;
while (Time.time < endTime) {
float progress = (Time.time - startTime) / duration;
// progress will equal 0 at startTime, 1 at endTime.
transform.rotation = Quaternion.Slerp (originalRotation,
finalRotation, progress);
yield return null;
}
}
transform.rotation = finalRotation;
}
You can now send in duration as seconds
I want to move the object up smooth slowly from it's current position on y 50.01 to new position 51.255
But the object keep moving up nonstop.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class RoboSphereWindowBreakInteraction : MonoBehaviour
{
public Transform target;
public AudioClip audioClip;
public float speed;
private bool hasStarted = false;
private Animator anim;
void Update()
{
if ((Input.GetKeyDown(KeyCode.B) || (hasStarted == true)))
{
float step = speed * Time.deltaTime; // calculate distance to move
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
hasStarted = true;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "Square 1")
{
GetComponent<Rigidbody>().isKinematic = false;
hasStarted = false;
Destroy(GameObject.Find("Wall_Window_Long_03"));
}
}
public void ActivateRoboSphere()
{
foreach(Transform child in transform)
{
if(child.name == "Camera")
{
RepositionCamera(child);
}
}
anim = GetComponent<Animator>();
anim.enabled = true;
GetComponent<FPEInteractableActivateScript>().interactionString = "";
FPEInteractionManagerScript.Instance.BeginCutscene();
StartCoroutine(PlayAudio());
}
private void RepositionCamera(Transform camera)
{
var Eyes = GameObject.Find("eyeDome");
camera.position = Eyes.transform.position + Eyes.transform.forward;
camera.LookAt(Eyes.transform);
camera.GetComponent<Camera>().enabled = true;
}
IEnumerator PlayAudio()
{
AudioSource audio = GetComponent<AudioSource>();
audio.clip = audioClip;
audio.Play();
yield return new WaitForSeconds(audio.clip.length);
var rotation = Quaternion.LookRotation(target.position - transform.position);
StartCoroutine(Spin(3f, rotation, () =>
{
anim.SetBool("Roll_Anim", true);
}));
StartCoroutine(MoveFromTo(transform, transform.position, new Vector3(transform.position.x,
transform.position.y + 51.255f, transform.position.z), 3f));
}
IEnumerator Spin(float lerpTime, Quaternion rotation, Action whenDone)
{
float elapsedTime = 0f;
while (elapsedTime <= lerpTime)
{
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, elapsedTime / lerpTime);
elapsedTime += Time.deltaTime;
yield return null;
}
whenDone?.Invoke();
}
// 51.255
IEnumerator MoveFromTo(Transform objectToMove, Vector3 a, Vector3 b, float speed)
{
float step = (speed / (a - b).magnitude) * Time.fixedDeltaTime;
float t = 0;
while (t <= 1.0f)
{
t += step; // Goes from 0 to 1, incrementing by step each time
objectToMove.position = Vector3.Lerp(a, b, t); // Move objectToMove closer to b
yield return new WaitForFixedUpdate(); // Leave the routine and return here in the next frame
}
objectToMove.position = b;
}
}
I did :
StartCoroutine(MoveFromTo(transform, transform.position, new Vector3(transform.position.x,
transform.position.y + 51.255f, transform.position.z), 3f));
But the object keep moving up nonstop. Or at least very high and not like I wanted from 50.01 to 51.255
And when the object reaching the height of 51.255 then I want it to move fast smooth forward to target.
In your code replace this part:
StartCoroutine(MoveFromTo(transform, transform.position, new Vector3(transform.position.x,
transform.position.y + 51.255f, transform.position.z), 3f));
with this:
StartCoroutine(MoveFromTo(transform, transform.position, new Vector3(transform.position.x,
51.255f, transform.position.z), 3f));
I have a 3D object that I want to rotate with mouse/finger swipe, so I made the script below.
The object's rotation looks smooth on editor, but when playing the game on real device (android), the rotation didn't follow the finger movement immediately, it takes some milliseconds to follow finger, it isn't smooth and the controls become hard and frustrating!
float sensitivity = 0.8f;
Vector2 firstPressPos;
Vector2 secondPressPos;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//save began touch 2d point
firstPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButton(0))
{
//save ended touch 2d point
secondPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
if (firstPressPos != secondPressPos)
{
float RotX = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
float RotY = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
transform.RotateAround(Vector3.up, RotX);
transform.RotateAround(Vector3.right, -RotY);
}
}
}
try this code
// Screen Touches
Vector2?[] oldTouchPositions = {
null,
null
};
// Rotation Speed
public float rotSpeed = 0.5f;
public void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
float distanceX = (oldTouchPositions[0] - newTouchPosition).Value.x;
float distanceY = (oldTouchPositions[0] - newTouchPosition).Value.y;
float rotX = distanceX * rotSpeed * Mathf.Deg2Rad;
float rotY = distanceY * rotSpeed * Mathf.Deg2Rad;
transform.Rotate(Vector3.up, rotX * 5, Space.Self);
transform.Rotate(Vector3.left, rotY * 5, Space.Self);
oldTouchPositions[0] = newTouchPosition;
}
}
else
{
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
}
else
{
}
}
}
Here's a script I found a few years back that manipulates X axis spin with Mouse or Touches. It seems to work well with touches, but not as good with Mouse. Try it and let me know if it behaves a bit better. This one should adjust the spinning speed dynamically:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinDrag : MonoBehaviour {
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
}
else if (Input.GetMouseButton(0))
{
f_difX = Mathf.Abs(f_lastX - Input.GetAxis("Mouse X"));
if (f_lastX < Input.GetAxis("Mouse X"))
{
i_direction = -1;
transform.Rotate(Vector3.up, -f_difX);
}
if (f_lastX > Input.GetAxis("Mouse X"))
{
i_direction = 1;
transform.Rotate(Vector3.up, f_difX);
}
f_lastX = -Input.GetAxis("Mouse X");
}
else
{
if (f_difX > 0.5f) f_difX -= 0.05f;
if (f_difX < 0.5f) f_difX += 0.05f;
transform.Rotate(Vector3.up, f_difX * i_direction);
}
}
}
I have implemented various enemies in my game but for now, I'm confronted with a problem when I want to add pre-defined movement to all enemies.
Firstly, the code managing enemies worked fine. The enemies just waited and if the players was too close to him, he attacked.
[SerializeField]
private float rotationSpeed = 180;
[SerializeField]
private float movementSpeed = 1f;
[SerializeField]
private float meshRadius = 1f;
private IEnumerator turnTowardsPlayerCoroutine;
private IEnumerator moveTowardsPlayerCoroutine;
private bool isDead = false;
public float speed = 1;
private int maxLife = 3;
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.tag == "Player")
{
float playerDistance = Vector3.Distance(collider.transform.position, transform.position);
if (playerDistance >= 2f * meshRadius)
{
turnTowardsPlayerCoroutine = TurnTowardsPlayer(collider.transform);
moveTowardsPlayerCoroutine = MoveTowardsPlayer(collider.transform);
StartCoroutine(turnTowardsPlayerCoroutine);
StartCoroutine(moveTowardsPlayerCoroutine);
}
}
}
void OnTriggerExit(Collider collider)
{
if (collider.tag == "Player")
{
float playerDistance = Vector3.Distance(collider.transform.position, transform.position);
if (playerDistance >= 2f * meshRadius)
{
StopCoroutine(turnTowardsPlayerCoroutine);
StopCoroutine(moveTowardsPlayerCoroutine);
}
}
}
void OnDeath()
{
if (isDead)
{
return;
}
maxLife--;
if (maxLife <= 0)
{
isDead = true;
GameManager.Instance.NumKilledEnemies++;
StopCoroutine(turnTowardsPlayerCoroutine);
StopCoroutine(moveTowardsPlayerCoroutine);
Destroy(gameObject);
}
}
private IEnumerator TurnTowardsPlayer(Transform player)
{
while (true)
{
Quaternion targetRotation = Quaternion.LookRotation(player.position - transform.position, Vector3.up);
targetRotation.x = 0f;
targetRotation.z = 0f;
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
yield return 0;
}
}
private IEnumerator MoveTowardsPlayer(Transform player)
{
while (true)
{
Vector3 playerDirection = transform.position - player.position;
playerDirection.y = 0;
playerDirection = playerDirection.normalized;
Vector3 deltaMovement = playerDirection * movementSpeed * Time.deltaTime;
int layermask = LayerMask.GetMask("Environment");
Vector3 movingTowards = transform.position - playerDirection * meshRadius + (new Vector3(0f, 0.1f, 0f));
if (Physics.Raycast(movingTowards, Vector3.down, 0.25f, layermask))
{
transform.position -= deltaMovement;
}
yield return 0;
}
}
But after that, I wanted to add a predefined movement of enemies if nobody is close to him so I did something like this :
private IEnumerator moveDefaultCoroutine;
void Start()
{
moveDefaultCoroutine = MoveToPosition(new Vector3(transform.position.x, transform.position.y, transform.position.z + 3), 5);
StartCoroutine(moveDefaultCoroutine);
}
private IEnumerator MoveToPosition(Vector3 newPosition, float time)
{
while (true)
{
float elapsedTime = 0;
Vector3 startingPos = transform.position;
while (elapsedTime < time)
{
transform.position = Vector3.Lerp(startingPos, newPosition, (elapsedTime / time));
elapsedTime += Time.deltaTime;
yield return null;
}
yield return new WaitForSeconds(2);
elapsedTime = 0;
while (elapsedTime < 0.8)
{
transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, new Vector3(0, 180, 0), (elapsedTime / 0.8f));
elapsedTime += Time.deltaTime;
yield return null;
}
elapsedTime = 0;
while (elapsedTime < time)
{
transform.position = Vector3.Lerp(newPosition, startingPos, (elapsedTime / time));
elapsedTime += Time.deltaTime;
yield return null;
}
yield return new WaitForSeconds(2);
elapsedTime = 0;
while (elapsedTime < 0.8)
{
transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, new Vector3(0, 0, 0), (elapsedTime / 0.8f));
elapsedTime += Time.deltaTime;
yield return null;
}
}
}
And here come the problem, when I'm adding this code the enemies disappear randomly... Did I did something wrong ?
Full code here : http://pastebin.com/tzGczv26
Thanks per advance !
PokeRwOw
This game I create that the characters is moving to right only by following the cursor. I want like Feeding Frenzy, when I moving the mouse the characters will follow the cursors and when it press short left click the character have more speed.
The problem in my code is when I press long left click, the character also going faster.
this is my code:
//variable for moving characters
public float moveSpeed;
public float turnSpeed;
private Vector3 moveDirection;
//variable for detect short/long click
private float t0;
private bool longClick;
private bool shortClick;
void Start ()
{
moveDirection = Vector3.right;
t0 = 0f;
longClick = false;
shortClick = false;
}
void Update ()
{
// code to moving my characters (moving to right only)
Vector3 currentPosition = transform.position;
Vector3 moveToward = Camera.main.ScreenToWorldPoint( Input.mousePosition );
moveDirection = moveToward - currentPosition;
moveDirection.z = 0;
moveDirection.Normalize();
if (moveDirection.x <= 0)
{
moveDirection = Vector3.right;
}
Quaternion rot = Quaternion.LookRotation (transform.position - moveToward, Vector3.forward);
rot *= Quaternion.Euler (0, 0, 90);
transform.rotation = rot;
transform.eulerAngles = new Vector3 (0, 0, transform.eulerAngles.z);
Vector3 target = moveDirection * moveSpeed + currentPosition;
transform.position = Vector3.Lerp( currentPosition, target, Time.deltaTime );
float targetAngle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Slerp( transform.rotation,
Quaternion.Euler( 0, 0, targetAngle ),
turnSpeed * Time.deltaTime );
//THIS IS MY PROBLEM!
//IN MY CODE BELOW, WHEN I PRESS LONG CLICK IT HAVE moveSpeed=12.
//I WANT moveSpeed = 12 WHEN I PRESS SHORT CLICK ONLY
if (Input.GetMouseButtonDown (0))
{
t0 = Time.time;
moveSpeed = 12;
}
else if (Input.GetMouseButtonUp(0) && (Time.time - t0) > 0.5f)
{
longClick = true;
moveSpeed = 3;
}
else if (Input.GetMouseButtonUp(0) && (Time.time - t0) < 0.5f)
{
shortClick = true;
moveSpeed = 3;
}
longClick = false;
shortClick = false;
}
function Update()
{
longClick = false; //Remove this
shortClick = false; //Remove this
if ( Input.GetMouseButtonDown (0) )
{
t0 = Time.time ;
longClick = false;
shortClick = false;
}
if ( Input.GetMouseButtonUp(0) (Time.time - t0) < 0.2 )
{
longClick = false;
shortClick = true;
}
if ( Input.GetMouseButtonUp(0) (Time.time - t0) > 0.2 )
{
longClick = true;
shortClick = false;
}
//Process Movement
}
And then use if(longclick) or if(shortClick) to do your speed. When there is a short click, the character moves fast and in the next update, the character goes back to the same speed. If you want the character to continue moving in same speed till it gets the next click, then remove the lines right after update.
process the character movement after the longClick and shortClick is set.