My implementation of Lerp should gradually increase the light from minbrightness to maxBrightness over time. It does change the range of my light however it is immediately going to my maxBrightness instead of gradually increasing. Where have I gone wrong?
Here is the code I am using
private void Update()
{
//this is a timer that will only only count down when collided = true
if (_collided == true)
{
timeLeft -= Time.deltaTime;
_light1.range = Mathf.Lerp(minbrightness, maxBrightness, lightTimer);
//increases interloper
lightTimer += _brightenRate * Time.deltaTime;
}
else
{
//this sets the lights range value to be bigger then normal
_light1.range = Mathf.Lerp(maxBrightness, minbrightness, lightTimer);
//increases interloper
lightTimer += _brightenRate * Time.deltaTime;
}
//checks if the time value is 0
if (timeLeft <= 0)
{
//this resets the value back
timeLeft = timeLeftReset;
_collided = false;
}
}
I have heard of IEnumerator, but am unsure of how to apply it to my current solution or if that will even fix my current problem.
Related
I have a code that works just fine but i think if i keep following the same strategy to do all the same things it's gonna over load on the processor for no reason
I have a variable that represents the time and this variable rests to 0 in every frame that the gameObject has a velocity higher than 0.5f so instead of resetting it every frame i want to start the timer when it's below 0.5f
if (speed >= 0.5f)
{
t = 0;
}
t = t + Time.deltaTime;
You could use a bool value to save performance.
public static bool isTimerMoving = false;
public void Update()
{
if (speed < 0.5f)
{
t = t + Time.deltaTime;
isTimerMoving = true;
}
else if (isTimerMoving) {
t = 0;
isTimerMoving = false;
}
}
This code resets the timer whenever speed reaches 0.5f. If you only want to pause the timer, you can remove the t = 0 from it.
P.S. using > or < is faster than using <= or >=. Not by very much, but I like keeping things efficient ;)
EDIT: After asking a question, responses indicate that this statement is false, my apologies.
I have been working on a Unity2d project for a while now and I recently implemented a method of which my "Enemy" housed in the GreyGuardController script would fire a bullet in the direction of which it would be facing, using the animator and
otherAnimator = otherObject.GetComponent<Animator>();
for this.
Every time I now run my code, my game freezes but doesn't crash (I think it is stuck in a loop but there are no real loops in my program). It isn't my instantiation of the bullet before anyone starts accusing that as the loop of it freezing as I have commented this out and changed things around over and over again.
public class HurtPlayer : MonoBehaviour {
public float timeToShoot;
private float timeToShootCounter;
private bool shot;
private Vector3 moveDirection;
public float timeBetweenShot;
public float timeBetweenShotCounter;
public Transform firePoint;
public GameObject Bullet;
// Use this for initialization
void Start()
{
shot = false;
timeToShootCounter = timeToShoot;
timeBetweenShotCounter = timeBetweenShot;
}
IEnumerator ExecuteAfterTime(float time)
{
yield return new WaitForSeconds(time);
}
// Update is called once per frame
void Update () {
if (shot == true)
{
timeBetweenShot -= Time.deltaTime;
timeToShoot -= Time.deltaTime;
if (timeBetweenShot <= 0f)
{
shot = false;
timeToShoot = timeToShootCounter;
timeBetweenShot = timeBetweenShotCounter;
}
}
}
void OnTriggerStay2D(Collider2D other)
{
if (other.gameObject.tag == "player")
{
if(shot == false)
{
if (timeToShoot >= 0f)
{
shot = true;
while(shot == true)
{
Instantiate(Bullet, firePoint.position, firePoint.rotation);
if (timeBetweenShot <= 0f)
{
shot = false;
timeToShoot = timeToShootCounter;
timeBetweenShot = timeBetweenShotCounter;
}
}
}
}
}
}
This here is my code attached to my guard which instantiates a bullet as well as trying to use variables "TimeToShoot" as a counter for how long the enemy has left to shoot for and "TimeBetweenShoot" as a counter for how long the enemy has in between shots.
This doesn't work and neither does the Enumerator delay.
As an amateur I am obviously doing something clearly wrong but I have no idea what I'm doing wrong or where and would greatly appreciate your help.
while(shot == true)
this will freeze the editor if the body is never left
if (timeBetweenShot <= 0f)
{
shot = false;
if this is not executed in the first iteration, it won't be in the second because you never change the value of "timeBetweenShot" in that loop
It is important to understand that your update function needs to terminate for the game frame to continue with the next game object's update etc, until the end of the frame is reached, before the next update is called on this game object in the next game frame, so
void Update () {
if (shot == true)
{
timeBetweenShot -= Time.deltaTime;
is never executed while your while loop goes rogue
EDIT:
try something like:
// Update is called once per frame
void Update()
{
if (timeToShoot >= 0f) // if we are shooting at all
{
timeToShootCounter -= Time.deltaTime; // make sure we'll stop shooting after the given amount of time (decrease countdown until negative
timeBetweenShotCounter -= Time.deltaTime; // decrease countdown until next shot (after some intervall)
if (timeBetweenShotCounter <= 0f) // if intervall since last shot expired
{
Instantiate(Bullet, firePoint.position, firePoint.rotation); // shoot
timeBetweenShotCounter += timeBetweenShot; // add the time to wait for the next shot to the intervall (so that we don't shoot anymore in the following frames, until this time expired again (by becoming negative))
}
}
}
void OnTriggerStay2D(Collider2D other)
{
if (other.gameObject.tag == "player")
{
timeToShootCounter = -1f; // initialise as expired (start shooting immediately)
timeBetweenShotCounter = timeBetweenShot; // shoot in intervalls for this amount of time
}
}
this way, when the collision event is triggered, you reset the counters to their initial values. After that the update function makes sure to fire after intervals of time, and stops once the overall shooting time is over.
Of course you can further improve this code to handle edge cases (if overall time expires and intervals time also expires at the same time, do we shoot a last bullet or not? etc)
hope this helps.
If you appreciate my efforts, please give them a thumbs up =)
Here is your loop: you increase timeBetweenShot on each frame but your while have to be executed in one frame, this means your code executes this while until you enter the if statement but you will never do since timeBetweenShot will change value only in next frame
while(shot == true)// here is your loop budy
{
// shot = false; // try this row here you will problably stop having the trouble
Instantiate(Bullet, firePoint.position, firePoint.rotation);
if (timeBetweenShot <= 0f)//
{
shot = false;
timeToShoot = timeToShootCounter;
timeBetweenShot = timeBetweenShotCounter;
}
}
This has been asked before, but none of the answers solved my problem because the problem was always slightly different.
I have a character that jumps on spacebar down. I want it to make higher jumps when the spacebar is pressed longer, with a maximum of twice the normal jump height.
Here's what I came up with so far:
void FixedUpdate () {
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
timeHeld = 1;
}
if (Input.GetKey(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}
Since the jump has to happen on keydown (not keyup), I can't increase the force added on jump, because the force is already applied on keydown. Therefore, I was thinking of lowering the mass of my rigidbody.
The above code "works" if I keep holding spacebar: the character jumps (minimum height), lands, jumps again but now a bit higher, etc. But that's not what I'm looking for, obviously.
This can easily be done by making a Time frame in which Jumping occurs;
Within this time frame u allow upward forces to be applied by holding space bar down. As soon as you reach either the end of the time frame or the end of the button press; you restrict upward velocity until the character has landed.
Let gravity take its own course after you end the jump.
As for the coding part i suggest you start a co routine when the jump happens.
here is some code to u help you get started;
IEnumerator Jumper()
{
if (maxjumpduration!=jumpduration)
{
jumpduration = jumpduration + 0.1f;
yield return new WaitForSeconds(0.1f);
}
else
{
jumpduration = 0;
StopCoroutine(Jumper());
}
}
As for the fact you want have a regular jump as well; make another time frame in which is decided if the press of space bar is considered either a regular jump or a controlled jump; During that initial time frame in which you are still deciding what kind of jump it is; you execute a short part of the jump until you reach a conclusion and then you send it to the correct method.
I added Some ground work for u but try to finish the code yourself;
{
private bool shortjump = false;
private bool checkphase = false;
private bool hitground = false;
private Rigidbody player = new Rigidbody();
private bool jumping = false;
Vector3 sharedjumpforce = new Vector3();
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Initialjump();
}
if (Input.GetKeyUp(KeyCode.Space))
{
if (jumping)
{
shortjump = true;
}
}
if (jumping)
{
if (hitground)
{
jumping = false;
}
}
}
void Initialjump()
{
if (jumping = false)
{
checkphase = true;
jumping = true;
player.AddForce(sharedjumpforce);
Invoke("Standardorcontrolledjump", 0.2f);
}
}
void Standardorcontrolledjump()
{
checkphase = false;
if (shortjump)
{
}
else
{
}
}
}
I don't understand why are you putting
&& myRB.velocity.y == 0
You want it to reduce its mass while in air don't you. Assuming that reducing the mass after the initial force has been applied does allow the Rigidbody to go higher, (force of gravity weakens, im not sure if that happens in Unity)
Why don't you try this
void FixedUpdate () {
// apply force the instant button is pressed. That is only once
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld = 1;
}
// keep subtracting from mass while its held
if (Input.GetKey(KeyCode.Space))
{
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}
I have enemies that patrol to different waypoints using NavMesh Agent I want when the enemy reach the next waypoint to have the same rotation as that waypoint.
Here is the code:
void Update ()
{
if (agent.remainingDistance < 0.1)
{
// tried to stop the agent so I can override it's rotation, doesn't work
agent.Stop();
// Give him the desired rotation
transform.rotation = wayPoints[curretPoint].rotation;
if (curretPoint < wayPoints.Length -1)
{
curretPoint++;
}
else
{
curretPoint = 0;
}
// make him wait for a fixed amount of time
patrolTimer += Time.deltaTime;
if (patrolTimer >= patrolWait)
{
patrolTimer = 0;
agent.SetDestination (wayPoints[curretPoint].position);
agent.Resume ();
}
}
}
The problem is that he keeps rotating back and forth very quickly, I can't get teh desired effect that I want.
Try setting Angular Speed of NavMesh Agent to 0.
Edit:
That should work:
// make him wait for a fixed amount of time
patrolTimer += Time.deltaTime;
if (patrolTimer >= patrolWait)
{
if (curretPoint < wayPoints.Length -1)
{
curretPoint++;
}
else
{
curretPoint = 0;
}
patrolTimer = 0;
agent.SetDestination (wayPoints[curretPoint].position);
agent.Resume ();
}
This is how I handled it:
Instead of doing agent.Stop(); and agent.Resume(); I simply set its speed to 0 and used transform.Rotate to rotate the character.
I desire to increment an float by 0.5 every time the user clicks the UI button and if the user presses the button for more than 2 second want to continuously increment the float by 0.5, to do so i use Event trigger (PointerDown, PointerUp) and call the functions in update. When i user the down below code i cant increment the float value continuously.
Update Code
void Update () {
transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);
if(Time.timeScale == 0)
transform.rotation = Quaternion.Euler(0,0,0);
clickCondition ();
}
PointerDown Function
public void WhenIncreaseClicked()
{
if (timeDown < 2.0f)
IncreaseBPM ();
else
increase = true;
}
PinterUp function
public void WhenIncreaseNotClicked()
{
increase = false;
Time.timeScale = 1;
}
IncreaseBPM
public void IncreaseBPM()
{
if (speed < 12)
{
speed += 0.05f;
bpmText.GetComponent<BeatTextControl> ().beats += 1;
PlayerPrefs.SetFloat ("savedBPM", speed);
}
}
ClickCondition
public void clickCondition()
{
if(increase)
{
IncreaseBPM();
}
else if(decrease)
{
DecreaseBPM();
}
}
Start
void Start () {
qStart = Quaternion.AngleAxis ( angle, Vector3.forward);
qEnd = Quaternion.AngleAxis (-angle, Vector3.forward);
timeDown = Time.deltaTime;
if (PlayerPrefs.HasKey ("savedBPM"))
speed = PlayerPrefs.GetFloat ("savedBPM");
else
speed = 1.5f;
}
I have set timeDown = Time.deltaTime in Start().
Assuming no other code alters your increase variable, you'll be unable to increment it continuously because it will never be set to true.
In Start() you have a line timeDown = Time.deltaTime;, so timeDown will be equal to the number of seconds since the last frame. Not only is this an issue because timeDown never changes (Start() is only called once), but it's an issue because it's not likely to ever be above 2.0f since a single frame is highly unlikely to take 2 seconds to complete. It will generally be a very small number, for example 0.06f.
Due to this, in your WhenIncreaseClicked() method, the if (timeDown < 2.0f) will always equate to true. Thus the else clause is never executed and increase is never set to true.
To resolve this you could create a new boolean variable, e.g. clicked and set it to true at the start of WhenIncreaseClicked() and false at the start of WhenIncreaseNotClicked(). Then in Update() you can just add Time.deltaTime to timeDown if clicked is true. You'll also want to move that if/else outside of WhenIncreaseClicked() also, and into Update(), making sure it's only run when clicked is true.
For example:
void Update () {
transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);
if(Time.timeScale == 0)
transform.rotation = Quaternion.Euler(0,0,0);
if(clicked) {
timeDown += Time.deltaTime;
if (timeDown >= 2.0f) // note the >= not <
increase = true;
}
clickCondition ();
}
and WhenIncreaseClicked():
public void WhenIncreaseClicked()
{
clicked = true;
IncreaseBPM();
}
and WhenIncreaseNotClicked():
public void WhenIncreaseNotClicked()
{
clicked = false;
increase = false;
Time.timeScale = 1;
}
You can also remove the assignment to timeDown in Start() since it's not useful.
First of all, Unity documentation says about Time.deltaTime
The time in seconds it took to complete the last frame.
When you set timeDown = Time.deltaTime timeDown becomes a tiny fraction, for example 0.01621689. Therefore, timeDown < 2.0f always returns true and your code never reaches increase = true; line.
Second point you should know is Time.time
The time at the beginning of this frame (Read Only). This is the time in seconds since the start of the game.
You used Time.time in your Update() method as Mathf.Sin(Time.time * speed). Bear in mind that Time.time can be enough large number representing the time in seconds since the start of the game as mentioned in document. When you do Time.time * speed the output number may be huge (assuming speed > 1) causing some problems. Luckily, you are using it inside Mathf.Sin() you get number only between [0, 1]. Probably, you intended to use Time.deltaTime instead.
Let's remember Time.time:
The time in seconds since the start of the game
You can use this to check time difference.
float lastDownTime;
bool isDown;
void OnPointerDown() // Method name itself says when it should be called
{
lastDownTime = Time.time;
isDown = true;
}
void OnPointerUp()
{
isDown = false;
}
void Update ()
{
if (isDown)
{
if (Time.time - lastDownTime > 2) // 2 seconds
{
IncreaseBPM ();
}
}
}
Note: Unity says about Time.timeScale:
Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.
So if you insist on using Time.timeScale, instead of using Time.time you should use Time.realtimeSinceStartup in above example.