Unity, C# | How do I have a wait time between methods? - c#

My goal: To get my snail to seem like it's moving on its own.
Example: Going right for a few seconds, going left for a few seconds, staying in one place for a few seconds.
Current Status: Snail sits still in one place when I attempt to use WaitForSeconds
Without WaitForSeconds, my snail changes directions back and forth successfully(Except doing this really fast)
I've only started learning Unity and C# yesterday. Any tips/suggestions would be of much help, even if it's not on my original question.
If there's anything else I can do to help you help me, let me know! :)
using UnityEngine;
using System.Collections;
public class SnailMove : MonoBehaviour {
void Start()
{
}
// Use this for initialization
void Update ()
{
Waiting();
}
// Update is called once per frame
void Movement ()
{
int direct = Random.Range(-1, 2);
if (direct == 1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
if (direct == -1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator Waiting()
{
Movement ();
yield return new WaitForSeconds (5);
}
}

Coroutines need to be started with StartCoroutine. From your description it sounds like you want something like this:
using UnityEngine;
using System.Collections;
public class SnailMove : MonoBehaviour
{
public float speed = 1f;
int direction = 0;
void Start()
{
StartCoroutine(ChangeDirection());
}
void Update ()
{
if (direction == 1)
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
else if (direction == -1)
{
transform.Translate(Vector3.left * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator ChangeDirection()
{
while(true)
{
yield return new WaitForSeconds (5);
direction = Random.Range(-1, 2); // returns "-1", "0" or "1"
}
}
}

Good day I believe that your problem is that you are calling waiting in your update method that gets called on every frame regardless of previous executions, this implies that only the thread that called waiting before waits and as such the method can be called again as the other thread only waits.
try this:
using UnityEngine;
using System.Collections;
private bool waiting = false;
public class SnailMove : MonoBehaviour {
void Start()
{
}
// Use this for initialization
void Update ()
{
if(waiting == false)
{
Waiting();
}
}
// Update is called once per frame
void Movement ()
{
int direct = Random.Range(-1, 2);
if (direct == 1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,180);
}
if (direct == -1)
{
transform.Translate(Vector3.left * 1f * Time.deltaTime);
transform.eulerAngles = new Vector2(0,0);
}
}
IEnumerator Waiting()
{
Movement ();
waiting = true;
yield return new WaitForSeconds (5);
waiting = false;
}
}
This will make the update function wait for the boolean waiting to be set to false before it will call the function again.

Your logical flow is a little confused. You start the Waiting() coroutine every frame, when you probably want to call it once (in Start() for example) and loop your coroutine. The result is you have a whole bunch of Waiting() coroutines running and all competing with each other.
You have two options here:
void Start() {
StartCoroutine(Waiting());
}
IEnumrator Waiting() {
while(true) {
Movement();
yield return new WaitForSeconds(5f);
}
}
I got nauseated typing that though, because while(true) is a horrible idea. Better would be to track time in Update() and call Movement() every 5 seconds, like so:
private float timer = 0f;
void Update() {
timer += Time.deltaTime;
if (timer > 5f) {
Movement();
timer -= 5f;
}
}

Related

How do I get my collision function into my private void Update() on Unity?

I have object 1 with rigid body and box collider, I want it to hit object 2 (also has collider and rigid body) so I can use the collision to stop object 1 for 5 seconds then have it move through object 2 whish has kinematics on
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TRAINMOVE : MonoBehaviour
{
private int speed = 200;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
StartCoroutine(WaitBeforeMove());
}
// Update is called once per frame
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
rb.AddForce(transform.up * speed * Time.deltaTime);
}
//void OnCollision(Collision stop)
// {
// if (stop.gameObject.name == "train trigger station1")
// {
// speed = 0;
// WaitBeforeMove();
// speed = 200;
// rb.AddForce(transform.up * speed * Time.deltaTime);
// }
// else
// {
// speed = 200;
// }
// }
IEnumerator WaitBeforeMove()
{
yield return new WaitForSeconds(5);
}
}
Thats not exactly how Coroutines work.
The method/message you are looking for is called OnCollisionEnter. If it is not exactly written like that and with the expected signature then Unity doesn't find it and never invokes it.
A Coroutine does not delay the outer method which runs/starts it.
A Coroutine has to be started using StartCoroutine otherwise it does nothing (or at least it only runs until the first yield statement).
private void OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
StartCoroutine(WaitBeforeMove());
}
}
private IEnumerator WaitBeforeMove()
{
speed = 0;
// Note that without this you would have no force applied but still the remaining velocity it already has
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
speed = 200;
}
The method/message OnCollisionEnter can be a Courine itself! So in your specific case you actually can just do
// By making this an IEnumerator Unity automatically starts it as a Coroutine!
private IEnumerator OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
speed = 0;
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
speed = 200;
}
}
Finally instead of permanently continue to add 0 force I would in general rather use a simple bool flag and pause the adding of force entirely.
You should AddForce not every frame but rather in FixedUpdate.
And then you should not multiply force by Time.deltaTime. Since it is applied in fixed time intervals in FixedUpdate it is already a frame-rate independent event.
private bool stopped;
private void FixedUpdate()
{
if(stopped) return;
rb.AddForce(transform.up * speed);
}
// By making this an IEnumerator Unity automatically starts it as a Coroutine!
private IEnumerator OnCollisionEnter(Collision stop)
{
if (stop.gameObject.name == "train trigger station1")
{
stopped = true;
rb.velocity = Vector3.zero;
yield return new WaitForSeconds(5f);
stopped = false;
}
}
I suggest instead of comparing a name you should rather use a Tag and use stop.gameObject.CompareTag("Station")

I need help on this lerping issue. I am trying to make a platformer game

(Once it reaches point B, it goes to point A and back to point B in a smooth and orderly fashion). For some reason, the platform refuses to move and stays put. I have tried many things such as using vector3.movetowards and much more but nothing makes it move.
Here is the code. (Point A and Point B are empty game objects that are not parented to the platform)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTwoTransforms : MonoBehaviour
{
public Transform pointA;
public Transform pointB;
bool HeadingtowardsB;
bool HeadingtowardsA;
public float speed = 10;
// Start is called before the first frame update
void Start()
{
transform.position = pointA.position;
HeadingtowardsB = true;
HeadingtowardsA = false;
GlideAround();
}
// Update is called once per frame
void Update()
{
}
public IEnumerator GlideAround()
{
while (true)
{
while ((Mathf.Abs((pointB.position.x - transform.position.x) + (pointB.position.y - transform.position.y)) > 0.05f) && HeadingtowardsB == true && HeadingtowardsA==false )
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.Lerp(transform.position, pointB.position, speed * Time.deltaTime);
if(Mathf.Abs((pointB.position.x - transform.position.x) + (pointB.position.y - transform.position.y)) > 0.05f)
{
HeadingtowardsB = false;
HeadingtowardsA = true;
}
}
HeadingtowardsB = false;
HeadingtowardsA = true;
while (Mathf.Abs((pointA.position.x - transform.position.x) + (pointA.position.y - transform.position.y)) > 0.05f && HeadingtowardsA==true && HeadingtowardsB==false)
{
yield return new WaitForEndOfFrame();
transform.position=transform.position=Vector3.Lerp(transform.position, pointA.position, speed*Time.deltaTime);
}
}
}
}
There are no error messages, the platform won't move. The platform is still colliding and it seems to behave like a normal platform.
GlideAround() is an IEnumerator and can not be called like a method. You have to start it using StartCoroutine
StartCoroutine(GlideAround());
Also note that speed * Time.deltaTime makes little sense for usage in Lerp. You usually would want a constant value between 0-1 in your case (since you re-use the current position as first parameter).
E.g. a value of 0.5 means: Every frame set the new position to the center between the current and the target position.
Since you catch it using a threashold of 0.05f this should be fine but in general I wouldn't use Lerp like this ... with very small values you might never really reach the target position.
I would therefore prefer to either control the constant speed and use
bool isHeadingA = true;
while(true)
{
// if it was intended you can ofourse also again use
// Vector2.Distance(transform.position, isHeadingA ? pointA.position : pointB.position) <= 0.05f)
while (transform.position != (isHeadingA ? pointA.position : pointB.position))
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.MoveTowards(transform.position, isHeadingA ? pointA.position : pointB.position, speed * Time.deltaTime);
}
// flip the direction
isHeadingA = !isHeadingA;
}
!= has a precision of 0.00001 and is fine here since MoveTowards avoids overshooting so at some point it will surely reach the position if speed != 0.
Or alternatively you can use Lerp if you rather want to control the duration of the movement with a smoothed in and out speed using e.g. Mathf.PingPong as factor and Mathf.SmoothStep for easing in and out like
while(true)
{
yield return new WaitForEndOfFrame();
// linear pingpong between 0 and 1
var factor = Mathf.PingPong(Time.time, 1);
// add easing at the ends
factor = Mathf.SmoothStep(0, 1, factor);
// optionally add even more easing ;)
//factor = Mathf.SmoothStep(0, 1, factor);
transform.position = Vector2.Lerp(pointA.position, pointB.position, factor);
}
Try this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTwoTransforms : MonoBehaviour
{
public Transform pointA;
public Transform pointB;
bool HeadingtowardsB;
bool HeadingtowardsA;
public float speed = 10;
// Start is called before the first frame update
void Start()
{
transform.position = pointA.position;
HeadingtowardsB = true;
HeadingtowardsA = false;
StartCoroutine(GlideAround());
}
// Update is called once per frame
void Update()
{
}
public IEnumerator GlideAround()
{
//Because we want a specific speed, the % between the two points
//that we should be at will be equal to (time * speed) / distance
//with an adjustment for going backwards.
float distance = Vector3.Distance(pointA, pointB) * 2;
float lapTime = distance / speed;
float startTime = Time.time;
Debug.Log("The platform speed is: " + speed.ToString());
Debug.Log("The distance for one full lap is: " + distance.ToString());
Debug.Log("One lap will take: " + lapTime.ToString() + " seconds");
while (true)
{
yield return new WaitForEndOfFrame();
float elapsedTime = (Time.time - startTime) % lapTime;
float progress = elapsedTime / (lapTime / 2);
if (progress > 1){
progress = 2 - progress;
}
Debug.Log("The platform speed is currently: " + progress.ToString() + "% between pointA and pointB");
transform.position = Vector2.Lerp(pointA.position, pointB.position, progress);
}
}
As I mentioned in the comments, you Lerp uses a percentage between two points as the return value. You need to give it a percent, not a speed.
Here is an implementation that uses speed, like you wanted, but #derHugo's answer with PingPong is much simpler!
The main issue is that you are not using coroutines properly, as pointed out in derHugo's answer.
However, I'll provide my own answer, seeing that you are making the rookie mistake of way over-engineering this problem.
I think teaching by example might be the most appropriate in this case, so here it is:
If the points dictating the platform's movement are static, you should do this with animation. I won't explain it here. Tutorials like this one can easily be found all over the unity tutorials, unity forums, other StackOverflow Q&As, and youtube.
If your points are dynamic, this is more than enough:
public class MoveTwoTransforms : MonoBehaviour {
public Transform pointA;
public Transform pointB;
public float speed = 10;
void Start() {
transform.position = pointA.position;
StartCoroutine(GlideAround());
}
private IEnumerator MoveTowards(Vector3 targetPosition) {
while (transform.position != targetPosition) {
transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
yield return null;
}
}
private IEnumerator GlideAround() {
while(true) {
yield return StartCoroutine(MoveTowards(pointA));
yield return StartCoroutine(MoveTowards(pointB));
}
}
}
Just a final note:
If the platform should have physics or a collider, it is preferable to add a Rigidbody, set it to be kinematic, and to the movement by setting the Rigidbody.position instead of the transform. This is because that is updated on the physics loop (FixedUpdate) rather than the frame loop (Update), and avoids some bugs related to asyncrony between the physics system and moving objects through transform's position.
rigidbody.position = Vector3.MoveTowards(rigidbody.position, //...
Here is the code that worked.
public IEnumerator GlideAround()
{
while (true)
{
while (HasReachedA == false)
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.Lerp(transform.position, pointA.position, 0.01f);
if ((Mathf.Abs(Vector2.Distance(pointA.position, transform.position)) < 0.01f))
{
HasReacedB = false;
HasReachedA = true;
}
}
while (HasReacedB == false)
{
yield return new WaitForEndOfFrame();
transform.position = Vector2.Lerp(transform.position, pointB.position, 0.01f);
if ((Mathf.Abs(Vector2.Distance(pointB.position, transform.position)) < 0.01f))
{
HasReacedB = true;
HasReachedA = false;
}
}
}
}

How can I wait number of seconds before changing for new random speed? [duplicate]

This question already has answers here:
How to make the script wait/sleep in a simple way in unity
(7 answers)
Closed 4 years ago.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GateControl : MonoBehaviour
{
public Transform door;
public float doorSpeed = 1.0f;
public bool randomDoorSpeed = false;
[Range(0.3f, 10)]
public float randomSpeedRange;
private Vector3 originalDoorPosition;
// Use this for initialization
void Start()
{
originalDoorPosition = door.position;
}
// Update is called once per frame
void Update()
{
if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
{
StartCoroutine(DoorSpeedWaitForSeconds());
}
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
Mathf.PingPong(Time.time * doorSpeed, 1.0f));
}
IEnumerator DoorSpeedWaitForSeconds()
{
doorSpeed = Random.Range(0.3f, randomSpeedRange);
yield return new WaitForSeconds(3);
}
}
Making StartCoroutine inside the Update is a bad idea. But I want that it will take one random speed when running the game then will wait 3 seconds and change to a new random speed then wait another 3 seconds and change for another new random speed and so on.
And while it's waiting 3 seconds to keep the current speed constant until the next change.
Update:
This is what I tried:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GateControl : MonoBehaviour
{
public Transform door;
public float doorSpeed = 1.0f;
public bool randomDoorSpeed = false;
public bool IsGameRunning = false;
[Range(0.3f, 10)]
public float randomSpeedRange;
private Vector3 originalDoorPosition;
// Use this for initialization
void Start()
{
IsGameRunning = true;
originalDoorPosition = door.position;
StartCoroutine(DoorSpeedWaitForSeconds());
}
// Update is called once per frame
void Update()
{
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
Mathf.PingPong(Time.time * doorSpeed, 1.0f));
}
IEnumerator DoorSpeedWaitForSeconds()
{
var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
while (IsGameRunning)
{
if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
doorSpeed = Random.Range(0.3f, randomSpeedRange);
yield return delay;
}
}
}
But there are two problems.
The first problem is that every 3 seconds, when it's changing the speed of the door, it's also changing the door position from its current position. So it looks like the door position is jumping to another position and then continue from there. How can I make that it will change the speed meanwhile the door keep moving from its current position ?
Second problem is how can I change the randomDorrSpeed flag so it will take effect while the game is running? I Want that if randomDorrSpeed is false use the original speed of the door (1.0) and if it`s true use the random speed.
You already know that the coroutine should start from Start:
void Start()
{
//initialization
StartCoroutine(DoorSpeedWaitForSeconds());
}
So make the coroutine a loop with the proper terminate condition:
IEnumerator DoorSpeedWaitForSeconds()
{
var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
while(IsGameRunning)
{
if(randomDoorSpeed == true && randomSpeedRange > 0.3f)
doorSpeed = Random.Range(0.3f, randomSpeedRange);
if(!randomDoorSpeed)
doorSpeed = 1;//reset back to original value
yield return delay;//wait
}
}
For the other question you asked, if you think about it you can't possibly use ping pong with dynamic speed based on Time.time. You need to change it like this:
bool isRising = true;
float fraq = 0;
void Update()
{
if (isRising)
fraq += Time.deltaTime * doorSpeed;
else
fraq -= Time.deltaTime * doorSpeed;
if (fraq >= 1)
isRising = false;
if (fraq <= 0)
isRising = true;
fraq = Mathf.Clamp(fraq, 0, 1);
door.position = Vector3.Lerp(originalDoorPosition,
new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
fraq);
}
You can solve the original problem without coroutines:
public float timeBetweenChangeSpeed = 3f;
public float timer = 0;
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If 3 seconds passed, time to change speed
if(timer >= timeBetweenChangeSpeed)
{
timer = 0f;
//Here you call the function to change the random Speed (or you can place the logic directly)
ChangeRandomSpeed();
}
}
And about opening and closing doors. Here is a script I used to control doors in a maze game I worked in:
You need to set empty gameObjects with to set the boundaries, that is until what point you want to move the door one opening or when closing. You place this empty gameobjects in your scene and link them to the scrip in the correct field. The script will take the transform.position component on it's own. There is also a trigger enter to activate the door when a character approaches. If you dont need that part, I can edit the code tomorrow.
You can use this script also to move platforms, enemies... in general anything which can move in a straight line.
using UnityEngine;
using System.Collections;
public class OpenDoor : MonoBehaviour {
// define the possible states through an enumeration
public enum motionDirections {Left,Right};
// store the state
public motionDirections motionState = motionDirections.Left;
//Variables for State Machine
bool mOpening = false;
bool mClosing = false;
//bool mOpened = false;
//OpenRanges to open/close the door
public int OpenRange = 5;
public GameObject StopIn;
public GameObject StartIn;
//Variables for Movement
float SpeedDoor = 8f;
float MoveTime = 0f;
int CounterDetections = 0;
void Update () {
// if beyond MoveTime, and triggered, perform movement
if (mOpening || mClosing) {/*Time.time >= MoveTime && */
Movement();
}
}
void Movement()
{
if(mOpening)
{
transform.position = Vector3.MoveTowards(transform.position, StopIn.transform.position, SpeedDoor * Time.deltaTime);
if(Vector3.Distance(transform.position, StopIn.transform.position) <= 0)
mOpening = false;
}else{ //This means it is closing
transform.position = Vector3.MoveTowards(transform.position, StartIn.transform.position, SpeedDoor * Time.deltaTime);
if(Vector3.Distance(transform.position, StartIn.transform.position) <= 0)
mClosing = false;
}
}
// To decide if door should be opened or be closed
void OnTriggerEnter(Collider Other)
{
print("Tag: "+Other.gameObject.tag);
if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player" || Other.gameObject.tag == "Elevator")
{
CounterDetections++;
if(!mOpening)
Opening();
}
}
void OnTriggerStay(Collider Other)
{
if(Other.gameObject.tag == "Elevator")
{
if(!mOpening)
Opening();
}
}
void OnTriggerExit(Collider Other)
{
if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player")
{
CounterDetections--;
if(CounterDetections<1)
Closing();
}
}
void Opening()
{
mOpening = true;
mClosing = false;
}
void Closing()
{
mClosing = true;
mOpening = false;
}
}
Using timer and setting an interval. The delegate event will fire every time the interval is reached.
var t = new Timer {Interval = 3000};
t.Elapsed += (sender, args) => { /* code here */};

Recursive call to buff/unbuff? C# Unity3D

My goal is to make a single collision detection that will decrease the movement speed of the object it collided with for a specific duration.
What I tried so far:
//Class that detects the collision
if (other.gameObject.tag == "enemy")
{
EnemyMovement enemyMove = other.GetComponent <EnemyMovement> ();
if (enemyMove.slowMove != 1) {
return;
}
enemyMove.Slow (2, 0.5f, true);
//....
//Class that handles the Enemy-Movement
//The slowfactor gets multiplied with the Vector3 that handles the movementspeed of the Character
void FixedUpdate ()
{
Movement();
}
void Movement()
{
gegnerRigid.MovePosition (transform.position + (gegnerMove * slowMove));
}
public void Slow (float duration, float slowFactor, bool slowed)
{
if (slowed)
{
if (duration > 0) {
duration -= Time.deltaTime;
slowMove = slowFactor;
Slow (duration, slowFactor, slowed); //this recursive Call leads to huge performance issues, but how to keep the function going?
} else {
slowMove = 1;
slowed = false;
}
}
}
So what I wanted to happen:
Call the Slow-function if collision happens and make it invoke itself until the duration is 0.
Note, the key here is that
1. You have the buff/unbuff on the other object.
You just call to the other object from the 'boss' object. Do not put the actual buff/unbuff code in your 'boss' object. Just "call for a buff".
In other words: always have buff/unbuff code on the thing itself which you are buffing/unbuffing.
2. For timers in Unity just use "Invoke" or "invokeRepeating".
It's really that simple.
A buff/unbuff is this simple:
OnCollision()
{
other.GetComponent<SlowDown>().SlowForFiveSeconds();
}
on the object you want to slow...
SlowDown()
{
void SlowForFiveSeconds()
{
speed = slow speed;
Invoke("NormalSpeed", 5f);
}
void NormalSpeed()
{
speed = normal speed;
}
}
If you want to "slowly slow it" - don't. It's impossible to notice that in a video game.
In theory if you truly want to "slowly slow it"...
SlowDown()
{
void SlowlySlowForFiveSeconds()
{
InvokeRepeating("SlowSteps", 0f, .5f);
Invoke("NormalSpeed", 5f);
}
void SlowSteps()
{
speed = speed * .9f;
}
void NormalSpeed()
{
CancelInvoke("SlowSteps");
speed = normal speed;
}
}
It's that simple.

Why can't I jump, or jump well?

Right now I'm not getting much Out of this. Depending on what I do different i either end up with an infinite loop, or poor jumping ability. I used a timer to tick my jumped bool but I was getting a double like jump ability and my ground detection wasn't good enough. Can you See why I can't jump, or jump well?
using UnityEngine;
using System.Collections;
public class player : MonoBehaviour
{
public float speed = 0.05f;
public float jumpVelocity = 0.05f;
public bool onGround = true;
public bool jumped = false;
// Use this for initialization
void Start () { }
// Update is called once per frame
void Update ()
{
//test if player is on the ground
if (onGround) { jumped = false; }
// USER CONTROLS HERE.
if (Input.GetKeyDown(KeyCode.Space) && onGround == true)
{
jumped = true;
while(jumped)
{
this.rigidbody2D.AddForce(new Vector2(0, jumpVelocity));
if (onGround) { jumped = false; }
}
}
else if (Input.GetKey(KeyCode.RightArrow))
{
this.transform.position += Vector3.right * speed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
this.transform.position += Vector3.left * speed * Time.deltaTime;
}
}
void OnCollisionEnter2D(Collision2D col)
{
if(col.gameObject.tag == "floor") { onGround = true; }
}
void OnCollisionStay2D(Collision2D col)
{
if(col.gameObject.tag == "floor") { onGround = true; }
}
}
Your problem stems from a misunderstanding how the Update method and physics work. If you do this in the update method, it will create an endless loop:
while(jumped)
{
this.rigidbody2D.AddForce(new Vector2(0, jumpVelocity));
if(onGround)
{
jumped = false;
}
}
The thing is that you tell the physics body to add a force. But you keep doing so over and over again. The physics simulation only takes place after the Update method returns, so whatever "onGround" is it will never become true because the forces aren't being applied until after the Update method.
Instead you have to make this check over and over again every time the Update method runs until onGround is true.

Categories