this may be a dumb question...
I have two variables and I am setting them to serial data that continuosly changes (from an arduino), just at different times. Then, I am comparing them with each other to see if an object (The IKTarget) should move forwards or backwards(in unity).
Below is my code:
void Start() {
//Starting a new coroutine
StartCoroutine(VariableSetter());
}
//Using that corouting
IEnumerator VariableSetter() {
//Setting the first variable to the serialdata
controllerfinger1_Angle = SerialDataDecoder.finger1_Angle;
//Waiting 20ms
yield return new WaitForSeconds(0.02f);
//Setting the other variable to the serialdata
newcontrollerfinger1_Angle = SerialDataDecoder.finger1_Angle;
}
void Update() {
//Making the finger movement frame dependent
amountToMove = speed * Time.deltaTime; */
//If the finger angle is increasing
if (newcontrollerfinger1_Angle > controllerfinger1_Angle)
{
//Move the IKTarget fowards (Closes the finger)
IKTarget.Translate(Vector3.forward * amountToMove, Space.World);
}
//If the finger angle is decreasing
if (newcontrollerfinger1_Angle < controllerfinger1_Angle)
{
//Move the IKTarget backwards (Opens up the finger)
IKTarget.Translate(Vector3.back * amountToMove, Space.World);
}
}
When I run this in unity, the IKTarget object doesnt seem to want to move.
I KNOW my SerialData is correct as I have checked.
If anybody could provide an answer for this issue, it would be greatly appreciated.
Thanks,
Isaac.
Related
I'm trying to make a camera track two targets in a 2D game on unity but I can't quite get it to work.
This is the code I currently have, but it's changing the rotation in transform instead of position. the ortho size is changing but it is not properly tracking the center point between the characters. is there anyway I can fix this?
using System.Collections.Generic;
using UnityEngine;
public class CameraZoom : MonoBehaviour
{
private Camera cameraRef;
private GameObject[] playerPos;
void Start()
{
cameraRef = GetComponent<Camera>();
playerPos = GameObject.FindGameObjectsWithTag("Player");
Debug.Log(playerPos[0].transform.position);
Debug.Log(playerPos[1].transform.position);
Debug.Log(cameraRef.tag);
StartCoroutine(ZoomInOut());
}
// Update is called once per frame
void Update()
{
}
IEnumerator ZoomInOut()
{
while (true)
{
if (playerPos[0] != null && playerPos[1] != null)
{
Vector3 lookPoint = Vector3.Lerp(playerPos[0].transform.position, playerPos[1].transform.position, 0.5f);
cameraRef.transform.LookAt(lookPoint);
float distance = Vector3.Distance(playerPos[0].transform.position, playerPos[1].transform.position);
if (distance > (cameraRef.orthographicSize * 2))
{
cameraRef.orthographicSize += 0.05f;
// if (distance < (cameraRef.orthographicSize * 2))
//{
// cameraRef.orthographicSize -= 0.1f;
//}
}
else
if (distance < (cameraRef.orthographicSize))
{
cameraRef.orthographicSize -= 0.05f;
}
yield return new WaitForSeconds(0.02f);
}
}
}
}
Well cameraRef.transform.LookAt does exactly what you described
Rotates the transform so the forward vector points at worldPosition.
Since your game is 2D anyway what you rather want to do is set the camera to exactly the same XY position
var lookPoint = (playerPos[0].transform.position, playerPos[1].transform.position) * 0.5f;
//Maintain the Z depth position
lookPoint.z = cameraRef.transform.position.z;
cameraRef.transform.position = lookPoint;
Also instead of
yield return new WaitForSeconds(0.02f);
rather use
yield return null;
The latter makes it run every frame. But anyway assuming 60FPS a frame takes about 0.017seconds so waiting0.02` will most probably mean you wait two frames since this value is not the exact time but rather the minimum time to wait/skip to the next frame.
And move this OUT of the if block!!
If one of your objects is missing => endless loop -> Freeze/Crash of Unity and your app! You definitely want to wait one frame for every iteration of your while loop!
Actually you could as well do the thing in Update without the loop at all :)
And then instead of
cameraRef.orthographicSize -= 0.05f;
I would rather either use
// Take differences in the frame rate into account (jitter)
cameraRef.orthographicSize -= 3 * Time.deltaTime;
or directly interpolate
// Smooth interpolate -> if the target and current value are far apart
// this zooms faster and then becomes slower when already very close
// Adjust that "5" according to your needs
cameraRef.orthographicSize = Mathf.Lerp(cameraRef.orthographicSize, distance, 5 * Time.deltaTime);
without using your conditions at all.
Typed on the phone but I hope the idea gets clear
So, Hey guys. Im new to Unity and Im trying a very simple code that allows the player to Zoom-in & Zoom-Out. Here's the code of it:
[Header("Vertical Zooming")]
[SerializeField] private float zoomSpeed;
private void Update()
{
VerticalZooming();
}
private void VerticalZooming()
{
Vector3 initialPosition = new Vector3();
// bool canMove = false;
if (Input.GetMouseButtonDown(0))
{
initialPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Debug.Log(initialPosition.y);
}
if (Input.GetMouseButton(0))
{
Vector3 newPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Debug.Log("newPosition" + newPosition.y);
if (newPosition.y < initialPosition.y)
{
Zoom((zoomSpeed * Time.deltaTime) * -1f);
}
if (newPosition.y > initialPosition.y)
{
Zoom(zoomSpeed * Time.deltaTime);
}
intialPosition = newPosition;
}
}
private void Zoom(float inZoomSpeed)
{
transform.Translate(mCamRef.transform.position.z * inZoomSpeed * transform.forward);
}
So, if you see the code above. On mousebuttondown we note down the initial position and on holding the mouse button we keep track of new position constantly.. What i want is pretty simple. With reference to my initial mouse click im checking if my new position is greater in y is yes i need to zoom out. If new position is lower than initial position in y-axis. Them, i need to zoom in. Which I did, But for some reason its not working.
Two problems here:
Though if there is no change to newposition i.e., even if both my newposition variable and initial position variable are in same spot my camera moves(Zoom-out in my case) which shouldn't happen. It should only happen if my newPosition.y variable is greater that that of initialposition.y. I'm not able to figure out why this is happening. I tried using bool conditions to do this, but failed.
If i play test this in my mobile.. Its only going on one direction. in my case its only zooming out continously though my zoom-in if-condition meets. But when playtesting in unity game window. The zoom in works when my mouse is out of the game-screen. Because its only working outside the game screen.This is the reason its not working in mobile as there is no space outside mobile display. Which i dont know why this is happening or dont know how to overcome this.
Let me know why! Im stuck at it for a long time and not getting any idea. Thanks <3
If Any doubt in question let me know. Sorry for a huge explanation. Just wanted to be very precise on the question.
I have seen people suggesting zoom in zoom out through using FOV. But i wanna do it using translate or move the camera itself.
So your problem here is on taking count on the screenToViewPort point.
Instead just try this..
if (Input.GetMouseButtonDown(0))
{
mInitialPosition = Input.mousePosition.y;
}
if (Input.GetMouseButton(0))
{
mChangedPosition = Input.mousePosition.y;
if (mChangedPosition == mInitialPosition)
{
return;
}
if (mChangedPosition < mInitialPosition)
{
Zoom((mZoomSpeed * -1f) * Time.deltaTime);
}
if (mChangedPosition > mInitialPosition)
{
Zoom(mZoomSpeed * Time.deltaTime);
}
}
private void Zoom(float inZoomSpeed)
{
transform.Translate(mCamRef.transform.position.z * inZoomSpeed * transform.forward);
}
Not sure how ScreenToViewport point works... But I guess this code should do the magic for you... Here I'm just straight away taking the mouse.y value on click and hold and did the same functions as you did and also telling it not to do anything when both the y values are same and return the function... So meaning that you already had everything in your code itself... Have a nice day
i want to make a simple script that when u clicked the screen the ball in the game will move (20000 * Time.deltaTime) to the right, and then if i'll click again, it will move to the left side and then right and so on.
I managed to get the ball to move to the right, but i need it to wait after the animation is finish because i need to check if the player clicked again (if he did i need to check to what direction to move the ball).
I tried many methods i found online like checking if Rigidbody.velocity.magnitude == 0.0f that means the ball is not moving..
public Rigidbody rb;
public Transform PlayerPosition;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
rb.AddForce(20000 * Time.deltaTime, 0, 0); // moving ball to the right
while (rb.velocity.magnitude != 0.0f) // I tried to check until the ball is not moving
{
}
Debug.Log(PlayerPosition.position.x);
}
}
And here is my latest try:
void Update()
{
if (Input.GetMouseButtonDown(0))
{
rb.AddForce(20000 * Time.deltaTime, 0, 0); // moving ball to the right
if(rb.velocity.magnitude < 0.05f) // if i click the ball it just prints it and not wating for the ball to not move
{
Debug.Log(PlayerPosition.position.x);
}
}
}
I expected the output to wait until the animation is finished but instead, its printing the vaule(x) the moment i click the mouse.
Edit
You need to check if your animation is still playing. You are checking only if your velocity is greater than 0.05f, which is correctly printing out the statement.
Use Animation.IsPlaying(string name). One caveat is that this method will return false for the same frame of Update that it was invoked, since the animation hasn't technically started until afterward.
void Update()
{
if (!rb.velocity.magnitude <= 0.01f && !Animation.IsPlaying(nameOfAnimation))
{
Debug.Log("We're not moving and the animation is not playing");
}
}
Original
You should not need to use while in your Update method.
Use an if statement inside of your Update
void Update()
{
if (rb.velocity.magnitude > 0.01f) Debug.Log("We're moving!");
}
First
rb.velocity.magnitude != 0.0f
will almost allways be true due to single precision floatong point : Two float values even if they seem to be equal logical are most likely not.
So you can either use a threshold how you tried already
if(rb.velocity.magnitude <= 0.5f)
or use Mathf.Approximately which uses a very small Epsilon or threshold for the comparing
if(Mathf.Approximately(rb.velocity.magintude, 0))
Than it sounds like you want to wait until the ball has stopped moving and than output the position - like e.g. for a billard game. So actually there seems to be no Animation involved.
In most cases where you think/speek of of an "animation" you actually mean "doing something over time" not to confuse with using an Animator or Animation component with AnimationClips in Unity.
You can/should use a Coroutine for that:
public Rigidbody rb;
public Transform PlayerPosition;
// a flag to make sure there is only one animation at a time
private bool isMoving;
// a flag for altering between left and right movement
private bool isMovingRight;
// Update is called once per frame
void Update()
{
// only allow clicks while not moving already
if (!isMoving && Input.GetMouseButtonDown(0))
{
// stop further input until not moving anymore
isMoving = true;
// add the force
// (you might btw want to skip that Time.deltaTime here it makes no sense)
rb.AddForce(isMovingRight ? 20000 : -20000 * Time.deltaTime, 0, 0);
// alter the direction for the next call
isMovingRight = !isMovingRight;
// if you rather want to be able to interrupt the current animation by clicking again
// remove the isMoving flag and instead use this
//StopCoroutine(WaitForMoveStops());
// Start the routine
StartCoroutine(WaitForMoveStops());
}
}
private IEnumerator WaitForMoveStops()
{
// Inside a Coroutine while is okey now
// as long as you yield somwhere
// check if velocity is below threshold
while (!Mathf.Approximately(rb.velocity.magnitude, 0)
{
// yield in simple words means "leave" this method here, render the frame
// and than continue from here in the next frame
yield return null;
}
// I would now hard reset the velocity just to be sure
rb.velocity = Vector3.zero;
Debug.Log(PlayerPosition.position.x);
// whatever you want to do now
// reset the flag to allow input again
isMoving = false;
}
I think you want to move it if it's stopped, then call AddForce only when it's idle:
var wasMovingLastTime = false;
void Update()
{
var isMoving = rb.velocity.magnitude > 0f;
if (wasMovingLastTime && !isMoving)
{
/// Has just finished moving
Debug.Log(PlayerPosition.position.x);
}
if (Input.GetMouseButtonDown(0))
{
if (!isMoving)
{
rb.AddForce(20000 * Time.deltaTime, 0, 0);
}
}
wasMovingLastTime = isMoving;
}
I wanted to use my coroutine to smoothly interpolate the position and rotation of multiple GameObjects with the script attached to them. When I start the coroutine, the smooth part works fine, but all of my Objects get moved to the same position, which was not what I intended. I want to understand why that is the case, and if there is a smart way to deal with it.
This is what my coroutine looks like:
IEnumerator interpolate_Plate(Transform targ)
{
float passedTime = 0;
while (!transform.Equals(targ))
{
passedTime += Time.deltaTime;
transform.position = Vector3.Lerp(transform.position, targ.position, passedTime);
transform.rotation = Quaternion.Lerp(transform.rotation, targ.rotation,passedTime);
yield return null;
}
yield break;
}
I was thinking about creating a mastercoroutine with a list in it and then call the smoothing part.
Is the problem just, that the Reference of targ always gets reset for all coroutinecalls on the stack?
As requested by you the function that calls the coroutine:
public void move_Plate(Transform newPosition)
{
StartCoroutine(interpolate_Plate(newPosition));
}
Okay so I found the solution, since Unity or C# works with pointers and so on the problem was. that I continously changed the transforms of all Objects, since I used the pointer to the transform of the next Object. But I moved that Object to so it all ended up on the last Object I moved.
How to prevent this:
I created a new class which stores my values so position and rotation of the old one. I store an Instance of that in my Class where I move the plates.
I now changed from coroutine to the update method as suggested in the comments. With a flag I check if I should move the Object or not. Then I move it smoothly to the new Position.
Code:
private Trans MoveTo;
private bool move;
void Update()
{
if (move)
{
float passedTime = 0;
passedTime += Time.deltaTime;
transform.position = Vector3.Lerp(transform.position, MoveTo.position, passedTime);
transform.rotation = Quaternion.Lerp(transform.rotation, MoveTo.rotation, passedTime);
}
}
Seems to work.
I'm facing a problem in my scene. What i'm doing is there are two panels both panel has one button which performing OnClick() listener with the method name RotateCamera().
Also in hierarchy there is a MainMenu gameobject which attached with one script. When I play the scene and click on panel one button than MainCamera rotate with 90 angle to the direction of second panel. Script works fine but I want to smoothly rotate camera to that panel when I click on that button - right now, it is rotating instantly. I don't know what I'm doing wrong on this script.
public class CameraSmooth : MonoBehaviour {
private bool check = false;
private Transform from;
private Transform to;
void Start(){
from = Camera.main.transform;
}
void Update(){
if (to != null) {
Camera.main.transform.rotation = Quaternion.Slerp (from.rotation, to.rotation, 3 * Time.deltaTime);
}
}
public void RotateCamera(){
if (!check) {
Camera.main.transform.Rotate (0,90f,0f);
to = Camera.main.transform;
check = true;
}
else if (check) {
Camera.main.transform.rotation = Quaternion.identity;
to = Camera.main.transform;
check = false;
}
}
}
The main problem here is that you're calling Camera.main.transform.Rotate() in RotateCamera(). This causes the rotation to be applied to the camera immediately, resulting in the instant rotation you're seeing.
Another small misconception - since Transform is a reference type, from and to always actually point to the same instance (the Transform of the camera)! Lastly, the value of 3 * Time.deltaTime will always average around 3/60, and will likely never end up close to 1, which is needed for an interpolation to be complete. As such, the following line:
Camera.main.transform.rotation = Quaternion.Slerp (from.rotation, to.rotation, 3 * Time.deltaTime);
will not be able to do anything even if the first issue is addressed.
The situation calls for a different solution, in my view:
Storing the target rotations in Quaternion variables rather than setting them directly on the Transform, and keeping track of the camera's initial rotation
Maintaining a timer which keeps track of the progress of the rotation (or you can abandon Slerp() and just apply an incremental rotation directly, that's also a valid approach)
Here's my suggested update to your code:
public class CameraSmooth : MonoBehaviour {
private bool check = false;
private float rotationProgress = 1;
private Quaternion initial;
private Quaternion from;
private Quaternion to;
void Start(){
// Cache the starting rotation, so we can calculate rotations relative to it
initial = Camera.main.transform.rotation;
}
void Update(){
if (rotationProgress < 1) {
rotationProgress += 3 * Time.deltaTime;
Camera.main.transform.rotation = Quaternion.Slerp (from, to, rotationProgress);
}
}
public void RotateCamera(){
from = Camera.main.transform.rotation;
rotationProgress = 0;
if (!check) {
to = initial * Quaternion.Euler(0,90f,0f);
check = true;
}
else if (check) {
to = initial;
check = false;
}
}
}
(Haven't tested this code, so please let me know if there are any issues.) Hope this helps! Let me know if you have any questions!