Unity - GetKeyDown and GetKey using the same KeyCode to get a delay on input if held down - unity3d

I an trying to get the user input do two different behaviors with the same input key.
like this :
if (Input.GetKeyDown(KeyCode.D) || Input.GetKey(KeyCode.D))
Making a tetris game: The goal is, tapping "D" once, I want tetromino to move one world unit per tap. AND when holding down the same key "D" I want the block to move right continuously until it reaches the edge of the game board, without having to tap.
This sort of works with the code above but, the problem I have is that tapping once moves 2 or 3 world unit instead of once because there is no delay before unity realizes that I am holding the key down.
I would like unity to wait .5 seconds before activating "Input.GetKey(KeyCode.D)" so that I can keep the behavior "Input.GetKeyDown(KeyCode.D)"
Bottom line,
I want to be able to tap "D" to move one world unit per tap
I want the block to move continuously right until it reaches the edge of the game board if I hold down "D" but, only after holding it down for .5 seconds
How can I do this ?
Full code for the Tetromino.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tetromino : MonoBehaviour {
//#####################################################################################################
//#####################################################################################################
float fallTimer = 0f; // timer counting the seconds to check if mino needs to fall
public float fallSpeed = 1f; // variable to determine how fast the mino needs to fall
public bool allowRotation = true;
public bool limitRotation = false;
//#####################################################################################################
//#####################################################################################################
// Use this for initialization
void Start () {
}
//#####################################################################################################
//#####################################################################################################
// Update is called once per frame
void Update ()
{
CheckUserInput(); // --------------------------- // Checks the user input every frames
FallBehavior(); // checks if the block needs to fall and increments the timer
}
//#####################################################################################################
//#####################################################################################################
void CheckUserInput()
{
if (Input.GetKeyDown(KeyCode.D)) // moves the mino to the right
{
transform.position += new Vector3(1,0,0);
if (CheckIsValidPosition()) // if minos is not in a valid position, the transform pushes the minos
{ // back to the left, to keep it inside the grid
}
else
{
transform.position += new Vector3(-1, 0, 0); // this counters the first attempt to move
}
}
else if (Input.GetKeyDown(KeyCode.A)) // moves the mino to the left
{
transform.position += new Vector3(-1, 0, 0);
if (CheckIsValidPosition())
{
}
else
{
transform.position += new Vector3(1, 0, 0);
}
}
else if (Input.GetKeyDown(KeyCode.W)) // rotates the mino
{
if (allowRotation)
{
if (limitRotation) //limited rotation ON, to prevent rotating outside the grid
{ // after the tetromino landed at the bottom
if (transform.rotation.eulerAngles.z >= 90)
{
transform.Rotate(0, 0, -90);
}
else
{
transform.Rotate(0, 0, 90);
}
}
else
{
transform.Rotate(0, 0, 90); // 90 degrees rotation on the mino
}
if (CheckIsValidPosition())
{
}
else
{
if (limitRotation)
{
if (transform.rotation.eulerAngles.z >= 90)
{
transform.Rotate(0, 0, -90);
}
else
{
transform.Rotate(0, 0, 90);
}
}
else
{
transform.Rotate(0, 0, -90);
}
}
}
}
else if (Input.GetKeyDown(KeyCode.S))
{
transform.position += new Vector3(0, -1, 0); // makes the mino go down when pressing
if (CheckIsValidPosition())
{
}
else
{
transform.position += new Vector3(0, 1, 0);
}
}
}
//#####################################################################################################
//#####################################################################################################
/// <summary>
/// Makes the block fall by 1 unit and checks how fast it needs to fall
/// </summary>
void FallBehavior()
{
if (Time.time - fallTimer >= fallSpeed) // on the first frame, Time.time = 0 & fallTimer = 0
// so 0 - 0 = 0, is it >= then fallSpeed = 1? no
// so the if statement does not exectute, block dont fall
// after 1 sec, Time.time = 1 & fallTimer = 0
// so 1 - 0 = 1, is it >= then fallSpeed = 1? yes
// so block falls after 1 sec, because we increment it
// in the if statment also
{
transform.position += new Vector3(0, -1, 0); // moves the mino down
fallTimer = Time.time; // Time.time check the time since game started and is assigned
} // to fallTimer so that the timer updates every frame
// when called in the Update method. fallTimer = 0, 1, 2, 3 ...
if (CheckIsValidPosition()) // also helps checking if the Y is invalid, which tells the game to spawn
{ // the next tetromino when Y is less <= to the bottom of the grid
}
else
{
transform.position += new Vector3(0, 1, 0);
enabled = false; // disables the current piece, because it is at the bottom. So that the controls are not still
// attached to the current piece, after the next one spawned
FindObjectOfType<Game>().SpawnNextTetromino(); // spawns the next tetromino after the last one reached the bottom
}
}
//#####################################################################################################
//#####################################################################################################
/// <summary>
/// check the position of the individual tiles of the minos (children of the prefab)
/
/// </summary>
/// <returns></returns>
bool CheckIsValidPosition()
{
foreach (Transform mino in transform)
{
Vector2 pos = FindObjectOfType<Game>().RoundingTheMinoPosition (mino.position);
if (FindObjectOfType<Game>().CheckIsInsideGrid(pos) == false)
{
return false;
}
}
return true;
}
}
Full code of Game.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Game : MonoBehaviour {
public static int gridWidth = 10; // fixed grid size varibles
public static int gridHeight = 20; // for the blocks to fall in
// the grid need to be in a 2d array and we want to store all the x and y values for each world unit of the grid
// so that we can know which point on the grid are beind occupied by tetrominos that fell in.
//
// the array is gonna store the transforms so we use "gridWidth" and "gridHeight" to define the size of the array.
public static Transform[,] grid = new Transform[gridWidth, gridHeight];
// Use this for initialization
void Start () {
SpawnNextTetromino(); // spawns the first tetromino in the game
}
// Update is called once per frame
void Update () {
}
public void SpawnNextTetromino() // the Resources folder is included when the game compiles, we placed our prefabs
{ // in "Assets\Resources\Prefabs" to allow instantiation in the code.
// we cast a gameobject -> "(GameObject)" to let "Instantiate" know what we want to instantiate.
GameObject nextTetromino = (GameObject)Instantiate(Resources.Load(GetRandomTetromino(), typeof(GameObject)), new Vector2(5.0f, 20.0f), Quaternion.identity);
}
//gonna pass in the mino position in this method to see
// if it is still in the grid
public bool CheckIsInsideGrid(Vector2 pos)
{
return ((int)pos.x >= 0 && (int)pos.x < gridWidth && (int)pos.y >= 0);
}
public Vector2 RoundingTheMinoPosition(Vector2 pos)
{
return new Vector2(Mathf.Round(pos.x), Mathf.Round(pos.y));
}
/// <summary>
/// Genreates a random int and assings a teromino prefab to the outcome
/// </summary>
/// <returns></returns>
string GetRandomTetromino()
{
int randomTetromino = Random.Range(1, 8); //
string randomTetrominoName = null;
switch (randomTetromino)
{
case 1:
randomTetrominoName = "Prefabs/Tetromino_T";
break;
case 2:
randomTetrominoName = "Prefabs/Tetromino_Long";
break;
case 3:
randomTetrominoName = "Prefabs/Tetromino_Square";
break;
case 4:
randomTetrominoName = "Prefabs/Tetromino_J";
break;
case 5:
randomTetrominoName = "Prefabs/Tetromino_L";
break;
case 6:
randomTetrominoName = "Prefabs/Tetromino_S";
break;
case 7:
randomTetrominoName = "Prefabs/Tetromino_Z";
break;
}
return randomTetrominoName;
}
}

Looks like I misunderstood the original question. You want to move on "D" key press only but move until your you have reached the Edge when the the "D" key is held down.You need a timer when the the key is held down and this can be done with Time.deltaTime. Check while the key is held down with Input.GetKey, and if the timer reaches the amount of value you think makes it a held down, then you know the key is held down.
Also, check when the key is released with Input.GetKeyUp(KeyCode.D). If the key is released but timer has not reached the value you think makes it a held down,then it's simply a key press. It's worth doing this in a coroutine function instead of the Update function to simplify it and also reduce the amount of variables required to do it.
const float timeToCountAsHeldDown = 0.3f;
float pressTimer = 0;
IEnumerator moveChecker()
{
while (true)
{
//Check when the D key is pressed
if (Input.GetKeyDown(KeyCode.D))
{
//Continue to check if it is still heldown and keep counting the how long
while (Input.GetKey(KeyCode.D))
{
//Start incrementing timer
pressTimer += Time.deltaTime;
//Check if this counts as being "Held Down"
if (pressTimer > timeToCountAsHeldDown)
{
//It a "key held down", call the OnKeyHeldDown function and wait for it to return
yield return OnKeyHeldDown();
//No need to continue checking for Input.GetKey(KeyCode.D). Break out of this whule loop
break;
}
//Wait for a frame
yield return null;
}
}
//Check if "D" key is released
if (Input.GetKeyUp(KeyCode.D))
{
//Check if we have not not reached the timer then it is only a key press
if (pressTimer < timeToCountAsHeldDown)
{
//It just a key press, call the OnKeyPressedOnly function and wait for it to return
yield return OnKeyPressedOnly();
}
//Reset timer to 0 for the next key press
pressTimer = 0f;
}
//Wait for a frame
yield return null;
}
}
IEnumerator OnKeyPressedOnly()
{
Debug.Log("D key was only Pressed");
//Move 1 unit only
transform.position += new Vector3(1, 0, 0);
yield return null;
}
IEnumerator OnKeyHeldDown()
{
Debug.LogWarning("D key is Held Down");
//Don't move for 0.5 seconds
yield return new WaitForSeconds(0.5f);
//Move 1 unit every frame until edge detection is reached!
while (!CheckIsValidPosition())
{
transform.position += new Vector3(1, 0, 0);
//Wait for a frame
yield return null;
}
}

Related

Unity3d lift movement down with keycode

this code does so when I press the A key or the B key, the elevator stops upwards on the first or second floor.
The question is
How do I modify the code that when the elevator is on the second floor, for example, and I press the A key again to make the elevator go down to the first floor?
Question two
If I replace
if (Input.GetKey (KeyCode.A)) {}
with this
if (Input.GetKeyUp (KeyCode.Keypad1)) {}
so the code does not work. Why?
Thank you for advice
Sorry for the bad English. Here is the code
public GameObject lift;
private bool keyHHit=false;
private bool keyHHitB=false;
void Update ()
{
if (Input.GetKey(KeyCode.B))
{
keyHHit=true;
}
if( keyHHit==true)
{
if(transform.localPosition.y >= 14.52)
{
transform.Translate(new Vector3(0, 0, 0) * 2 * Time.deltaTime, Space.Self);
}
else
{
transform.Translate(new Vector3(0, 2, 0) * 2 * Time.deltaTime, Space.Self);
}
}
if (Input.GetKey(KeyCode.A))
{
keyHHitB=true;
}
if( keyHHitB==true)
{
if(transform.localPosition.y >= 8.52)
{
transform.Translate(new Vector3(0, 0, 0) * 2 * Time.deltaTime, Space.Self);
}
else
{
transform.Translate(new Vector3(0, 2, 0) * 2 * Time.deltaTime, Space.Self);
//transform.Translate(Vector3.up * 0.05f);
}
}
}
So if I understand you correctly
you have two or 3 floors (doesn't matter, could be more later).
Once you press a button you want to move towards the target floor until you reach there. "Lock" input meanwhile
Once you reached a floor "unlock" Input again and allow to also go down if the current floor is above the target floor
I would use a Coroutine and Vector3.Lerp for this.
First lets have a class for floors so it is easier to add additional floors later
[Serializable]
public class FloorSetting
{
public KeyCode Key;
public Vector3 Position;
}
Then simply have an array of all floors target positions and according keys
// Configure these floors in the Inspector
// simply add the entries you need and adjust buttons and target positions
[SerializeField] private FloorSetting[] floors;
[SerializeField] private float moveUnitsPerSecond = 1f;
// This flag is for blocking any Input while moving
// thus preventing concurrent routines
private bool isMoving;
private void Update()
{
// if already moving do nothing
if(isMoving) return;
// check if any of the configured keys was pressed and start moving
// towards the according position
foreach(var floor in floors)
{
// You want to use GetKeyDown to only get the first press event
// you don't care about continues press since you will keep moving automatically until reaching the floor
if(Input.GetKeyDown(floor.Key))
{
StartCoroutine(MoveRoutine(floor.Position));
}
}
}
private IEnumerator MoveRoutine(Vector3 targetPosition)
{
// block concurrent routine
if(isMoving) yield break;
isMoving = true;
// Get the duration of movement
var startPosition = transform.position;
var duration = Vector3.Distance(startPosition, targetPosition) / moveUnitsPerSecond;
// Move smoothly towards the target position and add some easing
var timePassed = 0f;
while(timePassed <= duration)
{
// A interpolation factor between 0 and 1
var factor = timePassed / duration;
// optionally add ease-in and out
factor = Mathf.SmoothStep(0, 1, factor);
// Set the position to an interpolated position between start and target depending on the factor
transform.position = Vector3.Lerp(startPosition, targetPosition, factor);
// increase by the time passed since last frame
timePassed += Time.deltaTime;
// Tells Unity to "pause" the routine here, render this frame
// and continue from here in the next frame
yield return null;
}
// Just to be sure in he end set it to hard position
transform.position = targetPosition;
// optionally add some cooldown in seconds
yield return new WaitForSeconds(1f);
// Release the lock so next move can start now
isMoving = false;
}
If you don't need the easing you could as well also implement it lot easier using Vector3.MoveTowards like e.g.
while(!Mathf.Approximately(Vector3.Distance(transform.position, targetPosition), 0)
{
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveUnitsPerSecond);
yield return null;
}
transform.position = targetPosition;
Note: Typed on smartphone but I hope the idea gets clear

How to fix this unity 2d sidescroller movement/animation problem

So I am creating my first game in unity and I am currently working on the left to right movement.
I move to the left, let go of the left arrow button -> idle animation.
Press right arrow and character moves to right, let go -> idle.
The problem is I have to wait for the idle animation before I can press to go to the other direction chosen. When I press left and same time right the character does not move.
What I would like to do is fe:
press left -> character goes left, and then
press right at the same time -> character goes right.
So the need to be able to press buttons at the same time, and the last key pressed dictates the movement/animation.
Animation code:
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 1);
}
if (Input.GetKeyUp(KeyCode.LeftArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 0);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 2);
}
if (Input.GetKeyUp(KeyCode.RightArrow))
{
this.GetComponent<Animator>().SetInteger("pallotila", 0);
}
Player movement code:
if (Input.GetKey(KeyCode.LeftArrow))
{
this.transform.position += Vector3.left * this.nopeus * Time.deltaTime;
this.transform.rotation = this.vasemmalle;
}
if (Input.GetKey(KeyCode.RightArrow))
{
this.transform.position += Vector3.right * this.nopeus * Time.deltaTime;
this.transform.rotation = this.oikealle;
}
Note that you should never use GetComponent in Update better do it once and reuse the reference.
//Here you store the Animator reference
private Animator animator;
private void Awake()
{
animator = GetComponent<Animator>();
}
I'ld also use a switch to define what should happen for which button in order to avoid having the same code over and over again.
private void SetLastPressed(KeyCode code)
{
int value = 0;
switch (code)
{
case KeyCode.None:
value = 0;
break;
case KeyCode.LeftArrow:
value = 1;
break;
case KeyCode.RightArrow:
value = 2;
break;
}
animator.SetInteger("pallotila", value);
lastPressed = code;
}
Simply store and check which button pressed last and make the Input checks exclusive using if-else.
// Here you store the last pressed key
private KeyCode lastPressed = KeyCode.None;
private void Update()
{
if (lastPressed != KeyCode.LeftArrow && Input.GetKeyDown(KeyCode.LeftArrow))
{
SetLastPressed(KeyCode.LeftArrow);
}
else if (lastPressed != KeyCode.RightArrow && Input.GetKeyDown(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.RightArrow);
}
// If none of the keys is pressed reset
else if (lastPressed != KeyCode.None && !Input.GetKey(KeyCode.LeftArrow) && !Input.GetKey(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.None);
}
// And if only one of them is released but the other one still pressed
//go on using that still pressed key again
else if (lastPressed != KeyCode.LeftArrow && Input.GetKeyUp(KeyCode.RightArrow) &&
Input.GetKey(KeyCode.LeftArrow))
{
SetLastPressed(KeyCode.LeftArrow);
}
else if (lastPressed != KeyCode.RightArrow && Input.GetKeyUp(KeyCode.LeftArrow) &&
Input.GetKey(KeyCode.RightArrow))
{
SetLastPressed(KeyCode.RightArrow);
}
For the movement you could simply reuse the lastPresses value than as well
if(lastPressed == KeyCode.LeftArrow)
{
transform.position += Vector3.left * nopeus * Time.deltaTime;
transform.rotation = vasemmalle;
}
else if (lastPressed == KeyCode.RightArrow)
{
transform.position += Vector3.right * nopeus * Time.deltaTime;
transform.rotation = oikealle;
}
Additionally you could/should use a List<KeyCode> to store the last presses. Everytime a button goes down add the button to the end of the list; everytime a button goes up remove it from the list
result => the last pressed button is always the last one in the list.
This makes the return to a previous button way more simple and flexible without adding/changing so much lines of code like
private List<KeyCode> lastPresses = new List<KeyCode>();
private KeyCode lastPressed = KeyCode.None;
private Animator animator;
private void Awake()
{
animator = GetComponent<Animator>();
}
private void SetLastPressed(KeyCode code)
{
int value = 0;
switch (code)
{
case KeyCode.None:
value = 0;
break;
case KeyCode.LeftArrow:
value = 1;
break;
case KeyCode.RightArrow:
value = 2;
break;
}
animator.SetInteger("pallotila", value);
lastPressed = code;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
if (!lastPresses.Contains(KeyCode.LeftArrow)) lastPresses.Add(KeyCode.LeftArrow);
}
else if (Input.GetKeyUp(KeyCode.LeftArrow))
{
if (lastPresses.Contains(KeyCode.LeftArrow)) lastPresses.Remove(KeyCode.LeftArrow);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
if (!lastPresses.Contains(KeyCode.RightArrow)) lastPresses.Add(KeyCode.RightArrow);
}
else if (Input.GetKeyUp(KeyCode.RightArrow))
{
if (lastPresses.Contains(KeyCode.RightArrow)) lastPresses.Remove(KeyCode.RightArrow);
}
var currentCode = lastPresses.Count > 0 ? lastPresses[lastPresses.Count - 1] : KeyCode.None;
if (currentCode != lastPressed) SetLastPressed(currentCode);
if (lastPressed == KeyCode.LeftArrow)
{
transform.position += Vector3.left * nopeus * Time.deltaTime;
transform.rotation = vasemmalle;
}
else if (lastPressed == KeyCode.RightArrow)
{
transform.position += Vector3.right * nopeus * Time.deltaTime;
transform.rotation = oikealle;
}
}
You can change the "Value" Variable to
animator.SetInteger("pallotila", 0);
break;
in the location of
value = 0;
break;
or change
int value;
to
int value = 0;
in the code by #derHugo

Fade in and out complex GameObject in Unity [duplicate]

I'm fairly new to coding, I'm still trying to develop that logic of thinking to help me create the solutions I'm wanting for games. Currently, I'm in Unity trying to create a 2D GameObject that's a wall hiding a secret door. I want that GameObject to fade out (about 90%) when the player GameObject triggers it, revealing the space behind and the hidden door.
So far, I've managed to figure out how to render the "secret wall" GO inactive on the trigger, so it disappears, but this doesn't produce the visual that I'm going for. As I said, I'm still working on developing that coder's way of thinking, so while I've done a lot of research to solve this problem, many of the results I don't readily understand.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SecretDoor1 : MonoBehaviour {
void OnTriggerEnter2D (Collider2D SecretDoorTrig) {
if (SecretDoorTrig.gameObject.tag == "Player") {
GetComponent<SpriteRenderer> ().enabled = false;
}
else {
GetComponent<SpriteRenderer> ().enabled = true;
}
}
void OnTriggerExit2D (Collider2D SecretDoorTrig) {
if (SecretDoorTrig.gameObject.tag == "Player") {
GetComponent<SpriteRenderer> ().enabled = true;
}
else {
GetComponent<SpriteRenderer> ().enabled = false;
}
}
}
Fading a Sprite is almost the-same as moving GameObject over time except that you modify its alpha instead of it's position.
The three most important stuff about fading an Object are Time.deltaTime, Mathf.Lerp/Color.Lerp and coroutine. You need to understand how these work together.
Start coroutine, use Time.deltaTime to increment a variable. That variable is used to use to determine how much that function has ran. In a for/while loop, use that variable that is incremented every-frame and the duration you want the fade to happen to generate the alpha with the help of the Mathf.Lerp function. Create new color with that alpha and and assign it to the Sprite.
This is done every frame until that variable that is incremented with Time.deltaTime reaches the duration you want to the fade to happen within.
Here is a simple SpriteRenderer fade function:
public SpriteRenderer spriteToFade;
IEnumerator fadeOut(SpriteRenderer MyRenderer, float duration)
{
float counter = 0;
//Get current color
Color spriteColor = MyRenderer.material.color;
while (counter < duration)
{
counter += Time.deltaTime;
//Fade from 1 to 0
float alpha = Mathf.Lerp(1, 0, counter / duration);
Debug.Log(alpha);
//Change alpha only
MyRenderer.color = new Color(spriteColor.r, spriteColor.g, spriteColor.b, alpha);
//Wait for a frame
yield return null;
}
}
If you want it to fade in, change Mathf.Lerp(1, 0, counter / duration); to Mathf.Lerp(0, 1, counter / duration); which will make the alpha go from 0 to 1 over-time instead of 1 to 0.
From the example above, writing a fade-out and fade-in functions only requires a way to tell the function to change the alpha from 1 to 0 or from 0 to 1. You can make the function use a boolean or enum variable to determine which type of fade to perform. Of-course, you can separate the fade-in/fade-out functions but it's good to have it in one function.
Here is the extended version of that function that supports fade-in and fade-out. It also supports almost all GameObjects like MeshRenderer(3D), SpriteRenderer(2D), Image, RawImage....You can extend it to support more components that's missing.
IEnumerator fadeInAndOut(GameObject objectToFade, bool fadeIn, float duration)
{
float counter = 0f;
//Set Values depending on if fadeIn or fadeOut
float a, b;
if (fadeIn)
{
a = 0;
b = 1;
}
else
{
a = 1;
b = 0;
}
int mode = 0;
Color currentColor = Color.clear;
SpriteRenderer tempSPRenderer = objectToFade.GetComponent<SpriteRenderer>();
Image tempImage = objectToFade.GetComponent<Image>();
RawImage tempRawImage = objectToFade.GetComponent<RawImage>();
MeshRenderer tempRenderer = objectToFade.GetComponent<MeshRenderer>();
Text tempText = objectToFade.GetComponent<Text>();
//Check if this is a Sprite
if (tempSPRenderer != null)
{
currentColor = tempSPRenderer.color;
mode = 0;
}
//Check if Image
else if (tempImage != null)
{
currentColor = tempImage.color;
mode = 1;
}
//Check if RawImage
else if (tempRawImage != null)
{
currentColor = tempRawImage.color;
mode = 2;
}
//Check if Text
else if (tempText != null)
{
currentColor = tempText.color;
mode = 3;
}
//Check if 3D Object
else if (tempRenderer != null)
{
currentColor = tempRenderer.material.color;
mode = 4;
//ENABLE FADE Mode on the material if not done already
tempRenderer.material.SetFloat("_Mode", 2);
tempRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
tempRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
tempRenderer.material.SetInt("_ZWrite", 0);
tempRenderer.material.DisableKeyword("_ALPHATEST_ON");
tempRenderer.material.EnableKeyword("_ALPHABLEND_ON");
tempRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
tempRenderer.material.renderQueue = 3000;
}
else
{
yield break;
}
while (counter < duration)
{
counter += Time.deltaTime;
float alpha = Mathf.Lerp(a, b, counter / duration);
switch (mode)
{
case 0:
tempSPRenderer.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 1:
tempImage.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 2:
tempRawImage.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 3:
tempText.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
case 4:
tempRenderer.material.color = new Color(currentColor.r, currentColor.g, currentColor.b, alpha);
break;
}
yield return null;
}
}
Usage:
GameObject to fade:
public GameObject SpriteRend;
Fade-out in 3 seconds
StartCoroutine(fadeInAndOut(SpriteRend, false, 3f));
Fade-in in 3 seconds
StartCoroutine(fadeInAndOut(SpriteRend, true, 3f));
The way I have accomplished this has been change the alpha on the sprite color.
Color(R,G,B,A). A is the alpha.
SpriteRenderer.color = new Color(1f,1f,1f,1f) is opaque.
SpriteRenderer.color = new Color(1f,1f,1f,.5f) is about 50%
transparent.
SpriteRenderer.color = new Color(1f,1f,1f,0f) is about
100% transparent, sprite cannot be seen.

Translating IEnumerator from seconds into minutes?

I am unsure how to translate this into my script. I have a bird script that hovers over the player. I have everything set in float seconds but I want that my FadeIn() function and Ienumerator GameReset() use 1 minute instead. This will help because I want players to have some time to shoot down the bird without having the issue of the game automatically resetting in a matter of seconds.The point of my game is that if players take too long the bird will attack them causing a reset window to appear.
public class OwlEx : MonoBehaviour {
public float waitTime = 10.0f;
public float fadeTime = 3.0f;
public float betweenFadesTime = 2.0f;
// Flag to determine whether or not the player may respond.
public bool canRespond = false;
// Flag to determine if the player has responded within the wait time.
public bool hasResponded = false;
public GameObject enemy;
void Start()
{ StartCoroutine(EnemyFadeIn(fadeTime, betweenFadesTime, waitTime)); }
void Update() {
if ((Input.GetKeyDown(KeyCode.S)) && (canRespond))
{ hasResponded = true; }
}
IEnumerator EnemyFadeIn(float timeToFade, float timeBetweenFades, float timeToWait) {
Debug.Log("An Enemy Is Fading In");
// Simulating Fade In Time.
yield return new WaitForSeconds(timeToFade);
// Fade in
iTween.FadeTo(enemy, 1, 1);
Invoke("SetMaterialOpaque", 1f);
Debug.Log("An Enemy Has Appeared");
yield return ListenForInput(timeToFade, timeBetweenFades, timeToWait);
}
IEnumerator EnemyFadeOut(float timeToFade, float timeBetweenFades, float timeToWait) {
Debug.Log("An Enemy Is Fading Away");
// Simulating Fade Out Time.
yield return new WaitForSeconds(timeToFade);
// Fade out
SetMaterialTransparent();
iTween.FadeTo(enemy, 0, 1);
Debug.Log("An Enemy Has Departed");
// Simulating Time Between Fades.
yield return new WaitForSeconds(timeBetweenFades);
yield return EnemyFadeIn(timeToFade, timeBetweenFades, timeToWait);
}
// Responsible for reacting to the 'S' key input.
IEnumerator ListenForInput(float timeToFade, float timeBetweenFades, float timeToWait) {
canRespond = true;
Debug.Log("Press the 'S' Key to Destroy the Enemy!");
float startTime = Time.time;
// Check every 0.25 seconds to see if the S key was pressed.
while (Time.time < (startTime + timeToWait)) {
if (hasResponded) {
Debug.Log("The 'S' Key was Pressed!");
hasResponded = false;
canRespond = false;
yield return EnemyFadeOut(timeToFade, timeBetweenFades, timeToWait);
}
yield return new WaitForSeconds(0.25f);
}
Debug.Log("The 'S' Key was not Pressed!");
canRespond = false;
yield return ResetGame();
}
IEnumerator ResetGame() {
Debug.Log("Game is Performing a Reset");
Simulating Game Reset Time.
yield return new WaitForSeconds(30);
Debug.Log("Game has Restarted. End of Coroutine!");
}
}
float waitTimeSeconds = 0.0f;
float waitTimeMinutes = 1.0f;
int formatMinutesFlag = 1; //this flag is 1 if you want to add minutes
yield return new WaitForSeconds(waitTimeSeconds + formatMinutesFlag * waitTimeMinutes * 60f);
You can put this in a function if you really don't want to multiply by 60 everytime you want to use minutes instead of seconds.
Edit: Added the part where you multiply by 60. Thanks for reminding me.

Lifting platforms is not working as it should

I would like to make some lifting platforms in my game, so if the platform went down, the characters can't go over it. I have written a script for it, but for some reason the "lifting up" is not working as intended. It won't go back to its starting place, but it will go a bit below. And for some reason it won't go smoothly to the place where it should, just "teleport" there and done. I thougt multiplying Time.deltaTime with a const will help, but it is the same.
Here is my code, any help would be appreciated:
public class LiftingPlatform : MonoBehaviour {
private Transform lift;
private bool isCanBeLifted;
private float timeToLift;
public float timeNeededToLift = 5f;
private Vector3 startPos;
private Vector3 downPos;
private Vector3 shouldPos;
private bool isDown;
public GameObject[] collidingWalls;
// Use this for initialization
void Start () {
lift = transform;
isCanBeLifted = true;
timeToLift = 0f;
isDown = false;
startPos = transform.position;
downPos = new Vector3(startPos.x, startPos.y - 5f, startPos.z);
}
// Update is called once per frame
void Update () {
timeToLift += Time.deltaTime;
if (timeToLift >= timeNeededToLift) {
if (isCanBeLifted) {
if (isDown) {
shouldPos = Vector3.Lerp(startPos, downPos, Time.deltaTime * 10);
lift.position = new Vector3(shouldPos.x, shouldPos.y, shouldPos.z);
isDown = true;
}
else if (!isDown) {
shouldPos = Vector3.Lerp(downPos, new Vector3(startPos.x, startPos.y, startPos.z), Time.deltaTime * 10);
lift.position = new Vector3(shouldPos.x, shouldPos.y, shouldPos.z);
isDown = false;
}
}
timeToLift = 0;
}
if (!isDown) {
for (int i = 0; i < collidingWalls.Length; i++) {
collidingWalls[i].SetActive(true);
}
}
else if (isDown) {
for (int i = 0; i < collidingWalls.Length; i++) {
collidingWalls[i].SetActive(false);
}
}
}
void OnTriggerEnter(Collider collider) {
if (collider.tag == "Player" || collider.tag == "Enemy") {
isCanBeLifted = false;
}
}
void OnTriggerExit(Collider collider) {
if (collider.tag == "Player" || collider.tag == "Enemy") {
isCanBeLifted = true;
}
}
}
These lifting platforms are a child of another Platforms object.
It doesn't look like you are updating the object's position every frame. You are only checking if the total time passed is greater than the time needed to lift, and then updating the position to a value that is dependent on the delta time (using the Vector3.Lerp function).
What I would do is in the update step, if timeToLift is greater then timeNeededToLift, subtract the latter from the former and invert the value of isDown. Then, in your Vector3.Lerp, make the third argument (timeToLift / timeNeededToLift) instead of (Time.deltaTime * 10). Can you try that and see if it works?
The third argument for Vector3.Lerp is the "blending factor" between the two vectors, 0 is the first vector, 1 is the second, and 0.5 is in between. If the total time is greater than the time needed to lift, but the delta time is not greater than 1, it will get the position of the platform using a blending factor of less than 1, resulting in a platform that didn't move fully.