In the fishing mini game I'm working on, each unique fish that the player catches is written to a "journal" type UI. If the player has caught that type again, instead of writing a whole new entry to the UI, a score increments by 1 to show how many times they've caught that type of fish.
I'm using scriptable objects to store the information about each fish (name, size, a picture, etc) along with the number of times it's been caught. I can see in the inspector that the variable is increasing each time that fish is caught and I'm also debugging a message each time a unique fish has been caught as well as the number of times.
The UI seems to update the number of times caught the first time, however, however it seems to always stay at 1 for every time that fish is caught afterwards, even though the variable that I'm writing to the UI is changing.
Here's the code that updates the UI:
public void UpdateFishPages(Fish fish)
{
if (!CheckIfExists(fish))
{
Debug.Log("New Fish: " + fish.fishName + " " + "caught ");
Debug.Log("Fish index: " + fishIndex);
fishCaught.Add(fish);
fishes[fishIndex].SetActive(true);
fishes[fishIndex].GetComponent<Image>().sprite = fish.image;
fishes[fishIndex].transform.GetChild(0).transform.GetChild(0).GetComponent<TMPro.TextMeshProUGUI>().text = fish.fishName;
fishes[fishIndex].transform.GetChild(0).transform.GetChild(1).GetComponent<TMPro.TextMeshProUGUI>().text = fish.fishDesc;
fishes[fishIndex].transform.GetChild(0).transform.GetChild(2).GetComponent<TMPro.TextMeshProUGUI>().text = fish.fishSize;
string newFishCount = fish.timesCaught.ToString();
Debug.Log(newFishCount);
fishes[fishIndex].transform.GetChild(1).transform.GetChild(0).GetComponent<TMPro.TextMeshProUGUI>().text = newFishCount;
fishIndex++;
}
else
{
string newFishCount = fish.timesCaught.ToString();
Debug.Log(fish.fishName + " now caught " + fish.timesCaught + " times!");
fishes[fishIndex].transform.GetChild(1).transform.GetChild(0).GetComponent<TMPro.TextMeshProUGUI>().text = newFishCount;
}
}
bool CheckIfExists(Fish fish)
{
if (fishCaught.Contains(fish))
{
return true;
}
else
{
return false;
}
}
and here's how I'm calling that method when a player catches the fish:
if (Input.GetKeyDown(KeyCode.E) || Input.GetButtonDown("Button A"))
{
if (timer < 1f)
{
int randomFish = Random.Range(1, 5);
playerAnimator.SetInteger("fishing_randomIndex", randomFish);
fish[randomFish - 1].timesCaught++;
journal.UpdateFishPages(fish[randomFish - 1]);
//Debug.Log("caught");
timer = 0;
fishStage = 2;
}
}
else if (timer > 1f)
{
//Debug.Log("Didn't reel");
playerAnimator.SetTrigger("fishing_fail");
}
I'm hoping someone can shed some light onto what I might be doing wrong.
Many thanks for your time and help!
Related
Currently, I am working on a puzzle roll a ball game on Unity and I've came across a problem with my program I have created a code which provides all the information I need where if the player picks up coins they collected the coin however there is another thing that the player needs to collect and it is the key to the next room. However, I came to a problem where the statement shows that I need a semicolon but when I add the semicolon the entire code is wrong and it doesn't provide a possible answer to my code.
the code string:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Coin"))
{
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
else
**{ (other.gameObject.CompareTag("Key"))**
other.gameObject.SetActive(false);
count = count + 1;
Setkeycount();
}
}
Can not understand this part :
else
**{ (other.gameObject.CompareTag("Key"))**
other.gameObject.SetActive(false);
count = count + 1;
Setkeycount();
}
Did you mean:
else if(other.gameObject.CompareTag("Key"))
{
other.gameObject.SetActive(false);
count = count + 1;
Setkeycount();
}
Update: This issue may be caused by binaryformatter's issues with editing data in existing fields. A comment that I can no longer find described alternate methods which I am currently implementing. Will update after these methods are attempted if it is a solution to the problem.
I should start by saying I am a student so please go easy on me, I got reported when I first started coming here and hope to keep learning. I an new to unity, my C# is decent, but full of gaps since my schooling was rather terrible. I have watched hundreds of hours of unity tutorials and am studying the new concepts I learn for 4 hours every night after I get out of work, so if you see something just let me know.
This is actually a problem I have had for a while, but thought I fixed months ago. I was attempting to save games for the first time, and read into binary formatting and such to save. I had problems getting it up, but I I managed to get it to save and pull properly from a file. I verify that the data going into the file is correct, and the data coming out is correct, and even made the data private with a control function so nothing will access and change it without jumping through my debug. And yet after I leave the scope where I define the data it changes, without anything accessing my update function.
To break it down I have a class called PlayerType that stores all player information including my scenemanager, and it serializes this and saves to a file as a list. I create a for loop using the current length of the loaded list using an instance of the saveload class (this is what holds the list of save games and the access to the file) and it loops through instantiating my buttons in the order. Slot 1 will click to save game 1 and so to speak. The issue I am having is clicking slot 1 clicks slot 16, so does slot 2. In face, it seems practically random which buttons go to which slot. I should say here I am not sure whether it is actually going to the wrong slot, or simply renaming the player names wrong, but either way it does not appear this should be the case.
Here is my load function
public void Load() //Loads file from .gd file after checking if exists, then deserializes it back into a list
{
accessDataPath(false);
Debug.Log("Size of Save File" + listSize);
for (int i = 0; i < listSize; i++)
{
Debug.Log("First Loop " + SavedGames[i].returnName());
}
foreach (PlayerType player in GameManager.instance.saveStorage.returnList())
{
Debug.Log("Second Loop" + player.returnName());
}
}
and here is my accessDataPath function
public void accessDataPath(bool isSave)
{
//This stucture checks if file exists or not, then checks if saving or loading for 4 outcomes
if (isSave && SavedGames == null)//if saving and save file to update has nothing in it
{
Debug.Log("Error attempted to save null list in SaveLoad.accessDataPath!");
}
if (File.Exists(Application.persistentDataPath + "/SavedGames.gd"))//if the file exists
{
if (isSave)//if you are saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/SavedGames.gd", FileMode.Open);
bf.Serialize(file, SavedGames);
file.Close();
}
else //if you are not saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/SavedGames.gd", FileMode.Open);
SavedGames = (List<PlayerType>)bf.Deserialize(file);
file.Close();
listSize = SavedGames.Count;
}
}
else//if the file does not exist
{
if (isSave)//if you are saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/SavedGames.gd");
bf.Serialize(file, SavedGames);
file.Close();
}
else//if you are not saving
Debug.Log("Error Loading File. Does not Exist!");//Display Later that file does not exist to user
}
updateNames();
}//End accessDataPath
here is the function that updates the names
public void updateNames()
{
for (int i = 0; i < listSize; i++)
{
SavedGames[i].updateName("Player " + i);
Debug.Log("Bump " + i);
}
}
As you can see I verify if it exists, then check if I am saving or loading. The save function calls with a true and SavedGames is the list that is pulled from the file. Now After I run the name change I can check to see if it worked, and it does. Running the check here they all come back as the proper name, however by the time it gets back to my load function and runs my first loop they are wrong, it never leaves this section of code but as soon as it exits the scope they change to be almost random.
Now I had this problem for a while, but thought it had to do with my file maybe having corrupt data, so I deleted the save game and created new ones to test. The numbers changed, but were still not right. This tells me that somehow the file is effecting the names even though I rename them almost immediately after they come out. I am not used to loading or saving to files so I am not sure where to start here.
I will post more of my code below in case some of it stands out as being blatantly wrong, I also appreciate advice on structure as I took college classes on game programming but they were terrible and filled with gaps even if you don't spot the answer to my problem.
First I have my menu system setup to be toggled on or off, called by onclick events.
public class SaveMenu : MonoBehaviour {
public GameObject menu;
bool isActive;
bool isSave;
PopulateSave playerSaves;
public static SaveMenu instance;
void Awake()
{
isSave = false;
instance = this;
menu = GameObject.Find ("SaveList");
menu.SetActive (false);
isActive = false;
playerSaves = menu.GetComponentInChildren<PopulateSave> ();
}
public bool getActive()
{
return isActive;
}
public void toggleMenu(bool saveLoad)
{
if (isActive)
{
menu.SetActive (false);
isActive = false;
} else
{
menu.SetActive (true);
isActive = true;
}
bool isSave = saveLoad;
menu.transform.Find("Scroll View").transform.Find("Viewport").transform.Find("Content").transform.Find("NewSave").gameObject.SetActive(isSave);
Debug.Log(isSave);
}
public void updateSave()
{
playerSaves.startList();//Seems redundant but is used to make this access public with limited use
}
public bool getSave()
{
return isSave;
}
}
I call populatesaves as a child after everything is created because I had issues with it not existing when I tried to bring it in via the inspector. PopulateSaves is where most of my functional code is.
public class PopulateSave : MonoBehaviour{
public Button NewSave;
public Button OldSaves; // This is our prefab object that will be exposed in the inspector
void Awake()
{
GameManager.instance.saveStorage.Load();
Populate();
}
void Update()
{
}
void Populate()
{
Button newObj = Instantiate(NewSave, transform); // Create GameObject instance
newObj.name = "NewSave";
startList();
}
public void startList()
{
clearList();
for (int i = 1; i < GameManager.instance.saveStorage.returnCount() + 1; i++)
{
createButton(i);
}
Debug.Log("Done creating");
}
public void updateList(PlayerType newSave)
{
Button newObj;
newObj = (Button)Instantiate(OldSaves, transform);
//GameManager.instance.saveStorage.Save(i);
}
public void clearList()
{
GameObject[] gameObjects;
gameObjects = GameObject.FindGameObjectsWithTag("SaveSlot");
for (var i = 0; i < gameObjects.Length; i++)
Destroy(gameObjects[i]);
Debug.Log("Done Destroying");
}
public void ButtonClicked(int slot)
{
if (SaveMenu.instance.getSave())
{
Debug.Log("Save");
GameManager.instance.saveStorage.Save(slot);
}
else
{
Debug.Log("load");
GameManager.instance.currentPlayer.newPlayer(slot);
}
}
public void createButton(int i)
{
// Create new instances of our prefab until we've created as many as is in list
Button newObj = (Button)Instantiate(OldSaves, transform);
//increment slot names
newObj.name = "Slot " + i;
newObj.GetComponentInChildren<Text>().text = "Slot " + i;
newObj.onClick.AddListener(() => ButtonClicked(i));
}
}
Now I also have never written a listener with a script like I have here, could that section be assigning the wrong number to them? I checked to make sure all my indexes had the right numbers, if not being 1 off. One of my loops might use a setup that is 1 off but I am more worried about getting this off the ground and fixing the specifics at this point.
Here is my player storage
[System.Serializable]
public class PlayerType {
string playerName;
SceneManagement currentScene;
public PlayerType()
{
playerName = "Starting Name";
}
public void updateName(string name)
{
//Debug.Log("New Name: " + name);
playerName = name;
}
public void updateScene(SceneManagement newScene)
{
currentScene = newScene;
}
public string returnName()
{
return playerName;
}
public SceneManagement returnScene()
{
return currentScene;
}
public void newPlayer(int slotSave)
{
//Tmp player has wrong name from this point, initiated wrong?
//Debug.Log("New Name to update" + tmpPlayer.returnName());
this.updateName(GameManager.instance.saveStorage.returnSaves(slotSave).returnName());
this.updateScene(GameManager.instance.saveStorage.returnSaves(slotSave).returnScene());
}
}
Update:
Bump correctly goes through displaying 0-16
then Size of Save File displays 17 total saves
First loop then starts by outputting 'First Loop Player 15' a total of 16 times
Then it displays 16 so the last one is correct, though one off I guess.
Second loop does the same as first, unsurprisingly.
I left the call to updateNames in but commented out the lines and ran it including taking out bump.
It starts with 17 saves again and the 16 time iteration of player 15, however this time around the last one displays 'Temp Name' which I only define once at the beginning of my sceneManagement script for the current player, it should have never been saved, and even if it had been should have been overwritten by my name loop, at least that was my intent.
SceneManagement
[System.Serializable]
public class SceneManagement : MonoBehaviour {
DialogueManager dialogueManager;
PlayerType currentPlayer;
bool isSave;
bool isActive;
string sceneName;
int lineCount;
void Start()
{
isSave = false;
//loads player object for the current save
currentPlayer = new PlayerType();
currentPlayer.updateName ("Temp Name");
//This loads the prologue from the DB and sets the dialoguemanager up, defaults to prologue for now but can be updated to another scene later
isActive = true;
sceneName = "Prologue";
string conn = "URI=file:" + Application.dataPath + "/Text/Game.sqlite3";
List<string> sceneLines = new List<string>();
List<string> sceneCharacters = new List<string>();
int tmpInt;
string tmpString = "NOTHING";
int count = 0;
lineCount = 1;
IDbConnection dbConn;
dbConn = (IDbConnection)new SqliteConnection (conn);
dbConn.Open (); //Open database connection
IDbCommand dbCmd = dbConn.CreateCommand();
string sqlQuery = "SELECT Line, Flags, Character, Image, Text, Color FROM Prologue";
dbCmd.CommandText = sqlQuery;
IDataReader reader = dbCmd.ExecuteReader ();
while (reader.Read ()) {
tmpInt = reader.GetInt32 (0);
tmpString = reader.GetString (1);
sceneCharacters.Add(reader.GetString (2));
tmpInt = reader.GetInt32 (3);
sceneLines.Add(reader.GetString (4));
tmpString = reader.GetString (5);
//Debug.Log (tmpString);
//Debug.Log (count);
count++;
}
reader.Close ();
reader = null;
dbCmd.Dispose ();
dbCmd = null;
dbConn.Close ();
dbConn = null;
dialogueManager = new DialogueManager(sceneCharacters, sceneLines, lineCount);
}
//These are the returnvalues that might be used, may or may not be kept depending on future use.
public string getSceneName()
{
return sceneName;
}
public int getLineCount()
{
return lineCount;
}
public bool getSave()
{
return isSave;
}
//These return the lines for displaymanager, preventing it from directly interacting with dialoguemanager
public string getNextLine()
{
return dialogueManager.getNextLine();
}
public string getNextCharacter()
{
return dialogueManager.getNextCharacter();
}
//This function sets up visibility and is only accessed to properly display the screen after the scene has been started.
public void startScene ()
{
GameManager.instance.screenDisplay.changeVisible(true);
}
void Update()
{
if (Input.GetKeyDown ("space") & isActive) {
dialogueManager.incrementCurrentLine ();
GameManager.instance.screenDisplay.changeText(dialogueManager.getNextLine ());
GameManager.instance.screenDisplay.changeCharacter(dialogueManager.getNextCharacter ());
}
if (Input.GetKeyDown ("escape")) {
if (!PauseMenu.instance.getActive () && !SaveMenu.instance.getActive ())
{
PauseMenu.instance.toggleMenu ();
}
else if (SaveMenu.instance.getActive())
{
SaveMenu.instance.toggleMenu (true);
PauseMenu.instance.toggleMenu ();
}
else if (PauseMenu.instance.getActive())
{
PauseMenu.instance.toggleMenu ();
}
}
}
public void initialScreen()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void OnLevelFinishedLoading (Scene scene, LoadSceneMode mode)
{
GameManager.instance.screenDisplay.initialScreen(dialogueManager.getNextLine(), dialogueManager.getNextCharacter(), null, null,
null, null, null, null);
}
public PlayerType returnPlayer()
{
return currentPlayer;
}
}
while im at it here is my GameManager too, though I havent messed with it a ton. Mostly using it as a DontDestroyOnLoad thing to hold everything else at this point.
public class GameManager : MonoBehaviour{
public static GameManager instance;
public DisplayScreen screenDisplay;
public SceneManagement managerScene;
public SaveLoad saveStorage;
public PlayerType currentPlayer;
//leave out until load data is setup
//PlayerType currentPlayer;
void Awake()
{
instance = this;
DontDestroyOnLoad (transform.gameObject);
managerScene = gameObject.AddComponent(typeof(SceneManagement)) as SceneManagement;
screenDisplay = gameObject.AddComponent (typeof(DisplayScreen)) as DisplayScreen;
saveStorage = gameObject.AddComponent (typeof(SaveLoad)) as SaveLoad;
//initialize player and sceneManager here, but only load through main menu options
//of new game or load game
}
void update()
{
}
}
I have continued troubleshooting and brought it down to a particularly confusing part for me. I took out all debugging logs and added 3 loops into my load function, they are these.
Debug.Log("LOAD CALLED");
accessDataPath(false);
for (int i = 0; i < listSize; i++)
{
Debug.Log("First Loop " + SavedGames[i].returnName());
SavedGames[i].updateName("Updated Player " + (i + 1));
}
for (int i = 0; i < listSize; i++)
{
Debug.Log("Second Loop " + SavedGames[i].returnName());
}
foreach (PlayerType player in GameManager.instance.saveStorage.returnList())
{
Debug.Log("Third Loop " + player.returnName());
}
So the first one displays player 15, then correctly displays the first loops 1-15 then temp name again, still havent 'figured out why that is popping up but I think it is related. Then the second loop iterates all wrong. Literally changed and back to back the loops are wrong, the only difference being it left the scope of the for loop. I ran a third loop using foreach to see if the type of call made a difference and it does not.
Even changing the name, and then immediately calling a loop to check shows that the values are changing. I think it might have something to do with how I am storing the objects, but I am not sure how the problem could be arising. Its not going null, and the names are changing to be the same every time so it isn't completely random. I am posting this here just after I found this hoping that soon I will solve it, but am also hoping if I do not someone else might spot something. I have the next 3 hours to work on it so I will be trying this entire time checking back every now and then. Thanks in advance for anyone that might glance at it for me.
Ok so I finally got the implementation done. I had to swap around a ton of my code, and ended up doing a wrapper object/list combination using JSON. Essentially the problem is that binary formatter messes up objects after you de-serialize them. Every time I updated my objects values they would randomly change on me for no reason without being accessed.
This was surprising as about half the posts I read on saving say its good, others like This one say that it is bad practice. I had done some research initially but had not come across the negative aspects of using it. I am still having problems, but Json is successfully retaining data and my objects are not messing up. I am pretty sure this was the problem as the only sections that I changed were my objects value structure to public for the serializing, and implemented the json structure into my SaveLoad script. This video was very helpful for the overall structure and getting started, and This thread helped me with troubleshooting when I ran into several problems.
I should also note that one thing I did not catch for a while. While Json can load lists, the initial object to be loaded must not be a list. I was attempting to save a list of my PlayerType directly into a folder, which it will not do. I ended up creating a quick object that contained my list and then saving the object. Since everywhere I read said that lists were fine it took a while to discover that this was causing part of my problem. It was not giving me any errors, just returning a blank string which most threads said was because it was not public or serializable.
Anyway here is to hoping my struggles and searches for answers might help as the things I found were quite scattered and hard to come across.
I working with an Admob API from Github -> https://github.com/unity-plugins/Unity-Admob
Im facing a strange problem. My Script works! I start ShowRewardVideo() on button click and it shows me the video. Afterwards i want to gift Coins to my User. As you can see it just increases the current Amount of Coins in PlayerPrefs by adding 20.
Where the problem is? I dont get +20 Coins i geta random amount of coins extra. Last time it was +280 and +320 before that. I tested it with other amounts and it seems like i always get the reward multiple times. So 14 * 20 = 280 and so on.
But why ismy script adding the reward multiple times?
Can you please help me?
private void Start() {
Admob.Instance().rewardedVideoEventHandler += onRewardedVideoEvent;
}
public void ShowRewardVideo() {
if(Admob.Instance().isRewardedVideoReady()) {
Admob.Instance().showRewardedVideo();
} else {
Admob.Instance().loadRewardedVideo("ca-app-pub-5129395190259237/xxxxxxxxx");
ShowRewardVideo();
}
}
void onRewardedVideoEvent(string eventName, string msg) {
Debug.Log("handler onRewardedVideoEvent---" + eventName + " " + msg);
if(eventName == "onRewarded") {
PlayerPrefs.SetInt("mmig", PlayerPrefs.GetInt("mmig") + 20);
PlayerPrefs.Save();
}
}
I would first of all check how often this part of your code gets called:
if(eventName == "onRewarded") {
PlayerPrefs.SetInt("mmig", PlayerPrefs.GetInt("mmig") + 20);
PlayerPrefs.Save();
}
Do this simply make a Debug.Log("Runned") call or something similar.
Also you should maybe consider to do this part:
PlayerPrefs.SetInt("mmig", PlayerPrefs.GetInt("mmig") + 20);
With something like this:
int oldAmount = PlayerPrefs.GetInt("mmig");
int newAmount = oldAmount + 20;
PlayerPrefs.SetInt("mmig",newAmount);
To avoid possible implicit covertig errors. But this change it not necessary for your current problem, just a tip :).
Just make sure to check how many times you get the output above in your console
I am trying to teach myself C# and Unity knowledge via this course over on Udemy.com.
In one of the first examples a very basic text adventure was created.
Now starting from scratch, I have used the same game structure used there, trying to recreate my own version of this, I've run into a problem:
Input.GetKeyDown(KeyCode.R)
gets activated multiple times in a row and I haven't found the solution in hours.
Here's the relevant parts of the code:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class TextEngine : MonoBehaviour {
public Text myText;
private int oxygen;
private enum States
{
wakeup, window_0, room_1, corridor_1, corridor_left,
corridor_right, corridor_right_left, locked_supply_door,
damaged_supply_door, supply_door_keypad
}
private States myState;
// Use this for initialization
void Start() {
myState = States.wakeup;
}
// Update is called once per frame
void Update()
{
// Basic gameplay loop:
//if myState equals scenario a, then call method a
if (myState == States.wakeup) wakeup();
if (myState == States.room_1) room1();
if (myState == States.corridor_1) corridor_1();
if (myState == States.corridor_right) corridor_right();
if (myState == States.locked_supply_door) locked_supply_door();
}
void wakeup()
{
oxygen = 100;
myState = States.room_1;
}
void room1()
{
myText.text = "Oxygen Level: " + oxygen + "\n\nYou wake up. Press W to see Window. "
+"Press C to go down the Corridor.";
if (Input.GetKeyDown(KeyCode.W))
{
myState = States.window_0;
}
else if (Input.GetKeyDown(KeyCode.C))
{
myState = States.corridor_1;
}
}
void corridor_1()
{
myText.text = "Oxygen Level: " + oxygen + "\n\nYou walk the corridor to the end."
+ "You can turn Left or Right.\nFrom the Left you hear two gun shots!"
+"\nFrom the Right side comes an eerie silence."
+ "\n\nPress L to turn Left, R to turn Right. Press B to go Back.";
if (Input.GetKeyDown(KeyCode.L))
{
myState = States.corridor_left;
}
else if (Input.GetKeyDown(KeyCode.R))
{
print("R1");
myState = States.corridor_right;
}
else if (Input.GetKeyDown(KeyCode.B))
{
print("B");
myState = States.room_1;
}
}
void corridor_right()
{
myText.text = "Oxygen Level: " + oxygen + "\n\nAnother T-junction!\n"
+ "You can turn Left or Right.\nFrom the left you still hear nothing."
+ "\nFrom the Right side you hear a deep and frightening buzz!"
+ "\n\nPress L to turn Left, R to turn Right. Press B to go Back.";
if (Input.GetKeyDown(KeyCode.L))
{
myState = States.corridor_right_left;
}
else if (Input.GetKeyDown(KeyCode.R))
{
print("R2");
myState = States.locked_supply_door;
}
else if (Input.GetKeyDown(KeyCode.B))
{
print("B");
myState = States.corridor_1;
}
}
void locked_supply_door()
{
myText.text = "Oxygen Level: " + oxygen + "\n\nYou stand in front of a rusty metal door. You step closer. At eye-level there is a dusty sign, "
+ "barely readable. You wipe off the dust. It reads: 'Supply Room'. Maybe you can find some Oxygen tanks and "
+ "some communication devices in there?"
+ "\n\nPress S to Search for a handle."
+ "\n\nPress R to Ram the door, it looks weak!\n\n"
+ "Press B to go Back.";
if (Input.GetKeyDown(KeyCode.S))
{
myState = States.supply_door_keypad;
}
else if (Input.GetKeyDown(KeyCode.R))
{
print("R3");
myState = States.damaged_supply_door;
}
else if (Input.GetKeyDown(KeyCode.B))
{
print("B2");
myState = States.corridor_1;
}
}
}
What I expect to happen:
The game starts.
myState = States.wakeup; gets initalized.
wakeup() is called, myState = States.room_1; calls room1() via Update() and the text displayed on screen.
When pressing the C key, room(1) calls myState = States.corridor_1; which via Update() calls corridor_1() and the text is display again.
Everything working as expected so far. But now everthing goes wrong.
I expect this behavior:
4.A I press the R key, "R1" gets printed and via myState = States.corridor_right; the corridor_right() is called and waits for another key prompt.
But then this happens:
4.B I press the R key, "R1" gets printed and via myState = States.corridor_right; the corridor_right() is called and then without anymore input immediately "R2" gets printed, myState = States.locked_supply_door; is executed, which calls locked_supply_door() via Update() and then immediately "R3" gets printed to the console and then it changes myState = States.damaged_supply_door; where it would continue to call a method via Update(), but I've not yet implemented that method.
The steps seem to get executed correctly, but that GetKeyDown behaves more like `GetKey' and not like itself!
Why does GetKeyDown seemingly get activated multiple times, even when it's supposed to do so only once?
Most problems the people have seem to call GetKeyDowntwice, but not what seems several times.
A common problem seemed to be that the script is attached multiple times somewhere in Unity, which is not the case here: Canvas with Text Field + attaced Script.
If you have made it this far, I want to thank you for the time you already took to help me.
If only I could solve this problem, I cannot find the solution! My rubber duck also doesn't help me here.
The problem is that you are not doing the "update" with ELSE, so when you change from one state to another, it will not wait 1 frame to pass, and will directly go other if, because you changed and is correct, you enter the other if, and because a frame didn't pass till the last R was down, it will still say true to that...
So, in your "Update" function, make them with ELSE IF, not all IF. This way, when you enter one if, when the function inside finished, it will pass 1 frame to re enter.
So change Update to this:
void Update()
{
// Basic gameplay loop:
//if myState equals scenario a, then call method a
if (myState == States.wakeup) wakeup();
else if (myState == States.room_1) room1();
else if (myState == States.corridor_1) corridor_1();
else if (myState == States.corridor_right) corridor_right();
else if (myState == States.locked_supply_door) locked_supply_door();
}
I'm writing a small mathematical game where sums are generated, and when answered, scored and then another sum is generated. The program is, as of an hour or so ago, flawless but for one thing; the program crashes if the user attempts to input anything that contains more than numbers (with the exception of putting a - before the numbers, for a negative value). Here is my current code for parsing input (I may be using that terminology wrong; if so, I'm sorry):
private void txtAnswer_KeyPress(object sender, KeyPressEventArgs e)
{
// If a press of the enter key is detected...
if(e.KeyChar == (char)Keys.Return)
{
// The player's answer is converted to an integer and checked against the correct answer.
userguess = System.Convert.ToInt32(txtAnswer.Text);
if (userguess == answer)
{
// If the player's answer is correct, an appropriate message is displayed and 1 point added to the kill-score.
lblResult.Text = "# Enemy charge calculated correctly, charge bounced back and damage evaded.";
lblRight.Text = (System.Convert.ToInt32(lblRight.Text) + 1).ToString();
}
else
{
// If the player's answer is incorrect, an appropriate message is displayed and 100 points are added to the damages cost counter.
lblResult.Text = "# Enemy charge calculated incorrectly, charge fired and hit! The charge had " + answer.ToString() + " power units applied.";
lblWrong.Text = (System.Convert.ToInt32(lblWrong.Text) + 100).ToString();
}
// After appropriate action has been taken based on the player's answer, a new sum is generated.
makeNewSum();
}
}
I'm not that advanced of a coder, and I've no idea how I can get it to check what is actually being submitted before allowing it through and crashing if it's bad. Can anyone help me out?
That's because a character for example can't be converted to Int32, change this:
userguess = System.Convert.ToInt32(txtAnswer.Text);
to this:
if (!int.TryParse(txtAnswer.Text, out userguess)) { return; }
If it succeeds then it will set the integer value to userguess so the remainder of the program can stay the same.
Try something like this:
int userguess;
if (int.TryParse(txtAnswer.Text, out userguess))
{
if (userguess == answer)
{
// If the player's answer is correct, an appropriate message is displayed and 1 point added to the kill-score.
lblResult.Text = "# Enemy charge calculated correctly, charge bounced back and damage evaded.";
lblRight.Text = (System.Convert.ToInt32(lblRight.Text) + 1).ToString();
}
else
{
// If the player's answer is incorrect, an appropriate message is displayed and 100 points are added to the damages cost counter.
lblResult.Text = "# Enemy charge calculated incorrectly, charge fired and hit! The charge had " + answer.ToString() + " power units applied.";
lblWrong.Text = (System.Convert.ToInt32(lblWrong.Text) + 100).ToString();
}
// After appropriate action has been taken based on the player's answer, a new sum is generated.
makeNewSum();
}
else{
lblResult.Text = "Incorrect value!";
}
TryParse will attempt to parse your text value and put the result in userguess. If it succeeds it returns true, if it fails it returns false.