So I've been trying to make a game but when I press the button the scene reloads itself. What I want to do is make it so that whenever a scene is loaded it gets the build index of the active scene.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelSwitch : MonoBehaviour
{
int CurrentSceneBuildIndex;
bool sceneLoaded;
void Update()
{
if (sceneLoaded == true )
{
CurrentSceneBuildIndex = SceneManager.GetActiveScene().buildIndex;
}
}
public void NextLevel()
{
SceneManager.LoadScene(CurrentSceneBuildIndex + 3 );
sceneLoaded = true;
}
public void LevelSelect()
{
SceneManager.LoadScene("LevelSelect");
}
}
The issue:
Ok, so the issue with your solution is that when a new scene is loaded in Unity, GameObjects and their attached scripts are not kept between scenes. In your scripts function NextLevel() you are loading the scene and then setting the sceneLoaded boolean to true however this is after the new scene is loaded and we know that GameObjects and their attached scripts do not transfer between scenes which means this boolean value does not transfer to the next scene either. This is unless a GameObject is marked with dontdestroyonload.
So what can we do to fix this?
To get the current build index of the scene when it is loaded you can attach a script to a GameObject in the scene you want to get the index of which uses SceneManager.sceneLoaded to detect when the scene is finished loading and then get the index.
For example:
using UnityEngine;
using UnityEngine.SceneManagement;
public class ExampleCode : MonoBehaviour
{
void OnEnable()
{
Debug.Log("OnEnable called");
SceneManager.sceneLoaded += OnSceneLoaded; // This tells the script to call the function "OnSceneLoaded" when the scene manager detects the scene has finished loading with the parameters of the scene object and the mode of how the scene was loaded
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Debug.Log("OnSceneLoaded: " + scene.name + ", Build Index : " + scene.buildIndex.ToString());
Debug.Log("Load Mode : " + mode);
}
// called third
void Start()
{
Debug.Log("Start");
}
// called when the game or scene closes
void OnDisable()
{
Debug.Log("OnDisable");
SceneManager.sceneLoaded -= OnSceneLoaded; // This tells the script to stop calling OnSceneLoaded when the scene manager detects a new scene has been loaded
}
}
Related
I am a beginner in Unity and I am currently making a simple game. I have a problem where the instantiated Button is not destroyed.
The process of the script is to instantiate a button and destroy it upon collision exit. But when I move out of the object, the object stays and it is not destroyed. i don't know if there is something wrong with the Destroy code of line.
Here is the script for the collision:
using UnityEngine;
using UnityEngine.UI;
public class InteractButtonPosition : MonoBehaviour
{
public Button UI;
private Button uiUse;
private Vector3 offset = new Vector3(0, 0.5f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
}
// Update is called once per frame
void Update()
{
//uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
Destroy(uiUse);
}
}
}
The code does exactly what you have written, which is destroying uiUse which is a Button component. If you go and inspect your game object in the scene, you will see, that indeed, the button component has been destroyed.
What you want to do is to destroy the GameObject the button component is attached to, like: Destroy(uiUse.gameObject)
I've done it so far that when my player dies the level is restarted and I've written everything in the script but when I try it and the scene is reloaded everything is somehow extremely dark compared to before, although all settings from the camera etc. are the same and I don't know if I'm doing something wrong or if it's a bug
my Script:
public class GameManager : MonoBehaviour
{
public GameObject enemyPrefab;
// Start is called before the first frame update
void Start()
{
GameObject player = GameObject.Find("Player");
SpawnEnemy();
}
// Update is called once per frame
void Update()
{
RestartGame();
}
void RestartGame()
{
if(GameObject.Find("Player").GetComponent<PlayerMovement>().playerHealth <= 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
You need to bake your lighting inside your scene. Here are instructions on how:
Head to Window > Rendering > Lighting
Press Generate Lighting (Make sure Auto Generate is unselected)
Source
Your code has some trouble. But I'm not going to fix rotation issues. But here your working sample:
public class GameManager : MonoBehaviour {
public GameObject enemyPrefab;
// Start is called before the first frame update
void Start()
{
GameObject player = GameObject.Find("Player");
SpawnEnemy();
}
// Update is called once per frame
void Update()
{
RestartGame();
}
bool navigated = false;
void RestartGame()
{
if (!navigated)
{
if(GameObject.Find("Player").GetComponent<PlayerMovement>().playerHealth <= 0)
{
navigated = true;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
}
}
First of all, please don't get too technical: I've only been studying Unity coding for two months and I'm not a programmer in general! I'm a total beginner! :-)
So, I'm building a game where you control a ball on a treadmill avoiding endless spawning obstacles by shifting left-right and jumping.
I set up a restart function after game over with SceneManager.LoadScene method, it works, but after reloading the jumping function gets compromised: it looks like there's an invisible wall above the player blocking its jumps. And it also looks like it's an "additive" issue: if I die and restart again, the player jumps even less, until it just doesn't jump at all. The other functions seem fine.
Any idea why that happens?
public class PlayerController : MonoBehaviour
//Jump code:
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && isOnLane)
{
Jump();
}
}
void Jump()
{
playerRb.AddForce(Vector3.up * forceMult, ForceMode.Impulse);
isOnLane = false;
}
private void OnCollisionEnter(Collision other)
{
//checks if player is touching the ground
if (other.gameObject.CompareTag("Lane"))
{
isOnLane = true;
}
}
Restart code:
public class GameManager : MonoBehaviour
//restart game by clicking Restart Button
public void RestartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
Thanks!
The problem is that additive scene loading is being used when there is only a single scene. It would be good to break these up into 2 scenes:
A scene for GameManager & the Player object
A scene for the level itself which is being reloaded
This way the GameManager is not being reloaded and the player is not being reloaded. Upon reload you need to "reset" variables for the player back to 0 and move him to a starting position.
RestartGame needs some logic to reset the player and his physics.
public void RestartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
playerController.playerRb.velocity = Vector3.zero;
playerController.playerRb.angularVelocity = Vector3.zero;
playerTransform.position = spawnLocation.tranform.position;
}
You probably want to unload the scene, wait for 1 frame, and then load the scene. This way variables in the scene get reset properly.
public void RestartGame()
{
SceneManager.UnloadScene(scene);
playerController.playerRb.isKinematic = true; // Try setting kinematic between scenes
StartCoroutine(RestartLoad());
}
private IEnumerator RestartLoad()
{
yield return new WaitForEndOfFrame();
// Reset the player here
SceneManager.LoadScene(scene);
playerController.playerRb.isKinematic = false; // Player can use physics again
}
I need help with my project in unity
I want to stop each object by clicking on it.
What I did so far:
all my objects rotate but when I click anywhere they all stop, I need them to stop only if I click on each one.
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EarthScript : MonoBehaviour
{
public bool rotateObject = true;
public GameObject MyCenter;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if(rotateObject == true)
{
rotateObject = false;
}
else
{
rotateObject = true;
}
}
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}
}
Theres two good ways to achieve this. Both ways require you to have a collider attatched to your object.
One is to raycast from the camera, through the cursor, into the scene, to check which object is currently under the cursor.
The second way is using unity's EventSystem. You will need to attach a PhysicsRaycaster on your camera, but then you get callbacks from the event system which simplifies detection (it is handled by Unity so there is less to write)
using UnityEngine;
using UnityEngine.EventSystems;
public class myClass: MonoBehaviour, IPointerClickHandler
{
public GameObject MyCenter;
public void OnPointerClick (PointerEventData e)
{
rotateObject=!rotateObject;
}
void Update()
{
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}
I'm a complete unity novice. I want to make a simple scene where you have three lives and you lose a live if you collide with a cube. This is my script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Lives : MonoBehaviour {
public Transform player;
public static int lives;
public Image live1;
public Image live2;
public Image live3;
// Use this for initialization
void Start () {
lives = 3;
live1.enabled = true;
live2.enabled = true;
live3.enabled = true;
}
void Update () {
DisplayOfHearts();
}
public static void Damage() {
lives -= 1;
}
public void OnCollisionEnter(Collision col) {
if (col.gameObject.tag == "cube") {
Lives.Damage();
}
}
public void DisplayOfHearts() {
if (lives == 2) {
live3.enabled = false;
}
else if (lives == 1) {
live2.enabled = false;
}
else if (lives == 0) {
live1.enabled = false;
}
}
}
What happens is the player can't move through the cube but the amount of lives stays three. Is there something I'm missing?
The problem is you have attached the script to a wrong game object. The script and the collider must be attached to the same game object.
Unity methods inside a MonoBehaviour script (such as OnEnable, Update, FixedUpdate, Awake, Start, OnTriggerEnter, OnCollisionStay, etc..) only work for the game object which the script is attached to.
If you attach the script to another game object don't expect any of those to work. Update only works while that game object is active. OnCollisionEnter only works when a collision occurs on a collider which is attached directly to that game object. (it doesn't even work when a child has the collider instead of the actual game object where script is attached to)