I've been working on a game in unity for a school project. Currently I'm trying to make a countdown before my game starts. I'm sure this is basic knowledge but I'm fairly new to Unity.
This is my Script:
using UnityEngine;
using System.Collections;
public class StartScreen : MonoBehaviour {
static bool sawOnce = false;
// Use this for initialization
void Start () {
if(!sawOnce) {
GetComponent<SpriteRenderer>().enabled = true;
Time.timeScale = 0;
}
sawOnce = true;
}
// Update is called once per frame
void Update () {
if(Time.timeScale==0 && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) ) {
Time.timeScale = 1;
GetComponent<SpriteRenderer>().enabled = false;
}
}
}
I want to change between three different sprites before "Time.timeScale = 1;" and after "GetComponent().enabled = false;". Each sprite should just show for a second before the next one shows up.
You should create a new function with a wait statement.
Something like this would work.
void Update () {
if(Time.timeScale==0 && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) ) {
Time.timeScale = 1;
changeSprites();
GetComponent<SpriteRenderer>().enabled = false;
}
}
IEnumerator changeSprites(){
GetComponent<SpriteRenderer>().sprite = SPRITE1
yield return new WaitForSeconds(1);
GetComponent<SpriteRenderer>().sprite = SPRITE2
yield return new WaitForSeconds(1);
GetComponent<SpriteRenderer>().sprite = SPRITE3
yield return new WaitForSeconds(1);
}
}
Related
Hello my code is basically on collision it will start the coroutine of slowing the enemy then after 3.2 seconds it reverts back to original.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "slowProjectile")
{
StartCoroutine(slowEnemy());
}
}
// FROZEN ENEMY BEHAVIOUR
public bool isFrozen = true;
IEnumerator slowEnemy()
{
if (isFrozen == true)
{
isFrozen = false;
Debug.Log("FROZEN");
// Turns the enemy into color blue
this.GetComponent<SpriteRenderer>().color = Color.blue;
enemyMovementSpeed = enemyMovementSpeed / 2;
// waits for 3.2 seconds
yield return new WaitForSeconds(3.2f);
// Then return the enemy movement speed and color to its original state.
enemyMovementSpeed = enemyMovementSpeed * 2;
this.GetComponent<SpriteRenderer>().color = Color.white;
}
else
{
isFrozen = true;
}
}
problem is the coroutine is stacking meaning it will run x2 and lost the original value also the projectile fires every 3 seconds. Think of it as A shooter that shoots every 3 seconds and on impact slows the enemy for 3 seconds. ( Like a Snow Pea if you play Plants Vs Zombie )
Other answer is right but adds many coroutines. Here is a solution that uses only one coroutine at a time.
private float m_timer;
private IEnumerator m_coroutine;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "slowProjectile")
{
m_timer = 0f;
if (m_coroutine == null){
m_coroutine = FreezeTime();
StartCoroutine(m_coroutine);
}
}
}
IEnumerator FreezeTime()
{
while (m_timer < 3.2f){
m_timer += Time.deltaTime;
yield return null;
}
m_coroutine = null;
}
When a collision occurs, reset to 0 and if no coroutine is already running, create a new one.
The coroutine keeps increasing the timer, if a collision occurs, it will reset to 0. When done, it resets the coroutine reference.
if what you want is the Frozen effect doesn't stack :
public bool isFrozen = false;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "slowProjectile")
{
if (!isFrozen)
{
StartCoroutine(slowEnemy());
}
}
}
IEnumerator slowEnemy()
{
isFrozen = true;
Debug.Log("FROZEN");
// Turns the enemy into color blue
this.GetComponent<SpriteRenderer>().color = Color.blue;
enemyMovementSpeed = enemyMovementSpeed / 2;
// waits for 3.2 seconds
yield return new WaitForSeconds(3.2f);
// Then return the enemy movement speed and color to its original state.
enemyMovementSpeed = enemyMovementSpeed * 2;
this.GetComponent<SpriteRenderer>().color = Color.white;
isFrozen = false;
}
The downside of the code above is that while the Speed Change doesn't stack, the Frozen Time neither.
If you want to stack the Frozen Time and not stack Speed Change at the same time, maybe you need to add a Forzen Stack Counter to check whether the Frozen time is ended :
public int forenStackCount = 0;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "slowProjectile")
{
StartCoroutine(slowEnemy());
}
}
private IEnumerator slowEnemy()
{
if (forenStackCount == 0)
{
StartFrozenEffect();
}
forenStackCount++;
yield return new WaitForSeconds(3.2f);
forenStackCount--;
if (forenStackCount == 0)
{
EndFrozenEffect();
}
}
private void StartFrozenEffect()
{
Debug.Log("FROZEN");
// Turns the enemy into color blue
this.GetComponent<SpriteRenderer>().color = Color.blue;
enemyMovementSpeed = enemyMovementSpeed / 2;
}
private void EndFrozenEffect()
{
enemyMovementSpeed = enemyMovementSpeed * 2;
this.GetComponent<SpriteRenderer>().color = Color.white;
}
im trying to make walking animation for my character when he walk but animation always running.sorry for my english. here is my code;
Animator anim;
void Start ()
{ anim = GetComponent<Animator>();
anim.enabled = false;
}
void walk(){
if(body.velocity > 0){
anim.enabled = true;
anim.Play("walk");
}
if(Vector2.zero){
anim.enabled = false;
}
}
private void FixedUpdate()
{
body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}
your if (Vector2.zero) makes no sense.
Maybe try using the else keyword and add a anim.Stop to the second part:
if(body.velocity > 0){
anim.enabled = true;
anim.Play("walk");
}
else {
anim.Stop()
anim.enabled = false;
}
There was a very interesting error with game characters, on the first level they walk quietly and everything is OK, and on the second they go only in the editor, and after compilation they are no longer there. Ai navigation exists. The character must find ... by the tag maybe he is on stage. What could be the problem? error only at the second level and only after assembly
mob script(They do not go, they do not attack if you approach. So either they don’t see or an error in the script on the phone occurs)
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class EmenScript: MonoBehaviour
{
public NavMeshAgent agent;
public Animator animator;
public GameObject zombieObject;
private Transform player;
private float curr_time;
private int xp = 100;
void Start()
{
player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
StartCoroutine(findPath());
StartCoroutine(playerDetected());
curr_time = 0f;
}
public void damage()
{
if(xp == 0)
{
gameObject.transform.Find("Xp/Cube/").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
} else {
xp = xp > 15 ? xp - 15 : 0;
Transform xpp = gameObject.transform.Find("Xp/Cube/XpLine").transform;
xpp.localScale = new Vector3(xpp.localScale.x, xpp.localScale.y, xp / 100f);
xpp.localPosition = new Vector3(xpp.localPosition.x, xpp.localPosition.y, (0.97f - xpp.localScale.z) / 2);
}
}
public void damageFull()
{
gameObject.transform.Find("Xp/Cube").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
}
IEnumerator playerDetected()
{
while(true)
{
if(player == null)
{
break;
}
if(player.GetComponent<UserController>().xp <= 0)
{
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
if(Vector3.Distance(transform.position, player.position) < 1.2f)
{
animator.SetTrigger("attack");
curr_time -= Time.deltaTime;
if(curr_time <= 0)
{
if(player.GetComponent<UserController>().xp - 25 > 0)
{
player.GetComponent<UserController>().xp -= 25;
}
else
{
player.GetComponent<UserController>().xp = 0;
}
curr_time = 0.5f;
}
}
yield return new WaitForSeconds(.3f);
}
}
IEnumerator findPath()
{
while(true)
{
if(player.GetComponent<UserController>().xp > 0)
{
if(Vector3.Distance(transform.position, player.position) < 40f)
{
animator.SetBool("walk", true);
if(player && agent.isActiveAndEnabled)
{
agent.GetComponent<NavMeshAgent>().isStopped = false;
agent.SetDestination(player.position);
}
} else {
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
}
yield return new WaitForSeconds(0.2f);
}
}
}
I think error must be about scene change but I need to see script and lvl's.
I have a game in which you are a player cube and you have to dodge other cubes as they come through your way. The enemy cubes should spawn because of a script I have called GameController. But the cubes are not spawning. Please Help. (Also whenever my cube gets destroyed the gameover and the restart functions are not working)
I tried Recreating the prefab and the code, but nothing happened. Also, the same code is working in my other games
Here is my code:
void Start()
{
gameOver = false;
restart = false;
restartText.text = "";
gameOverText.text = "";
score = 0;
UpdateScore();
StartCoroutine(SpawnWaves());
}
void Update()
{
if (restart)
{
if (Input.GetKeyDown(KeyCode.R))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
}
IEnumerator SpawnWaves()
{
yield return new WaitForSeconds(startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
GameObject hazard = hazards[Random.Range(0, hazards.Length)];
Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
GameObject newSpawn = Instantiate(hazard, spawnPosition, spawnRotation) as GameObject;
yield return new WaitForSeconds(spawnWait);
}
yield return new WaitForSeconds(waveWait);
if (gameOver)
{
restartText.text = "Press 'R' for Restart";
restart = true;
break;
}
}
}
public void AddScore(int newScoreValue)
{
score += newScoreValue;
UpdateScore();
}
void UpdateScore()
{
scoreText.text = "Score: " + score;
}
public void GameOver()
{
gameOverText.text = "Game Over!";
gameOver = true;
}
}
I expect the enemies to spawn but they are not
I have copy and pasted your example code into an example project. In this example your script works as expected, as you already mentioned that it works in other projects.
So in my opinion it has something to do with the inspector values.
Check the following:
Did you checked that your hazardCount is greater than zero?
Is your hazardArray completely filled with prefabs?
(If not that should cause the not-spawning but should also cause a null-reference-exception.)
Another option is that you make a screenshot or provide your values in the inspector somehow, so its possible to reproduce the error.
Offtopic: Your Restart after the gameOver is delayed, because the if(gameOver)-Clause comes after the WaitForSeconds(waveWait). My suggestion is to change it to the following:
public GameObject[] hazards;
public Vector3 spawnValues;
public int hazardCount;
public float spawnWait;
public float startWait;
public float waveWait;
public Text scoreText;
public Text restartText;
public Text gameOverText;
private bool gameOver;
private bool restart;
private int score;
private Coroutine gameRoutine;
void Start()
{
gameOver = false;
restart = false;
restartText.text = "";
gameOverText.text = "";
score = 0;
UpdateScore();
gameRoutine = StartCoroutine(SpawnWaves());
}
void Update()
{
if (restart)
{
if (Input.GetKeyDown(KeyCode.R))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
}
IEnumerator SpawnWaves()
{
yield return new WaitForSeconds(startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
GameObject hazard = hazards[Random.Range(0, hazards.Length)];
Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
GameObject newSpawn = Instantiate(hazard, spawnPosition, spawnRotation) as GameObject;
yield return new WaitForSeconds(spawnWait);
}
yield return new WaitForSeconds(waveWait);
}
}
public void AddScore(int newScoreValue)
{
score += newScoreValue;
UpdateScore();
}
void UpdateScore()
{
scoreText.text = "Score: " + score;
}
public void GameOver()
{
gameOverText.text = "Game Over!";
restartText.text = "Press 'R' for Restart";
restart = true;
gameOver = true;
StopCoroutine(gameRoutine);
}
What i have changed here is, that the if-condition is removed and the Coroutine is now stored at Start() and is directly stop as the gameOver() method gets executed. Another option instead of the StopCoroutine() would be to set the condition of your while-loop to while(!gameOver).
I have a script named AccelerometerMovement which is taking care of accelerometer controls of player. The player is just moving left and right so I am just taking Input.acceleration.x component.
The script is as follows:
public class AccelerometerMovement : MonoBehaviour {
private bool isandroid;
private float AccelerometerStoreValue;
private robotController theRobo;
// Use this for initialization
void Start () {
theRobo = FindObjectOfType<robotController> ();
#if UNITY_ANDROID
isandroid=true;
#else
isandroid=false;
#endif
}
// Update is called once per frame
void Update () {
if (isandroid) {
//android specific code
Accelerometer();
} else {
//any other platform specific code
}
}
void Accelerometer(){
AccelerometerStoreValue = Input.acceleration.x;
if (AccelerometerStoreValue > 0.1f) {
//right
theRobo.moveRight();
} else if (AccelerometerStoreValue < -0.1f) {
//left
theRobo.moveLeft();
}
}
}
As u can see above according to left and right..it is calling moveLeft() and moveRight() from another script which is the actual player controller script.
The other script where the actual function is :
// after Update()
public void jump(){
if (grounded) {
myRigidBody.velocity = new Vector2 (myRigidBody.velocity.x, jumpHeight);
doubleJump = false;
}
if(!doubleJump&&!grounded){
myRigidBody.velocity = new Vector2 (myRigidBody.velocity.x, jumpHeight);
doubleJump = true;
}
}
public void moveLeft(){
myRigidBody.velocity = new Vector2 (-moveSpeed, myRigidBody.velocity.y);
robotMove = true;
lastMove = myRigidBody.velocity.x;
anim.SetFloat ("MoveX", -moveSpeed);
anim.SetFloat ("LastMoveX", lastMove);
anim.SetBool ("RobotMoving", robotMove);
}
public void moveRight(){
myRigidBody.velocity = new Vector2 (moveSpeed, myRigidBody.velocity.y);
robotMove = true;
lastMove = myRigidBody.velocity.x;
anim.SetFloat ("MoveX", moveSpeed);
anim.SetFloat ("LastMoveX", lastMove);
anim.SetBool ("RobotMoving", robotMove);
}
public void stop(){
robotMove = false;
anim.SetBool ("RobotMoving", robotMove);
}
Now when I checked the controls on actual device the controls are working fine but there is one problem!
The problem is that when player starts moving the animation of movement starts but when it stops the idle animation (or stop animation) doesn't start and even when still the player movement animation keeps on going.
Now I am not able to understand how to solve this problem.
the Stop() function above is lying dormant. We need to call it by putting one extra condition :
else if (AccelerometerStoreValue > 0.01f && AccelerometerStoreValue < 0.09f || AccelerometerStoreValue < -0.01f && AccelerometerStoreValue > -0.09f) {
theRobo.stop ();
}
the values will take care of device still and will set the idle animations to work ! Put above code just after 2nd else if in Accelerometer() function .