How can I restart coroutine? - c#

I am trying to implement a coroutine that moves an object to a specific point and then comes back to the origin (specified by me) as a coroutine in Unity, but the coroutine is not executed after returning to the origin. What's wrong?
public class LineManager : MonoBehaviour
{
public Vector3 positionToGo = new Vector3(0, -4, 0);
IEnumerator coroutine;
void Start()
{
coroutine = MoveToPosition(transform, positionToGo, 2f);
}
void Update()
{
if(transform.position.y == 4)
{
StartCoroutine(coroutine);
}
}
public IEnumerator MoveToPosition(Transform transform, Vector3 position, float timeToMove)
{
var currentPos = transform.position;
var t = 0f;
while (t < 1 && currentPos.y > position.y)
{
t += Time.deltaTime / timeToMove;
transform.position = Vector3.Lerp(currentPos, position, t);
yield return null;
}
transform.position = new Vector3(0, 4, 0);
StopCoroutine(coroutine);
}
}

You don't really need to restart your routine for that.
But first things first:
transform.position.y == 4
is risky as it is a direct float comparison and might fail. See Is floating point math broken?
Anyways, back to the coroutine restarting. Why not simply move without a routine at all
public Vector3 positionToGo = new Vector3(0, -4, 0);
public float timeToMove = 2f;
private Vector3 originalPosition;
private float factor;
private void Awake()
{
originalPosition = transform.position;
}
private void Update()
{
if(factor >= 1)
{
factor = 0;
transform.position = originalPosition;
}
else
{
factor += Time.deltaTime / timeToMove;
transform.position = Vector3.Lerp(originalPosition, positionToGo, factor);
}
}
As an alternative if you want to use the routine you can always simply make it loop
public Vector3 positionToGo = new Vector3(0, -4, 0);
public float timeToMove = 2f;
private IEnumerator Start()
{
var originalPosition = transform.position;
while(true)
{
for(var factor = 0f; factor < 1f; factor += Time.deltaTime / timeToMove)
{
transform.position = Vector3.Lerp(originalPosition, position, factor);
yield return null;
}
transform.position = originalPosition;
}
}

Call the Coroutine in that IEnumerator with WaitForSeconds

Related

Adding a delay to a moving object?

I have an object that moves forward and backwards. Just as it is about to move in the opposite direction, I am trying to add a very brief delay (1.0f) before it moves again.
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
void Start()
{
startPos = transform.position;
}
void Update()
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(Time.time * speed);
transform.position = v;
}
}
I attempted to implement a coroutine in two different ways with one of them not working and the other making my entire game basically freeze. I tried to call the method again as well which I am not sure works at all however there were no results.
using System.Collections;
using UnityEngine;
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
[SerializeField] private float _delay = 1f;
void Start()
{
startPos = transform.position;
StartCoroutine(DoMoving());
}
private IEnumerator DoMoving()
{
while (true)
{
yield return DoCycle();
yield return new WaitForSeconds(_delay);
}
IEnumerator DoCycle()
{
var time = 0f;
while (time * speed < Mathf.PI * 2f)
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(time * speed);
transform.position = v;
yield return null;
time += Time.deltaTime;
}
}
}
}
But it would be better to use dotween or dotween + unitask for async moving

Why the object keep moving up nonstop and how to move it forward fast when it finished moving up?

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));

Getting the distance of wall(Multiple objects with same tag)

I'm trying to get the distance between my player, and the nearest object with the tag 'wall' however I can't seem to get it to work.
To my knowledge my code isn't working at all.
So my question is;
What am I doing wrong? Again, I want to find the distance from my player and the nearest object with the tag 'wall'. If I'm near a object with the tag 'wall' I want it to set the variable to true.(nearWall = true) then once I'm away from the object(About 10.0f) I want it back to false.(nearWall = false)
This is the code I have been working with.
using UnityEngine;
using System.Collections;
public class PlayerMotor : MonoBehaviour {
private CharacterController controller;
private Vector3 moveVector;
private float speed = 2.0f;
private float verticalVelocity = 0.0f;
private float gravity = 12.0f;
private bool nearWall;
public GameObject playerObject;
GameObject closestObject;
float distance = Mathf.Infinity;
public float distanceToWall = Mathf.Infinity;
private void Start() {
nearWall = false;
playerObject = GameObject.Find("Player");
distanceToWall = 0;
controller = GetComponent<CharacterController> ();
}
public void getNearestWall()
{
if (distance <= 10.0f) {
nearWall = true;
print ("Near wall!");
}
else
nearWall = false;
}
GameObject findNearestWall()
{
GameObject[]objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
Vector3 position = playerObject.transform.position;
foreach(GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
private void Update()
{
findNearestWall ();
moveVector = Vector3.zero;
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
}
if (Input.GetMouseButton (0)) {
if (!nearWall) {
if (Input.mousePosition.x > Screen.width / 2)
moveVector.x = speed;
else
moveVector.x = -speed;
}
else
{
moveVector.x = transform.forward.x * speed;
transform.Rotate(new Vector3(0, -90, 0));
}
}
moveVector.y = verticalVelocity;
moveVector.z = transform.forward.z * speed;
controller.Move (moveVector * Time.deltaTime);
}
}
One thing is that you are not calling getNearestWall() method - which is actually changing the flag - anywhere.
And second why don't you just try:
currentDistance = Vector3.Distance(currentObject.transform.position, position);
When calculating distance
first of all you need to call getNearestWall(); inside the Update() method ( after findNearestWall() of course ). also what you are doing now is getting the minimal distance the player reached in the whole game. you might want to add distance = Mathf.Infinity; in top of findNearestWall() so it will something like this:
GameObject findNearestWall()
{
GameObject[] objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
distance = Mathf.Infinity;
Vector3 position = playerObject.transform.position;
foreach (GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
now whenever you get near a wall it should print Near wall!
note:
also you are calling FindObjectsWithTag() at an Update method which might significantly drain your processing power. you might want to avoid that by declaring a private GameObject[] objectArray in the class.
and then use objectArray = GameObject.FindGameObjectsWithTag("wall"); once at Awake() or Start()

Jumping at an angle with Unity and C#

I'm working on a project where I'm trying to make my character move by jumping at an angle. Right now during the frame updates, the character will pivot back and forth and when the right key is pressed, they will jump. This code causes them to jump at an angle, but they always return to their original position.
Additionally, I have two characters who start on opposite sides of the stage, but when I start the game they teleport to the same position. I've spent a lot of time reviewing my code but I can't seem to get this to work. Any help you can provide?
using UnityEngine;
using System.Collections;
public class Freg : MonoBehaviour {
public GameObject Tounge;
public float gravity;
public float tempScale = 1;
public float MaxJump = 8f;
public float MinJump = 0.1f;
static float yVector = 0;
static float xVector = 0;
static bool grounded = true;
bool isleft = false;
Vector3 farthestleft;
Vector3 farthestright;
// Use this for initialization
void Start () {
farthestleft = new Vector3 (-33.7f, 50.2f, 24.8f);
farthestright = new Vector3 (22.56f, 54.83f, -15.12f);
}
void OnTriggerEnter (Collider other) {
if (other.GetComponent<Collider> ().tag == "Ground") {
grounded = true;
yVector = 0;
//xVector = 0;
Vector3 onGround = new Vector3 (transform.position.x, -4.86f, transform.position.z);
transform.position = onGround;
} else
grounded = false;
}
// Update is called once per frame
void Update () {
/*if (Input.GetKey (KeyCode.UpArrow) == true) {
Tounge.transform.localScale.Set (1, 0.5f, 1);
} else {
Tounge.transform.localScale.Set (1, 1, 1);
}*/
if (grounded == false) {
yVector -= gravity;
}
if (Input.GetKeyDown (KeyCode.UpArrow) == true && grounded == true) {
MinJump += 0.5f;
} else if (MinJump > 0.1f){
yVector += MinJump;
xVector += MinJump;
MinJump = 0.1f;
grounded = false;
}
Vector3 stuff = new Vector3 (transform.localPosition.y + xVector, transform.position.y + yVector, transform.position.z);
transform.position = stuff;
float t = Mathf.PingPong (Time.time * 0.5f * 2.0f, 1.0f);
transform.eulerAngles = Vector3.Lerp (farthestright, farthestleft, t);
}
}
it looks like you should update the current position during the if statements, rather than after that way on each update, the actual position is moving based on the decision rather than just the end of the loop.

How to make player bounce up and down?

I'm making a very simple android game but I am new at coding. I want my player to continuously go up and down the screen, but can't make it wordk.
public class DuckBehaviour : MonoBehaviour {
Vector3 velocity = Vector3.zero;
float speed = 1f;
float verticality;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (transform.position.y < Screen.height -10) {
velocity.y = 0.7f;
} else if (transform.position.y > 10) {
velocity.y = -0.7f;
}
transform.position += velocity * Time.deltaTime;
}
}
There appear to be two issues with the code. The first is that if the gameobject starts on screen as opposed to offscreen then its velocity will remain at Vector2.zero. The second issue is that Screen.height is in pixels but transform is in Unity's units. Hope this helps.
public class DuckBehaviour : MonoBehaviour {
Vector3 velocity = Vector3.zero;
float speed = 1f;
float verticality;
// Use this for initialization
void Start () {
velocity.y = 0.7f;
}
// Update is called once per frame
void Update () {
//Requires that an orthographic camera named "MainCamera" exists with y transform of 0
if (transform.position.y < -Camera.main.orthographicSize) {
velocity.y = 0.7f;
} else if (transform.position.y > Camera.main.orthographicSize) {
velocity.y = -0.7f;
}
transform.position += velocity * Time.deltaTime;
}
}
You could try something like this (taken from Unity forums - see here.
Beware, the code is not actually tested :)
public class DuckBehaviour : MonoBehaviour {
float speed = 1f;
float verticality;
Vector3 pointB;
IEnumerator Start () {
Vector3 pointA = transform.position;
while (true) {
yield return StartCoroutine(MoveObject(transform, pointA, pointB, 3.0));
yield return StartCoroutine(MoveObject(transform, pointB, pointA, 3.0));
}
}
IEnumerator MoveObject (Transform thisTransform, Vector3 startPos, Vector3 endPos, float time) {
float i = 0.0f;
float rate = 1.0f / time;
while (i < 1.0f) {
i += Time.deltaTime * rate;
thisTransform.position = Vector3.Lerp(startPos, endPos, i);
yield return null;
}
}
}
C# requires you to use the StartCoroutine method and any methods to be used as coroutines must return IEnumerator. This page explains how coroutines work.

Categories

Resources