I have a shader in Unity that is set up to blend between two textures. This is set up and works fine.
Blend has a range from 0-1 and works well on offline mode.
_Blend1("Blend between _MainTex and Texture2", Range(0, 1)) = 0
I have set up an OnClick pointer that works fine. It essentially toggles a value to true and activates it in the Update. I have had some success on toggling the values between 0 (The first texture and 1 (The second texture).
public void OnColorChangeClick()
{
if (newSwitchOne)
{
switchOn = true;
}
else if (newSwitchTwo)
{
switchOff = true;
}
}
In the update when switchOn is true I have a while loop that runs and increments a count for the blend.
void Update()
{
rend.material.SetFloat("_Blend1", up);
while (switchOn == true) {
for (int i = 0; i < 10; i++)
{
//StartCoroutine(Wait());
up = Time.deltaTime * (up + 0.1f);
}
switchOn = false;
print(switchOn);
}
}
The trouble I am having is that the value increments are not working alongside time.deltaTime. I am seeing that Time.deltatime may not work in a while loop. So I have also tried a CoRoutine with a WaitForSeconds. None of this is giving me the incrementation that I desire.
I have looked into Lerping this - but I'm not aware how to Lerp such a value - I have been looking, perhaps in the wrong places.
Can someone point me in the right direction?
Time.deltaTime returns the time it took to complete the last frame so it will be roughly constant as you loop through (and a very small value) - which is keeping your up value to remain tiny. You should be able to lerp the value like so.
float t = 0;
void Update()
{
if (switchOn == true)
{
t += Time.deltaTime;
rend.material.SetFloat("_Blend1", Mathf.Lerp(0, 1f, t/3f)); //3 is time to complete lerp
}
if (t > 3) // lerp has completed. reset function and timer.
{
t = 0;
switchOn = false;
}
}
Update() already runs "over time." You don't need a for loop or a coroutine. You just need to track a variable that changes inside the Update() method body.
up = Time.deltaTime * (up + 0.1f);
Oh wait, you already do.
void Update()
{
rend.material.SetFloat("_Blend1", up);
if(switchOn == true) {
up = Time.deltaTime * (up + 0.1f);
if(up >= 1) {
switchOn = false;
}
print(switchOn);
}
}
Ta da.
However, you still need code to bring the value back down again (either animating it back to 0 or just setting it to 0) but your original code didn't have it either, so I'm not including it.
Related
if(GetComponent<Rigidbody2D>().position.y >= -2.4){
abletojump = false;
}
else{
abletojump = true;
}
if(abletojump == true && Input.GetKey("space")){
transform.Translate(Vector3.up * 10 * Time.deltaTime);
}
I have made it so that if the object is over a specific height they shouldn't be allowed to jump. But it seems that when ever I set that height range it always seems to go lower than that so it repeatedly keeps jumping in the air. anyways knowing how to tell if a key has been pressed the an amount of times or to detect how long a key has been pressed for would really help.
Thanks.
Save the time when button is pushed Input.GetKeyDown and while the button is held downInput.GetKey find the difference between currentTime and the time that the button was pushed.
float timeThatshouldBePassed = 5f;
float pushStart = 0f;
void Update() {
if (Input.GetKeyDown(KeyCode.Space)) {
pushStart = Time.time;
}
if (Input.GetKey(KeyCode.Space)) {
if ((Time.time - pushStart) > timeThatshouldBebPassed) {
// doSomethings
}
}
}
I'm trying to code a behaviour for my boss where it charges at the player but before charging it is supposed to flicker a bit to show intent of charge. Below is how I am achieving this in Update():
if (chargeTimer <= 0)
{
if (!returnToStart)
{
StartCoroutine(TankSpriteFlicker());
if (chargeNow)
{
transform.position = Vector3.MoveTowards(transform.position, chargeTarget, Time.deltaTime * chargeSpeed);
// Target reached? If so, start moving back to the original position
if (Vector3.Distance(transform.position, chargeTarget) <= Mathf.Epsilon)
{
returnToStart = true;
this.chargeTimer = this.chargeRate;
}
chargeNow = false;
}
}
else
{
transform.position = Vector3.MoveTowards(transform.position, tankStartPosition, Time.deltaTime * returnSpeed);
// Original position reached? If so, start moving to the target
if (Vector3.Distance(transform.position, tankStartPosition) <= Mathf.Epsilon)
{
returnToStart = false;
this.chargeTimer = this.chargeRate;
}
}
}
else
{
this.chargeTimer -= Time.time;
}
IEnumerator TankSpriteFlicker()
{
for (int i = 0; i <= 2; i++)
{
tankSprite.color = Color.red;
yield return new WaitForSeconds(0.1f);
tankSprite.color = startColor;
yield return new WaitForSeconds(0.1f);
}
chargeNow = true;
}
chargeTarget is a fixed value of chargeTarget = new Vector3(-2.5f, transform.position.y, transform.position.z);
The problem with this is that it charges, but stops midway and then charges again.
Also as time passes by the flickering becomes very random and it starts flickering during and after a charge..
Here is the problem in action:
https://gfycat.com/latefrigidbullmastiff-rivalsofaether
I can't explain any of this behaviour and cant fix it, any help would be appreciated.
This is not how coroutines work
Lets look at just these lines:
StartCoroutine(TankSpriteFlicker());
if (chargeNow) { ... }
You start a coroutine, that's fine, but your next instruction asks if the coroutine has been completed (as chargeNow is not set to true until the last line of the coroutine). This cannot and will not ever be true at this point in the execution because coroutines are fundamentally "go do this stuff later" and later is not now.
You need to move these additional pieces of logic (the stuff that happens "after" the coroutine) to the end of the coroutine.
Ok, so I have an animationnthe speed of which is controlled by user's tapping m meaning I cant just lerp for a set time but have to have it depend on if this is true:
cameraAnim.GetCurrentAnimatorStateInfo (0).IsName ("stillOpening")
By the end of this animation (no matter how long it took, fast or slow) I need this float in my material to have lerped to its final value:
skybox.SetFloat ("_Exponent1",Mathf.Lerp(skybox.GetFloat("_Exponent1"), topSkyBoxOpen, ratio));
Meaning it has to be equal to topSkyBoxOpen at the end of "stillOpening". I don't know how to coordinate the timing.
I have tried this in the Update():
void openSkyLerp()
{
float ratio = 0;
float duration = 0.5f; // this is the one that will control how long it takes
// value is in second
float multiplier = 1 / duration;
while (cameraAnim.GetCurrentAnimatorStateInfo (0).IsName ("stillOpening")) {
ratio += Time.deltaTime * multiplier;
skybox.SetFloat ("_Exponent1",Mathf.Lerp(skybox.GetFloat("_Exponent1"), topSkyBoxOpen, ratio));
}
}
But nothing happens at all - I read this might be because its trying to have it all lerp in 1 frame. Is this possible? How can I lerp WHILE an animation is playing regardless of its speed?
Meaning it has to be equal to topSkyBoxOpen at the end of
"stillOpening". I don't know how to coordinate the timing.
The problem is that you are not even waiting for a frame. So, even if your equation is correct, all those cannot happen smoothly in a single frame. You wait for a frame with yield return null; and that requires coroutine.
Answered a very similar but not the-same question few hours ago.
If the stillOpening variable is the destination value, get the current _Exponent1 value before going into the while loop. Have a counter variable that increments each frame while counter is less than topSkyBoxOpen. You can then use Mathf.Lerp(currentVal, topSkyBoxOpen, counter / duration); in the SetFloat function.
bool running = false;
void openSkyLerp()
{
if (running)
{
return;
}
running = true;
StartCoroutine(OpenSky(5));
}
IEnumerator OpenSky(float duration)
{
float currentVal = skybox.GetFloat("_Exponent1");
float counter = 0;
while (counter < topSkyBoxOpen)
{
//Exit if not still opening
if (!cameraAnim.GetCurrentAnimatorStateInfo(0).IsName("stillOpening"))
{
yield break;
}
counter = counter + Time.deltaTime;
float val = Mathf.Lerp(currentVal, topSkyBoxOpen, counter / duration);
skybox.SetFloat("_Exponent1", val);
yield return null; //Wait for a frame
}
running = false;
}
void OnMouseDown () {
if(name == "SlowButton"){
PlaneMovement.GameSpeed = 0.5f;
}
if(name == "MediumButton"){
PlaneMovement.GameSpeed = 1f;
}
if(name == "FastButton"){
PlaneMovement.GameSpeed = 2f;
}
if(name == "VeryFastButton"){
PlaneMovement.GameSpeed = 3f;
}
Application.LoadLevel("game");
}
I enter with this code into the Next Scene and there i have a code for some extra Power like speedup while collision occurs for that the code is:
if(C.tag == "Dimond"){
Camera.main.GetComponent<StoneInitiate>().DimondList.Remove(C.gameObject);
Destroy (C.gameObject);
Camera.main.GetComponent<StoneInitiate>().StoneCounter+=20;
smooth = 4f;
SpeedUpTimer = 5f;
SpeedUp = true;
}
speedup code is:
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,Time.time);
if(SpeedUp){
SpeedUpTimer -= Time.deltaTime;
print(SpeedUpTimer);
if(SpeedUpTimer <= 0){
SpeedUp = false;
smooth = PlaneMovement.GameSpeed;
}
It Works Fine when collision occurs but smooth takes value 4f and It Doesn't get value form
PlaneMovement.GameSpeed
please help me for that I am new in Unity. Thanks in advance.
The problem is here
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,Time.time);
if(SpeedUp){
SpeedUpTimer -= Time.deltaTime;
print(SpeedUpTimer);
if(SpeedUpTimer <= 0){
SpeedUp = false;
smooth = PlaneMovement.GameSpeed;
}
}
You are using Lerp incorrectly, the first argument is the From value, the second is the To value and the third is how far you go between From and To, lets call it t.
So for example, say that your From = 1 and To = 2.
If t = 0, then it will return From and thus 1
if t = 1 then it will return To and thus 2
if t = 0.5 then it will return the value half way between 1 and 2 thus 1.5
t is clamped to 0 and 1
You use Time.time which is a number larger then 1 which means that it will always return your smooth. thus GameSpeed will always be equal to smooth after you call
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,Time.time);
What you want to do is call that line several times with a t of something like 0.5
Lets say GameSpeed is 1 and smooth is 4. When you call this
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,0.5f);
GameSpeed will now be 2.5. If you call it again with GameSpeed now beeing 2.5 it will become 3,25 and a third time for 3,625. The more you call it the close it will get to 4.
As Rudolfwm pointed out you can make this framerade independant by using the delta time like this
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,0.5f * Time.deltaTime);
I just Do this and it works..
float smooth;
float smooth1;
void Start () {
smooth = PlaneMovement.GameSpeed;
smooth1 = PlaneMovement.GameSpeed;
}
PlaneMovement.GameSpeed = Mathf.Lerp (PlaneMovement.GameSpeed,smooth,Time.deltaTime);
if(SpeedUp){
SpeedUpTimer -= Time.deltaTime;
if(SpeedUpTimer <= 0){
SpeedUp = false;
smooth = smooth1;
}
I am trying iterate through an array of Bullets in order to set the position of each one with a delay of 0.3 secs.
FireTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (kbState.IsKeyDown(Keys.Space) && FireTimer > FireRate)
{
for (int i = 0; i < bullets.Count(); i++)
{
if (bullets[i].IsAlive == false)
{
bullets[i].IsAlive = true;
bullets[i].position = position;
FireTimer = 0f;
}
}
}
My FireTimer is assigned a value of 0.0f and the FireRate is assigned 0.3f.
All bullets are drawn and given the same position when I call this method. Can anybody tell me what needs to be done to get them to be positioned at the position in 0.3sec intervals?
You are checking the firetimer when the key is down, then you iterate over the entire array and fire each bullet. You will want a variable to store the current index in the clip, then increment it each time a bullet is fired.
int clipIndex = 0;
...
FireTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (kbState.IsKeyDown(Keys.Space) && clipIndex < bullets.Count() FireTimer > FireRate)
{
if (bullets[clipIndex].IsAlive == false)
{
bullets[i].IsAlive = true;
bullets[i].position = position;
FireTimer = 0f;
}
clipIndex++;
}
You could then reload by changing the index back to 0; Another thing to be aware of, if the bullet's flag IsAlive is true, then this miss fire for a single frame. If you wanted to just find the next alive bullet you could do a while statement:
while (bullets[clipIndex].IsAlive && clipIndex < bullets.Count())
clipIndex++;
if (clipIndex < bullets.Count())
...
The if statement changes because you know that clipIndex will be the index of a bullet that isn't alive, but you do want to make sure there IS a bullet.