Run more than expected number - c#

Please do not get too hard about my grammar.
I write follow class for delay
public class Queue_System_Of_Begin_Game : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Game_Controller.Player1_First_throws_true && Game_Controller.Player2_First_throws_true)
{
StartCoroutine(ExecuteAfterTime(1));
}
}
//--------------------------------------
public GameObject player1_icon, player2_icon, dice1_p1, dice2_p1, dice1_p2, dice2_p2;
void determine_the_turn()
{
Debug.Log("update");
}
IEnumerator ExecuteAfterTime(float time)
{
yield return new WaitForSeconds(time);
determine_the_turn();
}
}
I receive 62 times the word update on the console.
This problem will cause my next round of games to run 62 times, which slowed down my game.

The Update() method is called once per frame, thats the reason you get 62 "updates".
You can try adding a boolean so it only gets called once like this:
bool ischecked = false;
void Update(){
if (!ischecked){
if (Game_Controller.Player1_First_throws_true && Game_Controller.Player2_First_throws_true) {
ischecked = true;
StartCoroutine (ExecuteAfterTime (1));
}
}
}

I find solution for my problem .I must use a boolean variable in my if commond like this :
public class Queue_System_Of_Begin_Game : MonoBehaviour
{
private bool coroutineStarted;
// Update is called once per frame
void Update()
{
if (!coroutineStarted && Game_Controller.Player1_First_throws_true && Game_Controller.Player2_First_throws_true)
{
coroutineStarted = true ;
StartCoroutine(ExecuteAfterTime(1));
}
}
//--------------------------------------
public GameObject player1_icon, player2_icon, dice1_p1, dice2_p1, dice1_p2, dice2_p2;
void determine_the_turn()
{
Debug.Log("update");
}
IEnumerator ExecuteAfterTime(float time)
{
yield return new WaitForSeconds(time);
determine_the_turn();
}
}

Related

In Unity how do I stop perpetual math statements?

The question is simple but I can't for the life of me, figure it out.
My logic goes like this
// Static floats are StatBase.maxHealth = 0 and rStat.maxHealth = 70
class rStat : Monobehaviour
{
public bool nomatter = false;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
nomatter = true;
}
if (nomatter == true)
{
healthcalc();
}
void healthcalc()
{
StatBase.maxHealth += rstat.maxHealth; // StatBase.maxHealth should = 70 but the
// number never stops adding
nomatter = false;
}
}
}
To be honest that logic is quite strange.
Why have this bool flag if you already have one you want to act on? You can simply do
void Update()
{
if (Input.GetMouseButtonDown(0))
{
healthcalc();
}
}
// in general rather put this on class level and don't nest it under Update
void healthcalc()
{
StatBase.maxHealth += rstat.maxHealth;
}
or if there is only one line anyway even
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StatBase.maxHealth += rstat.maxHealth;
}
}

Passing data between scenes Errors

I have made a game manager making sure my data gets passed on from the first scene on to the next scene. Within the game manager, I have added certain scripts to ensure it gets passed. As you can see in the picture underneath.
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
The second problem is that while the score manager does work. The health script cancels everything out when switching levels.
The user starts with 10 health. Takes damage in the first scene, but in the second scene, the user still has 10 health for some reason?
Game Manager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public ActionButton PopupPrefab;
private ActionButton currentlySpawnedPopup;
public static GameManager instance = null;
void Awake () {
if (instance == null) {
instance = this;
} else if (instance != this) {
Destroy (gameObject);
}
Application.targetFrameRate = 60;
}
void Update () {
//if (Input.GetKeyDown(KeyCode.R)) {
// RestartScene ();
//}
}
public void InvokeRestartScene (float time) {
Invoke ("RestartScene", time);
}
public void RestartScene () {
SceneManager.LoadScene (0);
}
public void SpawnPopup (Vector2 position) {
DespawnPopup ();
currentlySpawnedPopup = Instantiate (PopupPrefab, position, Quaternion.identity) as ActionButton;
}
public void DespawnPopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.DestroySelf();
currentlySpawnedPopup = null;
}
}
public void FadePopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.FadeMe ();
currentlySpawnedPopup = null;
}
}
}
Score Manager
using UnityEngine;
using System;
using System.Collections;
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance { get; private set; }
public int Score { get; private set; }
public int HighScore { get; private set; }
public bool HasNewHighScore { get; private set; }
public static event Action<int> ScoreUpdated = delegate {};
public static event Action<int> HighscoreUpdated = delegate {};
private const string HIGHSCORE = "HIGHSCORE";
// key name to store high score in PlayerPrefs
void Awake()
{
if (Instance)
{
DestroyImmediate(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
Reset();
}
public void Reset()
{
// Initialize score
Score = 0;
// Initialize highscore
HighScore = PlayerPrefs.GetInt(HIGHSCORE, 0);
HasNewHighScore = false;
}
public void AddScore(int amount)
{
Score += amount;
// Fire event
ScoreUpdated(Score);
if (Score > HighScore)
{
UpdateHighScore(Score);
HasNewHighScore = true;
}
else
{
HasNewHighScore = false;
}
}
public void UpdateHighScore(int newHighScore)
{
// Update highscore if player has made a new one
if (newHighScore > HighScore)
{
HighScore = newHighScore;
PlayerPrefs.SetInt(HIGHSCORE, HighScore);
HighscoreUpdated(HighScore);
}
}
}
Health Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Health : MonoBehaviour {
public UnityEvent OnTakeDamageEvent;
public UnityEvent OnTakeHealEvent;
public UnityEvent OnDeathEvent;
[Header ("Max/Starting Health")]
public int maxHealth;
[Header ("Current Health")]
public int health;
[Header ("IsDeathOrNot")]
public bool dead = false;
[Header ("Invincible")]
public bool invincible = false;
public bool becomeInvincibleOnHit = false;
public float invincibleTimeOnHit = 1f;
private float invincibleTimer = 0f;
[Header ("Perform Dead Events after x time")]
public float DieEventsAfterTime = 1f;
void Start () {
health = maxHealth;
}
void Update () {
if (invincibleTimer > 0f) {
invincibleTimer -= Time.deltaTime;
if (invincibleTimer <= 0f) {
if (invincible)
invincible = false;
}
}
}
public bool TakeDamage (int amount) {
if (dead || invincible)
return false;
health = Mathf.Max (0, health - amount);
if (OnTakeDamageEvent != null)
OnTakeDamageEvent.Invoke();
if (health <= 0) {
Die ();
} else {
if (becomeInvincibleOnHit) {
invincible = true;
invincibleTimer = invincibleTimeOnHit;
}
}
return true;
}
public bool TakeHeal (int amount) {
if (dead || health == maxHealth)
return false;
health = Mathf.Min (maxHealth, health + amount);
if (OnTakeHealEvent != null)
OnTakeHealEvent.Invoke();
return true;
}
public void Die () {
dead = true;
if (CameraShaker.instance != null) {
CameraShaker.instance.InitShake(0.2f, 1f);
}
StartCoroutine (DeathEventsRoutine (DieEventsAfterTime));
}
IEnumerator DeathEventsRoutine (float time) {
yield return new WaitForSeconds (time);
if (OnDeathEvent != null)
OnDeathEvent.Invoke();
}
public void SetUIHealthBar () {
if (UIHeartsHealthBar.instance != null) {
UIHeartsHealthBar.instance.SetHearts (health);
}
}
}
I have thought of adding the following script on to my Health Script
But then I get the following error messages:
" Cannot implicitly convert type 'int' to 'bool'"
"The left-hand side of an assignment must be a variable, property or indexer"
void Awake()
{
if (health)
{
DestroyImmediate(gameObject);
}
else
{
(int)health = this;
DontDestroyOnLoad(gameObject);
}
}
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
You can make one of the scripts set the UI text score when the scene is loaded.
void Start(){
// Loads the scoreText on start
scoreText.text = yourCurrentScore.ToString();
// Will work unless it has a "DontDestroyOnLoad" applied to it
}
The second problem is that while the score manager does work. The
health script cancels everything out when switching levels. The user
starts with 10 health. Takes damage in the first scene, but in the
second scene, the user still has 10 health for some reason?
In your health script, you had this:
void Start () {
health = maxHealth;
}
This resets your health everytime the scene loads and starts (Aka when you load to the next level). This causes the issue.
" Cannot implicitly convert type 'int' to 'bool'"
if (health)
The () for the if statement should be a condition (a question).
For example, doing health < 0 is valid since its saying "Is health less than 0?"
Doing health is not, since its just saying "10" (or some number).
"The left-hand side of an assignment must be a variable, property or
indexer"
(int)health = this;
If you wanted to change the value of health, just do health = 10 or health = some_Variable_That_Is_An_Integer

How can I make a C# script execute in a certain order?

I have a script conflict that checks if there is network connection and the version of the game (if it's up to date); but it's skipping those conditions and loading the game directly.
How do I make the script follow this pattern?:
Check if there is internet connection
Check the version of the game
Only load the game if there is an internet connection and the version of the game is current
You'll notice there are some loading function who repeat themselves; I'm not sure which ones to apply.
CheckNetwork.cs
public Text AlertText;
public GameObject alert;
public string URL = "";
public string CurrentVersion;
string latestVersion;
public GameObject newVersionAvailable;
private void Start()
{
StartCoroutine(LoadTxtData(URL));
}
void Awake()
{
if (Application.internetReachability == NetworkReachability.NotReachable)
{
alert.SetActive(true);
AlertText.text = "Sorry, you have to enable your conection to play this game";
if (Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
}
else
{
alert.SetActive(false);
CheckVersion();
}
}
public void CheckVersion()
{
if(CurrentVersion != latestVersion)
{
newVersionAvailable.SetActive(true);
}
else
{
newVersionAvailable.SetActive(false);
}
}
private IEnumerator LoadTxtData(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
latestVersion = www.ToString();
CheckVersion();
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
Loading.cs
private Image progressBar;
private void Start()
{
Invoke("LoadAsyncOperation", 3f);
StartCoroutine(LoadAsyncOperation());
}
public IEnumerator LoadAsyncOperation()
{
AsyncOperation gameLevel = SceneManager.LoadSceneAsync(1);
while (gameLevel.progress < 1)
{
progressBar.fillAmount = gameLevel.progress;
yield return new WaitForEndOfFrame();
}
}
Loading2.cs
public GameObject loadingScreenObj;
public Slider slider;
AsyncOperation async;
public void StartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
public void LoadScreen(int LVL)
{
//StartCoroutine(loadingScreen());
}
IEnumerator LoadingScreen(int lvl)
{
loadingScreenObj.SetActive(true);
async = SceneManager.LoadSceneAsync(lvl);
async.allowSceneActivation = false;
while (async.isDone == false)
{
slider.value = async.progress;
if (async.progress == 0.9f)
{
slider.value = 1f;
async.allowSceneActivation = true;
}
yield return null;
}
}
SplashScrean.cs
void Start()
{
Invoke("loadMenuLevel", 3f);
Screen.sleepTimeout = SleepTimeout.NeverSleep;
}
void loadMenuLevel()
{
SceneManager.LoadScene("gameplay");
}
void Update()
{
if (Input.GetKey(KeyCode.Mouse0))
{
loadMenuLevel();
}
if (Input.GetKey(KeyCode.Escape))
{
Application.Quit();
}
}
This is happening because you call the Invoke("loadMenuLevel", 3f); method in the Start() method in the SplashScrean.cs script.
Start() is invoked very soon after a MonoBehaviour is attached to an object. Ostensibly, you have it attached to a GameObject in the scene. All of these are being hit at once.
You also have it as invokable via left mouse click in the same script's Update() method:
if (Input.GetKey(KeyCode.Mouse0))
{
loadMenuLevel();
}
I would add bools to each of the loading scripts that are set to true when each task completes. Then, in SplashScrean.cs, change the above condition to load the level automatically if all three are complete. Or, keep the key press condition and add the bools.
if (Application.internetReachability != NetworkReachability.NotReachable
&& loadScriptComplete && isCurrentVersion && Input.GetKey(KeyCode.Mouse0))
{
loadMenuLevel();
}
Now, if you also need the Loading MonoBehaviours to wait to execute their loading logic too, then consider adding Update() logic to them that checks the flag you set in CheckNetwork.cs.
//For example. Instead of this
private void Start()
{
Invoke("LoadAsyncOperation", 3f);
StartCoroutine(LoadAsyncOperation());
}
//Do this
private void Update()
{
//Note that we only need to check if it is a CurrentVersion, as if that is true, then we definitely have internet access.
if(CheckNetwork.IsCurrentVersion) {
Invoke("LoadAsyncOperation", 3f);
StartCoroutine(LoadAsyncOperation());
}
}
Edits/Additional Notes As I notice:
CheckNetwork.cs references CheckVersion(); in the else clause. That seems pointless. It is impossible for LoadTxtData() to have set the logic that CheckVersion() relies on in that time frame. A sort of race condition, if you will. Plus, you handle that check in LoadTxtData() anyways, so I would just do that there.
I can't give you a complete copy-pastable code here (mainy because I don't fully understand yet how all your scripts are connected between each other) but I see you are already using Coroutines.
I would as mentioned before use one central manager to handle all those things.
I will only give you a general pseudo-code here and hope you find your way frome here
public class LoadManager
{
public CheckNetwork check;
public Loading loading;
public Loading2 loading2;
public SplashScrean splashScreen;
// suprise: a not well documented fact
// you can simply make the Start method an IEnumerator (Coroutine)
// so you can directly wait for anything you want
private void IEnumerator Start()
{
// Next suprise: You can simply yield other IEnumerators
// that makes them execute and at the same time waits until they are finished
// so all methods that you want to wait for from here
// should be IEnumerators
// as said this is only an example
// you could directly within that single
// Coroutine do your complete download and check routine together
yield return check.CheckPermissions();
if(!check.isReachable)
{
yield break;
}
// same for chekcing the version
yield return check.CheckVersion();
if(!check.isUpToDate)
{
// do something for update
yield break;
}
// is up to date so start and wait for loading
yield return loading.LoadAsyncOperation();
// and so on
}
}
And there are also some builtin ways for waiting like e.g. WaitUntil, WaitForSeconds etc.

Scripting in unity 3d

I am facing a problem in Unity3D. I have the same health script attached to both the player and the enemy. I want to show the game-over message when the player dies but the issue is that the game over message appears for both the player and enemy when they die.
My code looks like is that:
public class CharacterStats : MonoBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
health = Mathf.Clamp (health, 0, 100);
}
public void damage(float damage)
{
health -= damage;
if(health<=0)
{
Die();
Application.LoadLevel(gameover);
}
}
void Die()
{
characterController.enabled = false;
if (scriptstodisable.Length == 0)
return;
foreach (MonoBehaviour scripts in scriptstodisable)
scripts.enabled = false;
if (ragdollmanger != null)
ragdollmanger.Raggdoll();
}
}
As you are using 1 script for both player and enemy. You should have different classes for both and implement an interface or derive from a base class to implement health:
public class Character : MonoBehaviour
{
public float Health;
public virtual void Damage(float damageValue)
{
Health -= damageValue;
}
public virtual void Die()
{
}
}
public Enemy : Character
{
public override void Die()
{
// do enemy related stuff
}
}
public Player : Character
{
public override void Die()
{
// do player related stuff.
// like game over screen
}
}
Hope this helps :)
You could use a bool to check whether CharacterStats is attached to the player, for example by adding a tag called ”Player” to the player game object and checking if gameObject.tag == “Player”, or you could equivalently name the game object ”Player” and check gameObject.name if you so wish.
You could then run the function for the game over message only if the game object is a player (isPlayer is true).
public class CharacterStats : MonoBehaviour
{
bool isPlayer = false;
// Use this for initialization
void Start ()
{
if(gameObject.tag == “Player”)
{
isPlayer = true;
}
}
// Update is called once per frame
void Update ()
{
health = Mathf.Clamp (health, 0, 100);
}
public void damage(float damage)
{
health -= damage;
if(health<=0)
{
if(isPlayer)
{
// Do Player-only stuff
}
// Do Stuff for both players and enemies
}
}
}

Unity3D C# not going to the else statement (Invoke Repeating)

I'm currently making my first game using Unity3D written in C#. I've faced some game bug just now, and it's been hours that I've been thinking of what might have been wrong with my code, but I can't see anything wrong.
I have a stat called healthRegen which add HP to the character every second. What I have noticed is even when my player HP drops to zero, it just keep adding HP to my player, thus making it alive again. I have a method that checks if my character HP drops to zero but it didn't call it and I don't know why.
public bool fullHealth() {
if(currentHealth >= maxHealth) {
return true;
} else {
return false;
}
}
public void adjustHealth() {
if(currentHealth > maxHealth) {
currentHealth = maxHealth;
}
if(currentHealth < 0) {
currentHealth = 0;
}
}
That is my method and this is my player script
void Start() {
InvokeRepeating("regenerate", 0f, 1f);
}
// Check if the player is still alive
public bool isDead() {
if (attribute.currentHealth == 0) {
return true;
} else {
return false;
}
}
// Die method
public void dead() {
animation.Play(dieClip.name);
}
private void regenerate() {
if (!attribute.fullHealth()) {
attribute.currentHealth += attribute.healthRegen;
} else {
attribute.adjustHealth();
}
}
This maybe a dumb question for others but I'm sorry, I don't know what to do anymore.
Looks like your problem is that regenerate() is adding health to your player if his health is at 0.
You just need to add a call to isDead() to prevent this.
private void regenerate() {
if (!attribute.fullHealth() && !attribute.isDead()) {
attribute.currentHealth += attribute.healthRegen;
} else {
attribute.adjustHealth();
}
}
I just found out a solution right now, I forgot the CancelInvoke() method
private void regenerate() {
if (!attribute.fullHealth()) {
attribute.currentHealth += attribute.healthRegen;
} else {
CancelInvoke("regenerate");
attribute.adjustHealth();
}
}
Now it's working perfectly!

Categories