I'm trying to switch a scene over the network and i want each player to locally load the scene Async so that everyone can get a loading screen. I'm struggling with Command and RPC calls. After the scene changes i would like to respawn a new player and associate it with the client.
public void changeLevel(string name)
{
CmdChangeLevel(name);
//nm.ServerChangeScene(name); -> This doesnt change the scene Async
}
void changeScene(string name)
{
SceneManager.LoadScene(name);
//Stuff to re-Instantiate the player
}
[Command]
void CmdChangeLevel(string name)
{
SceneManager.LoadScene(name);
RpcChangeLevel(name);
}
[ClientRpc]
void RpcChangeLevel(string name)
{
changeScene(name);
}
Everything i tried resulted in a scene switch but no players instantiated, like (nm = networkManager) nm.OnServerAddPlayer() and instantiate it then spawn it through the server. Help would be much appreciated, thanks in advance
Perhaps what you need is a static gamemanager with DontDestroyOnLoad (DDOL)?
Basically what you do is:
1) Create a scene and put it first in your game build order (so game first load in to it)
2) Create an empty GameObject with a GameManager script. In Start() put the DontDestroyOnLoad-method.
3) In your script, load your "first" scene (main menu or splash screen or whatever)
This will make the Object you put your DDOL-script to stay even between scene changes, so you could handle the loading screens and player spawns etc in that gameobject.
Related
I'm a noob at unity and I'm trying to make a game where you come to an area and when you walk over an invincible box I have placed another scene loads in. And it will keep on going like that. In every scene you load in there will be another box to load the next scene in. But it will also unload scenes that are not directly behind you. So i you where to walk forwards, you would load 2 scenes infron of you and have 1 scenes loaded behind you.
I have done this since my game lags because of the amount of assets I have in the game and the graphics on them.
If it helps I'm using HDRP to make this game and all scenes are in front of each other so there is no bend to the map.
What I have come up with so far is using the box and adding a trigger on it to activate a bool that will load the next scene in a different script since that script has already a part where it loads a scene.
Any ideas on how to solve it or how to get the bool component from one script to another since it is triggered by a box collider. So when the box collider gets triggered you set the bool to true and the next scene loads in.
you can use a Singleton pattern to send and keep data between scene.
Here is one template has you didn't put code.
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public bool myBool; //here you can declare all the things you want
void Awake()
{
if (instance != null && instance != this)
Destroy(this.gameObject);
else
{
instance = this;
DontDestroyOnLoad(gameObject); //allow the script to not be destroyed when switching scene
}
}
}
Then, if you want to call this class from another class you just have to do this :
GameManager.Instance.myBool;
in the game I am trying to make there is a level with moving platforms that make the player object a child for the duration of the collision.
private void OnCollisionEnter2D(Collision2D collision)
{
collision.transform.SetParent(transform);
}
private void OnCollisionExit2D(Collision2D collision)
{
collision.transform.SetParent(null);
}
Player does have a DontDestroyOnLoad method so he can move between the levels freely. However that method disappears whenever i come into contact with one of the moving platforms so the game crashes while going to the next level because the camera is using the player object to follow him and without player is missing a reference. I am pretty sure that the cause is that it becomes a child object of the platform and the platform itself does not use that method. Is there a way to keep the DontDestroyOnLoad method no matter the circumstances fn the player object?
The scene cannot be loaded automatically. It is controlled by you, so you can unlink the player's parent before switching to the next scene.
player.transform.SetParent(null);
DontDestroyOnLoad(player.gameObject);
SceneManager.LoadScene("next scene");
I want to play a death animation to my enemy. Basically, he has an idle animation and I would like to play the death animation when he dies, and after one or two seconds, the GameObject gets deleted. I'm new to coding, so a basic solution would be better :) .
Here's my coding:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealthManager : MonoBehaviour {
public int enemyHealth;
public GameObject deathEffect;
public int pointsOnDeath;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
if (enemyHealth <= 0)
{
Instantiate (deathEffect, transform.position, transform.rotation);
ScoreManager.AddPoints (pointsOnDeath);
Destroy (gameObject);
}
}
public void giveDamage(int damageToGive)
{
enemyHealth -= damageToGive;
}
}
You can add a function called PlayAnimationAndDestroy() as a void and inside it put the Destroy (this.gameObject, 2f) and then animator.Play("deathAnim");
In the Destroy the number after the comma is the time Unity will wait to destroy the object so you need to check the duration of your animation in the timeline and put that duration in the Destroy ().
Another way to do this is to press the record button inside the animation at the end of it and change a public variable. In the script you will put a simple if() and If that variable has changed you destroy the object.
The third way is to use animation events (https://docs.unity3d.com/Manual/script-AnimationWindowEvent.html) but for your usage the first two options are easier :)
Welcome to Unity! Using an AnimatorController in your project and corresponding Animator components on your GameObject that you want to die is going to be your friend here as well.
You can check out a great tutorial by Unity about Animator Controllers here, but basically, it's a state machine. Based on what state your object is in, you can control which game object animations are active and you can set triggers in your game logic to trigger a transition to another state.
This is great for cases like triggering death animations.
In your case, you'd want one state for idle, and one state for death. You'd have a connection between your death and idle state.
You'd set a trigger named die. You'd make it so that the state idle only moves to state death when your die trigger is triggered in the game logic.
So, step 1:
You'd create a new AnimatorController Scriptable Object from the Editor, and then edit it in the Animator window. Make your desired state machine with the desired animations and that ScriptableObject will be saved in a project folder.
Step 2: Add an Animator component on your GameObject that you want to affect. It has an AnimatorController component - add your newly created controller here.
Step 3: In your game logic script, you'd have a reference to that Animator component:
...
public int enemyHealth;
public GameObject deathEffect;
public int pointsOnDeath;
public Animator animComponent;
...
Then when you hit your condition, you'd do something like this:
if (enemyHealth < 0){
animComponent.SetTrigger("die");
}
Then your AnimatorController will move from your previous state to death, and your animation that you set will play.
Best of luck.
This is the current script that I have. I have a ball that is player, and I want a collision with my game object tagged as "pit" to end the game. When the game ends I want my game over canvas to pop up. The current script detects the hit when the player rolls over the pit, however, currently, nothing else happens. Both my player and pit have rigidbodies and colliders attached to them. I would really appreciate any help with how to get my code to work properly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public GameObject GameManager;
private void OnTriggerEnter(Collider other)
{
Debug.Log("hit detected")
if(other.gameObject.tag == "pit")
{
GameManager.GetComponent<Game_Manager>().EndGame();
}
}
}
My EndGame code is in my GameManager script. The is the part of that script that deals with ending the game.
public void EndGame ()
{
player.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezePosition;
hasGameStarted = true;
inMenuUI.gameObject.SetActive(false);
inGameUI.gameObject.SetActive(false);
gameOverUI.gameObject.SetActive(true);
}
If I'm correct in interpreting your question, your script successfully detects player death already. If you want a game over screen you have a couple of options:
You can create a UI canvas with a panel on it that obscures the whole screen and put the words Game Over.
Or, probably the better option is to create an entirely new Unity scene and make the Game Over canvas there. When you want to trigger the game over screen you simply use:
Scene manager.LoadScene("Scene name");
You have to add "using UnityEngine.SceneManagement;" at the top of your script. Also note you have to add your Game Over scene to the list of scenes in you game. I believe this can be done by navigating to File>Build settings>scenes and then pressing add open scenes assuming the game over scene is open.
Could someone please point me to a tutorial that can make a global "back button" function in unity?
Currently I am able to override it via "Update" function with this code
if (Input.GetKeyDown(KeyCode.Escape))
{
//Do something you need
Debug.Log("Back button is pressed");
}
The drawback, however, I need to attach this function in one active "Gameobject" in every scene.
Is there perhaps any method to make this function globally and therefore this "Update" function always listening in every scene?
You can attach this script to a gameObject in your initial scene.
void Awake(){
DontDestroyOnLoad(this.gameObject);
}
void Update(){
if (Input.GetKeyDown(KeyCode.Escape))
{
//Do something you need
Debug.Log("Back button is pressed");
}
}
DontDestroyOnLoad causes the game object to persist after leaving the scene.
In order to change the scene, you can call SceneManager.LoadScene with one of these options:
Single Closes all current loaded scenes and loads a scene.
Additive Adds the scene to the current loaded scenes.
As in
SceneManager.LoadScene("OtherSceneName", LoadSceneMode.Single);
One design pattern is to have an initial scene (named e.g. persistantScene or bootstrapper) in which persistent objects such as the first script above exist. it navigates to the next scene with Single option, keeping persistent (DontDestroyOnLoad) objects through the next scene while discarding other objects which belong only to the previous scene.
Moreover, you can make it a singleton if you need easy access:
public static MyMonobehaviour Instance;
void Awake(){
Instance = this;
DontDestroyOnLoad(this.gameObject);
}
void Update(){
...
}