Cooldown for Slowmo - c#

I know the problem is simple, but I'm new to Unity and don't understand how to do it. I would like for there to be a delay between the ability to cause time dilation and the deceleration itself to last no more than a certain time.
{
void Start ()
{
}
void FixedUpdate ()
{
if (Input.GetKey (KeyCode.Mouse1))
{
Time.timeScale = 0.1f;
Time.fixedDeltaTime = Time.timeScale * 0.01f;
}
else
{
Time.timeScale = 1f;
}
}
}

By looking at your code i would totally suggest you to watch and study more tutorials on unity. I will still write down a simple delay logic with comments.
private float _lastTimeAbilityUsed;
private float _abilityCooldown = 2f; // cooldown for 2 seconds
private void Update()
{
if(_lastTimeAbilityUsed < Time.time - _abilityCooldown) return; // if not enough time has passed, returning
if (Input.GetKey (KeyCode.Mouse1))
{
_lastTimeAbilityUsed = Time.time; // saving the time when ability is used
}
}

Related

How do I get the boss to attack again 10 seconds after the last attack?

I'm new in unity and all the programing language so I don't know How do I get the bossPattern to starts again after 10 seconds when the boss pattern is over. could you can give how to make that?
I want to make sure that the pattern starts again after 10 seconds when the boss pattern is over.
You can implement a simple timer and after 10 seconds start your "StartBossPattern" and reset your timer:
float timer = 0f;
void Update()
{
timer -= Time.deltaTime;
if (timer <= 0f)
{
//Start Boss Pattern
timer = 10f;
}
}
But this is only one way to do it.
method 1:
float lastAttackTime=0;
float attackTimeGap=10;
void update()
{
if (Time.time-lastAttackTime>attackTimeGap)
{
//attack
lastAttackTime = Time.time;
}
}
method 2:
void update()
{
startCoroutine(Attack());
}
IEnumerator Attack()
{
//attack
yeild return new WaitForSeconds(10);
startCoroutine(Attack());
}

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

How to Damage Player after each Second if he is on Spikes?

I got Spikes and the bool onSpikes, which tells if the player is onSpikes or not.
Currently the health goes Down constantly, if the player is onSpikes.
if(onSpikes)
{
health -= 0.01f;
}
But I think this it isn't a good solution, cause I'm in void Update(), and I anyways wanted the Health to drop in bigger pieces ( like -0.2f each second).
I've already tried building an Method and use Invoke, but like this my player didn't lost health at all.
Code:
private void Update(){
Debug.Log("Player on Spikes: "+SpikeDMG.onSpikes);
bar.localScale = new Vector3(health,1f);
if(SpikeDMG.onSpikes)
{
Invoke("doDmg",1);
}
//Wenn leben unter 0 fällt ==> starte szene neu
if(health <=0){
int scene = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(scene, LoadSceneMode.Single);
Time.timeScale = 1;
SpikeDMG.onSpikes = false;
}
}
void doDmg(){
health -= 10/100;
}
}
Thanks to everyone who can help!
What you want to do is use some kind of time stamp, when your next action should be executed. It is also described here and here.
private float spikeDamageAt= 0.0f;
void update() {
if(onSpikes && Time.time >= spikeDamageAt) {
health -= 0.01f;
spikeDamageAt= Time.time + 1.0f; // for 1 seconds
}
}

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.

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

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

Categories