Print Unity Coordinates to a string at specified time interval - c#

I want to move a cube using some device and periodically (every 3 seconds) print those coordinates to a file. I am not sure how to accomplish this with my code below. Does anybody have ideas as to how this can be done?
Thank you!
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
[RequireComponent(typeof(MeshCollider))]
public class UserController : MonoBehaviour {
public int speed = 20;
// Update is called once per frame
void Update()
{
// get input data from keyboard or controller
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
// update player position based on input
Vector3 position = transform.position;
position.x += moveHorizontal * speed * Time.deltaTime;
position.z += moveVertical * speed * Time.deltaTime;
transform.position = position;
}
void OnMouseDrag()
{
if(Input.GetMouseButton(0))
{
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen));
}
}
}

I would suggest creating a separate script and attach it to your cube.
public class CubeTracker : MonoBehaviour
{
private bool logging = true;
void Awake()
{
StartCoroutine(LogPosition());
}
private IEnumerator LogPosition()
{
while (logging)
{
Debug.Log(transform.position);
yield return new WaitForSeconds(3f);
}
}
}
This will start a coroutine as soon as the cube is created and should log your desired result into console. If that's what you desire, you can then go ahead and replace the Debug.Log with a write-to-file implementation.

Use a global variable, and feed it inside Update() method.
for example:
private Vector3 LastCoordinate{get; set;}
and the use a periodic timer like :
private System.Threading.Timer timer;
timer = new System.Threading.Timer(GetLastCoordinate, null, 3000, 0);
private void GetLastCoordinate()
{
lock(this)
{
Vector3 lastCoordEachThreeSecs = LastCoordinate;
}
}

Related

how can i convert a transform into a float

I am trying to take the current position of something once when collided and im not sure how to
do that could anyone help me out please?
The problem i have is that the script is grabbing the playerLocation constantly i need it so it grabs it once it collides.
basically when my object colides with something it moves towards a diferent object but i dont want it to follow it constantly i want it to get the position of that 1 object only once it has collided.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CircleMover : MonoBehaviour
{
public float speed = 10.0f;
public Transform playerLocation;
public float redirectSpeed;
public bool isCurrentlyColliding;
Vector3 playerposition;
private Rigidbody2D rb;
private Vector2 screenBounds;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(-speed, 0);
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
}
// Update is called once per frame
void Update()
{
//if (transform.position.x < -11.6f)
//{
// Destroy(this.gameObject);
//}
if (isCurrentlyColliding)
{
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("CopyCat"))
{
playerposition = (playerLocation.transform.position);
isCurrentlyColliding = true;
}
}
}
The reason it grabs the playerLocation constantly because you are using isCurrentlyColliding which you are never making false and also using it in Update() method which calls every frame.
You can do two things (choose whichever goes well with your code) :
by making isCurrentlyColliding false inside Update() method like this:
void Update()
{
if (isCurrentlyColliding)
{
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
isCurrentlyColliding = false;
}
}
by removing isCurrentlyColliding and setting transform.position directly inside OnTriggerEnter2D() method like this:
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("CopyCat"))
{
playerposition = (playerLocation.transform.position);
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
}
}

How can I control the Lerp speed?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateToTarget : MonoBehaviour
{
public Transform target;
public Transform character;
private const float FAC_SPEED = 10f;
private const float FAC_LERP = 0.9f;
private const float ANG_MAX = 80f;
// Start is called before the first frame update
void Start()
{
/* ... */
}
// Update is called once per frame
void Update()
{
float targetAngleFromForward = Vector3.Angle(character.transform.forward, target.position - transform.position);
Vector3 lerpPoint;
if (targetAngleFromForward < ANG_MAX)
{
// Lerp towards the target's direction
// This is not a very good or elegant solution but it demonstrates the idea
lerpPoint = Vector3.Lerp(transform.forward, (target.position - transform.position).normalized * FAC_SPEED, FAC_LERP * Time.deltaTime);
}
else
{
// Lerp towards the forward direction
// Same idea, but to character.transform.forward instead
lerpPoint = Vector3.Lerp(transform.forward, character.transform.forward * FAC_SPEED, FAC_LERP * Time.deltaTime);
}
transform.rotation = Quaternion.LookRotation(lerpPoint);
}
}
I want to add a global public variable to control the lerpPoint in the IF and in the ELSE.
To control the speed of the Lerp towards the target's direction and the Lerp towards the forward direction.
I tried to play with the const variables values but didn't figure it how to control this speeds.
Lerp gives you a single point part of the way between the two inputs, based on the final parameter which should be between 0 and 1. So you need to smoothly increase the final parameter of Lerp from 0 to 1 over time.
Probably the easiest way would be something like this (pseudocode stripping down your example for clarity):
public class RotateToTarget : MonoBehaviour
{
public float secondsToRotate = 2.0f;
private float secondsSoFar = 0.0f;
void Update()
{
secondsSoFar += Time.deltaTime;
float t = secondsSoFar / secondsToRotate;
Vector3 lerpPoint = Vector3.Lerp(start, end, t);
transform.rotation = Quaternion.LookRotation(lerpPoint);
}
}

Sprite Movement Troubleshooting help in Unity?

I'm trying to get an object to move every second in Unity, but it doesn't seem to work. I'm trying to make the game snake, and I'm starting off by centering the Sprite of the head, and starting it by moving it to the right every second, later adding player controls.
Any help with getting it to work?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Snake_Move : MonoBehaviour
{
private Vector2 pos;
private Vector2 moveDirection;
private float moveTimer;
private float timerSeconds;
private void Startup()
{
pos = new Vector2(5, 5);
timerSeconds = 1f;
moveTimer = timerSeconds;
moveDirection = new Vector2(1, 0);
}
private void Update()
{
moveTimer += Time.deltaTime;
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
}
transform.position = new Vector2(pos.x, pos.y);
}
}
Well Startup is never called so all your values will keep their default values - in particular pos = Vector2.zero and moveDirection = Vector2.zero so your object will never move at all.
You probably rather wanted to call it Start in order to implement the Unity message MonoBehaviour.Start that is called automatically
on the frame when a script is enabled just before any of the Update methods are called the first time.
public class Snake_Move : MonoBehaviour
{
// These you adjust in the Inspector in Unity
// Later changes to the values here will have no effect!
[Tooltip("Time interval between steps in seconds")]
[SerializeField] private float stepInterval = 1f;
[Tooltip("Initial position")]
private Vector2 startPos = new Vector2(5, 5);
private Vector2 moveDirection;
private float moveTimer;
// What you wanted is probably the Unity message method Start
// which is called when you app starts
private void Start()
{
moveTimer = stepInterval;
moveDirection = Vector2.right;
transform.position = startPos;
}
private void Update()
{
moveTimer += Time.deltaTime;
if (moveTimer > stepInterval)
{
moveTimer -= stepInterval;
// No need to store the pos, simply only assign a new value
// to the position when needed
transform.position += moveDirection;
}
}
}

Unity - Quaternion.Slerp instantly rotating

I am trying to have my object smoothly rotate on the Z axis from 0 to 180, back and forth on every button press.
The Quaternion.Slerp setup i'm using does not smoothly rotate to the target rotation, rather it instantly jumps to a number close to it. After many button presses that call the Quaternion.Slerp, it it finally halfs works in that it goes from 0 to 180, but still instantly and not smoothly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed;
public bool movePlayer;
private float maxMoveSpeed;
public float waitToMove;
Rigidbody2D thisRigidbody;
//SCOOP variables
private GameObject scoop;
private GameObject scoopRotation;
Quaternion currentScoopRotation;
public Quaternion targetScoopRotation;
Quaternion lastScoopRotation;
public float scoopRotateTime;
// Use this for initialization
void Start ()
{
thisRigidbody = gameObject.GetComponent<Rigidbody2D> ();
maxMoveSpeed = moveSpeed;
//SCOOP finders
scoop = GameObject.FindGameObjectWithTag ("Scoop");
currentScoopRotation = scoop.transform.rotation;
}
// Update is called once per frame
void Update ()
{
if(movePlayer)
thisRigidbody.velocity = new Vector2 (moveSpeed, thisRigidbody.velocity.y);
//Rotates SCOOP using Quaternions + Spacebar
if (Input.GetKeyDown(KeyCode.Space)) {
lastScoopRotation = currentScoopRotation;
scoop.transform.transform.rotation = Quaternion.Lerp (currentScoopRotation, targetScoopRotation, scoopRotateTime * Time.time);
currentScoopRotation = targetScoopRotation;
targetScoopRotation = lastScoopRotation;
changeMoveDirection ();
}
}
void changeMoveDirection()
{
moveSpeed *= -1;
}
IEnumerator changeDirectionCO()
{
//thisRigidbody.velocity = new Vector2 (0f,0f);
//moveSpeed = 0;
yield return new WaitForSeconds (waitToMove);
moveSpeed *= -1;
}
}

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