Making a global function in Unity C# - c#

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(){
...
}

Related

How to access a bool from one script to another so I can load in multiple scenes?

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;

Maintaining DontDestroyOnLoad method after object becomes a child to another object

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");

How can i play a death animation on Unity?

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.

Unity - Clicking on one object activates others

I am trying to create a Minesweeper + clicker/idle game for practice. For now, I can't get the clicking to work properly. I spawned in all objects through code meaning they are all the same prefabs but at different locations. When I click them the code activates for all of them and all of the tiles change to being open. I am not sure if I'm using the wrong click function here, as I know there is also an OnMouseDown() function instead of Input.GetMouseButtonDown(0) but the only one where the code activates is in the second one.
public class TileClick : MonoBehaviour {
public GameObject openTile;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0)) {
Instantiate(openTile, transform.position, Quaternion.identity);
Object.Destroy(this.gameObject);
}
}
}
That's my clicking detection. While it does detect clicks, as I said before, it detects them for ALL tiles and activates them all. I only want it to activate on one of them. I've seen RayCasting stuff but I really need more explanation on how that thing works (if that's the solution).
If the TileClick script component is attached to your prefab, then for every tile you instantiate, you have a corresponding TileClick component attached.
When you click, the input is detected by all of these blocks simultaneously, and each of them calls Instantiate but the transform.position is the one corresponding to the tile that makes the call. This is why it seems like all the tiles open up simultaneously, because you are, in fact, instantiating an "open" tile on each of them every time you click.
You should keep all your user input code in a separate MonoBehaviour, and attach that to a single empty GameObject in your scene. For detecting the hit, you should attach a 2DCollider component to your tile prefab (you can decide the type according to the shape of your tiles), and then just use a simple RayCast in your user input code to instantiate an "open" tile at the position where the hit occurs:
void Update () {
if (Input.GetMouseButtonDown(0)) {
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition),
Vector2.zero);
if(hit.collider != null)
{
Instantiate(openTile,
hit.collider.gameObject.transform.position,
Quaternion.identity);
}
}
I highly recommend understanding how RayCast works since it is a very useful tool. Here's a good place to start: https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html

Respawn Player on Scene Change

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.

Categories

Resources