Forum begins after the advertisement:
[Part 9] The game is frozen
Home › Forums › Video Game Tutorial Series › Creating a Rogue-like Shoot-em Up in Unity › [Part 9] The game is frozen
- This topic has 4 replies, 3 voices, and was last updated 3 weeks, 2 days ago by
Terence.
-
AuthorPosts
-
March 8, 2025 at 8:43 pm #17443::
After creating the results screen (“Done” buttons, character images and his name) I wanted to check how the game works, I selected a character from the menu, and after that the game just freezes and doesn’t get in touch.
March 8, 2025 at 8:51 pm #17444::Based on the reference information, the issue likely stems from the GetData() function not properly selecting a character before the game becomes playable. The reference information suggests that when trying to play the game from the Game scene, you need to select a character first.
However, the specific details of resolving the freezing issue are NOT_FOUND in the provided reference information. More context or code would be needed to diagnose the exact cause of the game freezing after character selection.
March 8, 2025 at 9:03 pm #17445::using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class GameManager : MonoBehaviour { public static GameManager instance; // Define the different states of the game public enum GameState { Gameplay, Paused, GameOver } // Store the current state of the game public GameState currentState; // Store the previous state of the game public GameState previousState; [Header("Screens")] public GameObject pauseScreen; public GameObject resultsScreen; [Header("Current Stat Displays")] public Text currentHealthDisplay; public Text currentRecoveryDisplay; public Text currentMoveSpeedDisplay; public Text currentMightDisplay; public Text currentProjectileSpeedDisplay; public Text currentMagnetDisplay; [Header("Results Screen Displays")] public Image chosenCharacterImage; public Text chosenCharacterName; //Flag to check if the game is over public bool isGameOver = false; private void Awake() { //Warning check to see if there is another singleton of this kind in the game if(instance == null) { instance = this; } else { Debug.LogWarning("EXTRA " + this + " DELETED"); Destroy(gameObject); } DisableScreens(); } void Update() { // Define the behaviour for each state switch (currentState) { case GameState.Gameplay: // Code for the gameplay state CheckForPauseAndResume(); break; case GameState.Paused: // Code for the paused state CheckForPauseAndResume(); break; case GameState.GameOver: // Code for the game over state if (!isGameOver) { isGameOver = true; Time.timeScale = 0f; // Stop the game entirel Debug.Log("GAME IS OVER"); DisplayResults(); } break; default: Debug.LogWarning("STATE DOES NOT EXIST"); break; } } // Define the method to change the state of the game public void ChangeState(GameState newState) { currentState = newState; } public void PauseGame() { if (currentState != GameState.Paused) { previousState = currentState; ChangeState(GameState.Paused); Time.timeScale = 0f; // Stop the game pauseScreen.SetActive(true); Debug.Log("Game is paused"); } } public void ResumeGame() { if (currentState == GameState.Paused) { ChangeState(previousState); Time.timeScale = 1f; // Resume the game pauseScreen.SetActive(false); Debug.Log("Game is resumed"); } } // Define the method to check for pause and resume input void CheckForPauseAndResume() { if (Input.GetKeyDown(KeyCode.Escape)) { if (currentState == GameState.Paused) { ResumeGame(); } else { PauseGame(); } } } void DisableScreens() { pauseScreen.SetActive(false); resultsScreen.SetActive(false); } public void GameOver() { ChangeState(GameState.GameOver); } void DisplayResults() { resultsScreen.SetActive(true); } public void AssignChosenCharacterUI(CharacterScriptableObject chosenCharacterData) { chosenCharacterImage.sprite = chosenCharacterData.Icon; chosenCharacterName.text = chosenCharacterData.Name; } }
March 8, 2025 at 9:04 pm #17446::using System.Collections; using System.Collections.Generic; using UnityEditor.VersionControl; using UnityEngine; public class PlayerStats : MonoBehaviour { CharacterScriptableObject characterData; //Current stats float currentHealth; float currentRecovery; float currentMoveSpeed; float currentMight; float currentProjectileSpeed; float currentMagnet; #region Current Stats Properties public float CurrentHealth { get { return currentHealth; } set { //Check if the value has changed if (currentHealth != value) { currentHealth = value; if(GameManager.instance != null) { GameManager.instance.currentHealthDisplay.text = "Health: " + CurrentHealth; } //Add any additional logic here that needs to be executed when the value changes } } } public float CurrentRecovery { get { return currentRecovery; } set { //Check if the value has changed if (currentRecovery != value) { currentRecovery = value; if (GameManager.instance != null) { GameManager.instance.currentRecoveryDisplay.text = "Recovery: " + CurrentRecovery; } //Add any additional logic here that needs to be executed when the value changes } } } public float CurrentMoveSpeed { get { return currentMoveSpeed; } set { //Check if the value has changed if (currentMoveSpeed != value) { currentMoveSpeed = value; if (GameManager.instance != null) { GameManager.instance.currentMoveSpeedDisplay.text = "Move Speed: " + CurrentMoveSpeed; } //Add any additional logic here that needs to be executed when the value changes } } } public float CurrentMight { get { return currentMight; } set { //Check if the value has changed if (currentMight != value) { currentMight = value; if (GameManager.instance != null) { GameManager.instance.currentMightDisplay.text = "Might: " + CurrentMight; } //Add any additional logic here that needs to be executed when the value changes } } } public float CurrentProjectileSpeed { get { return currentProjectileSpeed; } set { //Check if the value has changed if (currentProjectileSpeed != value) { currentProjectileSpeed = value; if (GameManager.instance != null) { GameManager.instance.currentProjectileSpeedDisplay.text = "Project Speed: " + CurrentProjectileSpeed; } //Add any additional logic here that needs to be executed when the value changes } } } public float CurrentMagnet { get { return currentMagnet; } set { //Check if the value has changed if (currentMagnet != value) { currentMagnet = value; if (GameManager.instance != null) { GameManager.instance.currentMagnetDisplay.text = "Magnet: " + CurrentMagnet; } //Add any additional logic here that needs to be executed when the value changes } } } #endregion //Experience and level of the player [Header("Experience/Level")] public int experience = 0; public int level = 1; public int experienceCap; //Class for defining a level range and the corresponding experience cap increase for that range [System.Serializable] public class LevelRange { public int startLevel; public int endLevel; public int experienceCapIncrease; } //I-Frames [Header("I-Frames")] public float invincibilityDuration; float invincibilityTimer; bool isInvincible; public List<LevelRange> levelRanges; InventoryManager inventory; public int weaponIndex; public int passiveItemIndex; public GameObject firstPassiveItemTest, secondPassiveItemTest; public GameObject secondWeaponTest; void Awake() { characterData = CharacterSelector.GetData(); CharacterSelector.instance.DestroySingleton(); inventory = GetComponent<InventoryManager>(); //Assign the variables CurrentHealth = characterData.MaxHealth; CurrentRecovery = characterData.Recovery; CurrentMoveSpeed = characterData.MoveSpeed; CurrentMight = characterData.Might; CurrentProjectileSpeed = characterData.ProjectileSpeed; CurrentMagnet = characterData.Magnet; //Spawn the starting weapon SpawnWeapon(characterData.StartingWeapon); SpawnWeapon(secondWeaponTest); SpawnPassiveItem(firstPassiveItemTest); SpawnPassiveItem(secondPassiveItemTest); } void Start() { //Initialize the experience cap as the first experience cap increase experienceCap = levelRanges[0].experienceCapIncrease; // Set the current stats display GameManager.instance.currentHealthDisplay.text = "Health: " + CurrentHealth; GameManager.instance.currentRecoveryDisplay.text = "Recovery: " + CurrentRecovery; GameManager.instance.currentMoveSpeedDisplay.text = "Move Speed: " + CurrentMoveSpeed; GameManager.instance.currentMightDisplay.text = "Might: " + CurrentMight; GameManager.instance.currentProjectileSpeedDisplay.text = "Project Speed: " + CurrentProjectileSpeed; GameManager.instance.currentMagnetDisplay.text = "Magnet: " + CurrentMagnet; GameManager.instance.AssignChosenCharacterUI(characterData); } private void Update() { if (invincibilityTimer > 0) { invincibilityTimer -= Time.deltaTime; } //If the invinvibility timer has reached 0, set the invincibility flag to false; else if (isInvincible) { isInvincible = false; } Recover(); } public void IncreaseExperience(int amount) { experience += amount; LevelUpChecker(); } void LevelUpChecker() { if (experience >= experienceCap) //Increase level if the experience is more than or equal to the required amount to level up { //Level up the player and deduct their experience level++; experience -= experienceCap; int experienceCapIncrease = 0; foreach (LevelRange range in levelRanges) { if(level >= range.startLevel && level <= range.endLevel) { experienceCapIncrease = range.experienceCapIncrease; break; } } experienceCap += experienceCapIncrease; } } public void TakeDamege(float dmg) { //If the player is not currently invincible, reduce health and start invincibility if (!isInvincible) { CurrentHealth -= dmg; invincibilityTimer = invincibilityDuration; isInvincible = true; if (CurrentHealth < 0) { Kill(); } } } public void Kill() { if(!GameManager.instance.isGameOver) { GameManager.instance.GameOver(); } } public void RestoreHealth(float amount) { //Only heal the player if their current health is less than their maximum health if(CurrentHealth < characterData.MaxHealth) { CurrentHealth += amount; //Make sure the player's health doesn't exceed their maximum health if(CurrentHealth > characterData.MaxHealth) { CurrentHealth = characterData.MaxHealth; } } } void Recover() { if(CurrentHealth < characterData.MaxHealth) { CurrentHealth += CurrentRecovery * Time.deltaTime; } //Make sure the player's health doesn't exceed their maximum health if (CurrentHealth > characterData.MaxHealth) { CurrentHealth = characterData.MaxHealth; } } public void SpawnWeapon(GameObject weapon) { // Checking if the slots are full, and returning if it is if (weaponIndex >= inventory.weaponSlots.Count - 1) // Must be -1 because a list starts from 0 { Debug.LogError("Inventory slots already full"); return; } //Spawn the starting weapon GameObject spawnedWeapon = Instantiate(weapon, transform.position, Quaternion.identity); spawnedWeapon.transform.SetParent(transform); // Set the weapon to be a child of the player inventory.AddWeapon(weaponIndex, spawnedWeapon.GetComponent<WeaponController>()); // Add the weapon to it's inventory slot weaponIndex++; } public void SpawnPassiveItem(GameObject weapon) { // Checking if the slots are full, and returning if it is if (passiveItemIndex >= inventory.passiveItemSlots.Count - 1) // Must be -1 because a list starts from 0 { Debug.LogError("Inventory slots already full"); return; } //Spawn the starting passive item GameObject spawnedPassiveItem = Instantiate(weapon, transform.position, Quaternion.identity); spawnedPassiveItem.transform.SetParent(transform); // Set the weapon to be a child of the player inventory.AddPassiveItem(passiveItemIndex, spawnedPassiveItem.GetComponent<PassiveItem>()); // Add the weapon to it's inventory slot passiveItemIndex++; } }
March 8, 2025 at 9:06 pm #17447::It looks like you’re working on a Unity game, and your provided code includes a
GameManager
andPlayerStats
classes that manage game states and player statistics, respectively. However, I noticed a few potential issues and areas for improvement in your code. Here are some suggestions:-
Use of
<
and>
: It seems like the angle brackets in your code have been encoded as<
and>
. This typically occurs when code is copied from an HTML context. You should replace all instances of<
with “.For example:
public List levelRanges;
-
Game Over Logic: In the
Kill
method ofPlayerStats
, you check if the game is already over before callingGameManager.instance.GameOver()
. This is a good practice to avoid multiple calls to trigger a game over state. Just ensure thatGameManager.isGameOver
is consistently managed throughout your game. -
Health Recovery: The
Recover
method inPlayerStats
could potentially lead to health exceeding the maximum ifCurrentRecovery
is significantly high. Consider adding a clamp to ensure it stays within bounds:CurrentHealth = Mathf.Clamp(CurrentHealth, 0, characterData.MaxHealth);
-
Update Method Calls: In the
Update
method of both classes, you’re calling methods likeRecover()
andCheckForPauseAndResume()
. Ensure that these methods are lightweight and efficient, as they are called every frame. -
Debugging: You have placed debug logs in several areas. Make sure to remove or comment them out in your production build to avoid cluttering the console.
-
Using
Awake
vsStart
: In Unity,Awake
is called beforeStart
. If you have dependencies that need to be initialized inAwake
, but rely on other components that are initialized inStart
, you might run into null reference issues. Be cautious about the order in which you initialize your variables. -
Singleton Pattern: Your singleton pattern implementation is good, but consider making the
GameManager
instance accessible only through a property to ensure that it remains encapsulated. -
State Management: You might want to create methods for entering and exiting states to encapsulate the behavior related to each state. For example, you could have
EnterGameplay()
,EnterPaused()
, andEnterGameOver()
methods that setup the necessary conditions for each state. -
Refactor Repeated Code: If you find yourself repeating code for updating UI text, consider creating a method that takes in the relevant parameters and updates the UI, reducing redundancy.
Here’s a simple example of a method for updating UI text:
private void UpdateStatDisplay(Text display, string label, float value) { if (display != null) { display.text = $"{label}: {value}"; } }
You could call this method in your properties instead of duplicating the text assignment logic.
By addressing these points, your code will be cleaner and more efficient. If you have specific issues or errors you are encountering while running this code, please let me know, and I can assist you further!
March 8, 2025 at 9:10 pm #17448March 8, 2025 at 9:10 pm #17449::I apologize, but there is no specific query or problem description provided in your message. The reference information shows code for various scripts like CharacterScriptableObject, GameManager, ExperienceGem, Pickup, HealthPotion, CharacterSelector, and SceneController, but without a specific question about these scripts, I cannot provide a targeted response.
If you have a specific issue or question about the code, please provide more details about the problem you’re experiencing.
March 9, 2025 at 1:22 pm #17450::I’m sorry about the AI’s wacky responses. It is reading and sharing content from the later parts of the series.
In your case, it is likely that somewhere in your code, you have a
Time.timeScale = 0;
that causes the game to pause.Try adding the following line (highlighted below) to the
Start()
function inPlayerStats
to see if it fixes the issue:void Start() { Time.timeScale = 1; //Initialize the experience cap as the first experience cap increase experienceCap = levelRanges[0].experienceCapIncrease; // Set the current stats display GameManager.instance.currentHealthDisplay.text = "Health: " + CurrentHealth; GameManager.instance.currentRecoveryDisplay.text = "Recovery: " + CurrentRecovery; GameManager.instance.currentMoveSpeedDisplay.text = "Move Speed: " + CurrentMoveSpeed; GameManager.instance.currentMightDisplay.text = "Might: " + CurrentMight; GameManager.instance.currentProjectileSpeedDisplay.text = "Project Speed: " + CurrentProjectileSpeed; GameManager.instance.currentMagnetDisplay.text = "Magnet: " + CurrentMagnet; GameManager.instance.AssignChosenCharacterUI(characterData); }
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: