Having Troubles with Unity C# Time Delay / Coroutines - c#

I am trying to write a script for when you press a button to make it instantiate a card with a random rarity but I need to delete the cards after a small delay although I dont think the delay is working because the cards seemingly instantly dissapear
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CardMasterScript : MonoBehaviour
{
public GameObject[] CardArray = new GameObject[8];
public float RollNumber;
public void RollCard()
{
RollNumber = Random.Range(0.1f, 100);
Debug.Log("Number Rolled: " + RollNumber);
if(RollNumber <= 47.9)
{
var card = Instantiate(CardArray[0]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if(RollNumber > 47.9 && RollNumber <= 77.9)
{
var card = Instantiate(CardArray[1]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if( RollNumber > 77.9 && RollNumber <= 87.9)
{
var card = Instantiate(CardArray[2]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if(RollNumber > 87.9 && RollNumber <= 94.9)
{
var card = Instantiate(CardArray[3]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if(RollNumber > 94.9 && RollNumber <= 97.9)
{
var card = Instantiate(CardArray[4]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if(RollNumber > 97.9 && RollNumber <= 99.4)
{
var card = Instantiate(CardArray[5]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if(RollNumber > 99.4 && RollNumber <= 99.9)
{
var card = Instantiate(CardArray[6]);
StartCoroutine(TimeDelay());
Destroy(card);
} else if (RollNumber > 99.9 && RollNumber <= 100)
{
var card = Instantiate(CardArray[7]);
StartCoroutine(TimeDelay());
Destroy(card);
}
}
public IEnumerator TimeDelay()
{
yield return new WaitForSeconds(0.5f);
}
}
please help me fix this issue if you know how and thank you in advance!
at first I thought it was a problem with the instantiating and that it just wasn't instantiating the cards at all but now I'm not quite sure what the problem is.

you have to call the destroy after the waiting time like this
public IEnumerator TimeDelay(){
yield return new WaitForSeconds(0.5f);
Destroy(obj);
}
and other tip: Destroy method contains delay parameter
Destroy(obj,0.5f);
https://docs.unity3d.com/ScriptReference/Object.Destroy.html

In Quick way, it is enough to enter the delay value in the second parameter of the Destroy method.
Destroy(card, .5f); // Delay Time
The second way is to write the functions themselves inside the Coroutine. Because the delay time is not executed outside the coroutine.
private IEnumerator DelayRun(GameObject gameObject)
{
yield return new WaitForSeconds(.5f);
Destroy(gameObject);
}
The third way is to specify the action with a delay time, which allows you to execute any command after a delay. Just make sure you use the System library.
using System;
...
void Start()
{
StartCoroutine(DelayRun(.5f, () => Destroy(card)));
}
private IEnumerator DelayRun(float delay, Action action)
{
yield return new WaitForSeconds(delay);
action.Invoke();
}

The destruction is occurring independent from the coroutine. When you start the coroutine, you are "splitting" the program into two branches. Currently your first branch just turns on an alarm clock for half a second and your other branch deletes your object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CardMasterScript : MonoBehaviour
{
public GameObject[] CardArray = new GameObject[8];
public float RollNumber;
public void RollCard()
{
RollNumber = Random.Range(0.1f, 100);
Debug.Log("Number Rolled: " + RollNumber);
if(RollNumber <= 47.9)
{
var card = Instantiate(CardArray[0]);
StartCoroutine(TimeDelay());
} else if(RollNumber > 47.9 && RollNumber <= 77.9)
{
var card = Instantiate(CardArray[1]);
StartCoroutine(TimeDelay());
} else if( RollNumber > 77.9 && RollNumber <= 87.9)
{
var card = Instantiate(CardArray[2]);
StartCoroutine(TimeDelay());
} else if(RollNumber > 87.9 && RollNumber <= 94.9)
{
var card = Instantiate(CardArray[3]);
StartCoroutine(TimeDelay());
} else if(RollNumber > 94.9 && RollNumber <= 97.9)
{
var card = Instantiate(CardArray[4]);
StartCoroutine(TimeDelay());
} else if(RollNumber > 97.9 && RollNumber <= 99.4)
{
var card = Instantiate(CardArray[5]);
StartCoroutine(TimeDelay());
} else if(RollNumber > 99.4 && RollNumber <= 99.9)
{
var card = Instantiate(CardArray[6]);
StartCoroutine(TimeDelay());
} else if (RollNumber > 99.9 && RollNumber <= 100)
{
var card = Instantiate(CardArray[7]);
StartCoroutine(TimeDelay());
}
}
public IEnumerator TimeDelay()
{
yield return new WaitForSeconds(0.5f);
Destroy(card);
}
}
In your case using a coroutine isn't actually necessery, since the Destroy method has a build in delay argument.
Streamlined your code could look like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CardMasterScript : MonoBehaviour
{
public GameObject[] CardArray = new GameObject[8];
public float RollNumber;
public void RollCard()
{
RollNumber = Random.Range(0.1f, 100);
Debug.Log("Number Rolled: " + RollNumber);
GameObject card = null;
if(RollNumber <= 47.9)
{
card = Instantiate(CardArray[0]);
} else if(RollNumber <= 77.9)
{
card = Instantiate(CardArray[1]);
} else if(RollNumber <= 87.9)
{
card = Instantiate(CardArray[2]);
} else if(RollNumber <= 94.9)
{
card = Instantiate(CardArray[3]);
} else if(RollNumber <= 97.9)
{
card = Instantiate(CardArray[4]);
} else if(RollNumber <= 99.4)
{
card = Instantiate(CardArray[5]);
} else if(RollNumber <= 99.9)
{
card = Instantiate(CardArray[6]);
} else
{
card = Instantiate(CardArray[7]);
}
Destroy(card, 0.5f);
}
}

Related

How to go back to script after starting Coroutine?

I currently have a script that allows the player to pick up an item and plays an animation. I have a coroutine to wait 1 second before locking the game object to the player's hand. My problem is that my code for dropping the item and throwing it no longer functions. Is there a workaround to solve this problem?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUp : MonoBehaviour
{
bool isgrounded = true;
public Animator animator;
public GameObject Player;
public Rigidbody rb;
public bool inrange;
public int number = 1;
public Transform theDest;
public float thrust = 1.0f;
public float upthrust = 1.0f;
void start()
{
rb = GetComponent<Rigidbody>();
inrange = false;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "Player")
{
inrange = true;
}
}
private void OnTriggerExit(Collider other)
{
inrange = false;
}
public void Update()
{
bool isPickUp = animator.GetBool("isPickUp");
bool pickuppressed = Input.GetKey("e");
if (isgrounded == true)
{
if (pickuppressed && !isPickUp && inrange==true)
{
animator.SetBool("isPickUp", true);
}
if (!pickuppressed && isPickUp || inrange == false)
{
animator.SetBool("isPickUp", false);
}
if (Input.GetKeyUp(KeyCode.E) && (number % 2) == 1 && inrange == true )
{
StartCoroutine(waiter());
number = number + 1;
}
else if (Input.GetKeyUp(KeyCode.E) && (number % 2) == 0 && inrange == true)
{
GetComponent<Rigidbody>().isKinematic = false;
GetComponent<BoxCollider>().enabled = true;
this.transform.parent = null;
GetComponent<Rigidbody>().useGravity = true;
number = number - 1;
}
else if (Input.GetKey(KeyCode.G) && (number % 2) == 0 && inrange == true)
{
GetComponent<Rigidbody>().isKinematic = false;
GetComponent<BoxCollider>().enabled = true;
this.transform.parent = null;
GetComponent<Rigidbody>().useGravity = true;
number = number - 1;
rb.AddForce(Player.transform.forward * thrust);
rb.AddForce(Player.transform.up * upthrust);
}
}
void OnCollisionEnter(Collision theCollision)
{
if (theCollision.gameObject.name == "floor")
{
isgrounded = true;
}
}
//consider when character is jumping .. it will exit collision.
void OnCollisionExit(Collision theCollision)
{
if (theCollision.gameObject.name == "floor")
{
isgrounded = false;
}
}
IEnumerator waiter()
{
yield return new WaitForSeconds(1);
GetComponent<BoxCollider>().enabled = false;
GetComponent<Rigidbody>().useGravity = false;
GetComponent<Rigidbody>().isKinematic = true;
this.transform.position = theDest.position;
this.transform.parent = GameObject.Find("Destination").transform;
}
}
}
Let me know if more information is needed (still new to stack overflow)
Forget about the coroutine and use Time.time to save the time of pickup to a class variable. Then add comparison to the other if branches such as Time.time > pickupTime + 1f.

Unity 2d Character moves and jumps to specific positions with UI buttons

In a simple 2d project in which my player can move to the right and left on x and can also jump to the right and left in height with two other buttons. The problem is, that the player is not supposed to move freely. By pressing one of the buttons the player should only go to the next specific point, so that the player always stops at six different positions on x (while on y he is free and as high as the platform he is currently standing on). To be able to jump realistically, the player must have gravity and a collider to be able to land on the platforms (and move single platforms horizontal).
Thanks to the tutorial which #TEEBQNE linked in the comments I could finally realise this with Unitys Rigidbody2D and the following script. The problem is that the gravity is now behaving strangely. The player only moves down very slowly and in the process pushes Gameobjects underneath it through others. The player has a Dynamic Rigidbody2D with a gravity scale of 2 and a capsule collider 2d. Is that a problem with the script or with the components in the players inspector?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movePlayer : MonoBehaviour
{
public GameObject posChecker1;
public GameObject posChecker2;
public GameObject posChecker3;
public GameObject posChecker4;
public GameObject posChecker5;
public GameObject posChecker6;
public bool go; //Player is allowed to move
public bool grounded; //Player is allowed to jump
public string moveDirection;
public float horizVel = 0; //Movement along x
public float verticVel = 0; //Jump
public int laneNum = 3; //Player starts on lane 3!!
public bool rightButtonMove = false;//
public bool leftButtonMove = false;//
public bool rightButtonJump = false;//
public bool leftButtonJump = false;//
//Animation
private SpriteRenderer spriteRenderer;
private Animator animator;
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
posChecker1.SetActive(true);//GameObject.Find("PositionChecker1").SetActive(true);
posChecker2.SetActive(true);
posChecker3.SetActive(true); //Player start on lane 3!!
posChecker4.SetActive(true);
posChecker5.SetActive(true);
posChecker6.SetActive(true);
laneNum = 3;
go = true;
}
// Update is called once per frame
void Update()
{
//Raycast
int playerMask = LayerMask.GetMask("PositionChecker");// !!!
Debug.DrawRay(transform.position, transform.TransformDirection(Vector2.up) * 50f, Color.green);
RaycastHit2D hitCheck = Physics2D.Raycast(transform.position, transform.TransformDirection(Vector2.up), 50f, playerMask);
//Only the checker objects in the rows next to the player are active
if (laneNum == 1)
{
posChecker1.SetActive(false);
posChecker2.SetActive(true);
}
else if (laneNum == 2)
{
posChecker1.SetActive(true);
posChecker2.SetActive(false);
posChecker3.SetActive(true);
}
else if (laneNum == 3)
{
posChecker2.SetActive(true);
posChecker3.SetActive(false);
posChecker4.SetActive(true);
}
else if (laneNum == 4)
{
posChecker3.SetActive(true);
posChecker4.SetActive(false);
posChecker5.SetActive(true);
}
else if (laneNum == 5)
{
posChecker4.SetActive(true);
posChecker5.SetActive(false);
posChecker6.SetActive(true);
}
else if (laneNum == 6)
{
posChecker5.SetActive(true);
posChecker6.SetActive(false);
}
//Movement
GetComponent<Rigidbody2D>().velocity = new Vector3(horizVel, verticVel, 0);
//Raycast
if (hitCheck)
{
if (moveDirection == "l" && horizVel != 0)
{
laneNum -= 1;
}
if (moveDirection == "r" && horizVel != 0)
{
laneNum += 1;
}
go = true;
horizVel = 0;
verticVel = 0;
grounded = true;
}
if (horizVel == 0)
moveDirection = "";
//Animation
bool flipSprite = (spriteRenderer.flipX ? (horizVel > 0.01f) : (horizVel < 0.01f));
if (flipSprite)
{
spriteRenderer.flipX = !spriteRenderer.flipX;
}
animator.SetBool("grounded", grounded); // -->Jump
animator.SetFloat("velocityX", Mathf.Abs(horizVel));
}
//Button Input
public void RightButton() //
{
if (laneNum < 6 && go)
{
moveDirection = "r";
go = false;
horizVel = 4;
}
}
public void LeftButton()//
{
if (laneNum > 1 && go)
{
moveDirection = "l";
go = false;
horizVel = -4;
}
}
public void RightJump()//
{
if (laneNum < 6 && grounded && go)
{
moveDirection = "r";
horizVel = 4;
verticVel = 7;
go = false;
grounded = false;
}
}
public void LeftJump()//
{
if (laneNum > 1 && grounded && go)
{
moveDirection = "l";
horizVel = -4;
verticVel = 7;
go = false;
grounded = false;
}
}
}
Glad I was able to help in some way and that you figured out your issue!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movePlayer : MonoBehaviour
{
//Player Position x
public GameObject posChecker1;
public GameObject posChecker2;
public GameObject posChecker3;
public GameObject posChecker4;
public GameObject posChecker5;
public GameObject posChecker6;
public int laneNum = 3; //Player starts on lane 3!!
//Player Position y
public float yPos1;
public float yPos2;
public Transform player;
//Movement Variables
public bool go; //Player is allowed to move
public bool grounded; //Player is allowed to jump
public string moveDirection;
public float horizVel = 0; //Movement along x
public float verticVel = 0; //Jump
//Animation
private SpriteRenderer spriteRenderer;
private Animator animator;
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
posChecker1.SetActive(true);//GameObject.Find("PositionChecker1").SetActive(true);
posChecker2.SetActive(true);
posChecker3.SetActive(true); //Player start on lane 3!!
posChecker4.SetActive(true);
posChecker5.SetActive(true);
posChecker6.SetActive(true);
laneNum = 3;
go = true;
}
// Update is called once per frame
void Update()
{
//Raycast
int playerMask = LayerMask.GetMask("PositionChecker");// !!!
Debug.DrawRay(transform.position, transform.TransformDirection(Vector2.up) * 50f, Color.green);
RaycastHit2D hitCheck = Physics2D.Raycast(transform.position, transform.TransformDirection(Vector2.up), 50f, playerMask);
//Only the checker objects in the rows next to the player are active
if (laneNum == 1)
{
posChecker1.SetActive(false);
posChecker2.SetActive(true);
}
else if (laneNum == 2)
{
posChecker1.SetActive(true);
posChecker2.SetActive(false);
posChecker3.SetActive(true);
}
else if (laneNum == 3)
{
posChecker2.SetActive(true);
posChecker3.SetActive(false);
posChecker4.SetActive(true);
}
else if (laneNum == 4)
{
posChecker3.SetActive(true);
posChecker4.SetActive(false);
posChecker5.SetActive(true);
}
else if (laneNum == 5)
{
posChecker4.SetActive(true);
posChecker5.SetActive(false);
posChecker6.SetActive(true);
}
else if (laneNum == 6)
{
posChecker5.SetActive(true);
posChecker6.SetActive(false);
}
//Movement
if (grounded)
{
verticVel = GetComponent<Rigidbody2D>().velocity.y;
}
GetComponent<Rigidbody2D>().velocity = new Vector3(horizVel, /*GetComponent<Rigidbody2D>().velocity.y*/verticVel, 0);
//Jump
yPos2 = player.transform.position.y;
if ((yPos2 - 2) >= yPos1 && !grounded)
{
if (moveDirection == "l")
horizVel = -4;
if (moveDirection == "r")
horizVel = 4;
verticVel = verticVel * 0.95f;
}
//Raycast
if (hitCheck)
{
if (moveDirection == "l" && horizVel != 0)
{
laneNum -= 1;
}
if (moveDirection == "r" && horizVel != 0)
{
laneNum += 1;
}
go = true;
horizVel = 0;
verticVel = 0;
grounded = true;
}
if (horizVel == 0 && grounded)
moveDirection = "";
//Animation
bool flipSprite = (spriteRenderer.flipX ? (horizVel > 0.01f) : (horizVel < 0.01f));
if (flipSprite)
{
spriteRenderer.flipX = !spriteRenderer.flipX;
}
animator.SetBool("grounded", grounded); // -->Jump
animator.SetFloat("velocityX", Mathf.Abs(horizVel));
}
//Button Input
public void RightButton() //
{
if (laneNum < 6 && go)
{
moveDirection = "r";
go = false;
horizVel = 4;
}
}
public void LeftButton()//
{
if (laneNum > 1 && go)
{
moveDirection = "l";
go = false;
horizVel = -4;
}
}
public void RightJump()//
{
if (laneNum < 6 && grounded && go)
{
moveDirection = "r";
verticVel = 5;
go = false;
grounded = false;
//
yPos1 = player.transform.position.y;
Debug.Log(yPos1);
//
}
}
public void LeftJump()//
{
if (laneNum > 1 && grounded && go)
{
moveDirection = "l";
verticVel = 5;
go = false;
grounded = false;
//
yPos1 = player.transform.position.y;
Debug.Log(yPos1);
//
}
}
}

Prefabs of mobs in the game on Unity do not go on the phone

There was a very interesting error with game characters, on the first level they walk quietly and everything is OK, and on the second they go only in the editor, and after compilation they are no longer there. Ai navigation exists. The character must find ... by the tag maybe he is on stage. What could be the problem? error only at the second level and only after assembly
mob script(They do not go, they do not attack if you approach. So either they don’t see or an error in the script on the phone occurs)
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class EmenScript: MonoBehaviour
{
public NavMeshAgent agent;
public Animator animator;
public GameObject zombieObject;
private Transform player;
private float curr_time;
private int xp = 100;
void Start()
{
player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
StartCoroutine(findPath());
StartCoroutine(playerDetected());
curr_time = 0f;
}
public void damage()
{
if(xp == 0)
{
gameObject.transform.Find("Xp/Cube/").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
} else {
xp = xp > 15 ? xp - 15 : 0;
Transform xpp = gameObject.transform.Find("Xp/Cube/XpLine").transform;
xpp.localScale = new Vector3(xpp.localScale.x, xpp.localScale.y, xp / 100f);
xpp.localPosition = new Vector3(xpp.localPosition.x, xpp.localPosition.y, (0.97f - xpp.localScale.z) / 2);
}
}
public void damageFull()
{
gameObject.transform.Find("Xp/Cube").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
}
IEnumerator playerDetected()
{
while(true)
{
if(player == null)
{
break;
}
if(player.GetComponent<UserController>().xp <= 0)
{
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
if(Vector3.Distance(transform.position, player.position) < 1.2f)
{
animator.SetTrigger("attack");
curr_time -= Time.deltaTime;
if(curr_time <= 0)
{
if(player.GetComponent<UserController>().xp - 25 > 0)
{
player.GetComponent<UserController>().xp -= 25;
}
else
{
player.GetComponent<UserController>().xp = 0;
}
curr_time = 0.5f;
}
}
yield return new WaitForSeconds(.3f);
}
}
IEnumerator findPath()
{
while(true)
{
if(player.GetComponent<UserController>().xp > 0)
{
if(Vector3.Distance(transform.position, player.position) < 40f)
{
animator.SetBool("walk", true);
if(player && agent.isActiveAndEnabled)
{
agent.GetComponent<NavMeshAgent>().isStopped = false;
agent.SetDestination(player.position);
}
} else {
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
}
yield return new WaitForSeconds(0.2f);
}
}
}
I think error must be about scene change but I need to see script and lvl's.

Change unity input to crossplatform input

This is the code i have coded through the online tutorial it is a normal swiping input but i want to change it to cross-platform input. I have no idea how to change it hope you guys can help me out
if (Input.touchCount == 1)
{
if (isSwipping)
{
Vector2 diff = Input.GetTouch(0).position - startingTouch;
diff = new Vector2(diff.x / Screen.width, diff.y /
Screen.width);
if (diff.magnitude > 0.01f)
{
if (Mathf.Abs(diff.y) > Mathf.Abs(diff.x))
{
if (diff.y < 0)
{
Slide();
}
else
{
Jump();
}
}
else
{
if (diff.x < 0)
{
ChangeLane(-1);
}
else
{
ChangeLane(1);
}
}
isSwipping = false;
}
}
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
startingTouch = Input.GetTouch(0).position;
isSwipping = true;
}
else if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
isSwipping = false;
}
}

Unity Swipe Inputs

I wrote a method for objectCreation at random places in the scene. I want this to happen in my game when a player Swipes the Screen. I am using the following code
void Start(){
StartCoroutine (SwipeInput ());
}
void Update(){
if (Swiped) {
if (Direction == Vector2.up) {
RandomObjects ();
} else if (Direction == Vector2.right) {
RandomObjects ();
} else if (Direction == -1 * Vector2.up) {
RandomObjects ();
} else if (Direction == -1 * Vector2.right) {
RandomObjects ();
}
}
}
IEnumerator SwipeInput ()
{
while(true){
if (Input.touchCount > 0) {
Touch t = Input.GetTouch (0);
Swiped = false;
Vector2 initial = t.position;
yield return new WaitForSeconds (0.5f);
Direction = (t.position - initial).normalised;
Swiped = true;
yield return new WaitForSeconds (0.5f);
} else {
Swiped = false;
}
}
}
But the game is not working with while(true) in Coroutine. Thanks.
You should write "normaliZed" instead of "normaliSed"

Categories