Multiple characters in videogame using Unity - c#

I am developing a videogame using Unity and I want the user to be able to choose from a group of characters who have different attributes and weapons.
Do I have to create a scene for every character for each level or there is a dynamic way of doing it?

Your scripts :
GameManager :
public class GameManager : MonoBehavior
{
public static GameObject character; // this field is to remember the selection. Since it is 'static', it will keep value in between scenes.
}
LevelManager :
public class LevelManager : MonoBehavior
{
public void Start()
{
// read info stored in GameManager
GameManager.character.transform.position = /* your start position */
}
}
In scene 1 (selection):
store charcter selected in GameManager.character
In scene 2 (level):
An empty object with LevelManager script.
Note: Since we use static, I'm actually unsure that you even need the GameManager script to be attached to an empty object, for both scenes.
In the selection scne, just make sure to assign the proper thing to character (instance of Zelda or Megaman character prefab)

Related

Accessing other script method from instantiated object [duplicate]

This question already has answers here:
Store References to Scene Objects in prefabs?
(1 answer)
How can I grab a reference of a game-object in a scene from a prefab
(1 answer)
Closed 2 years ago.
I am trying to set my game up to where there is a player, you touch the screen to throw the object, once that object collides with another object 1 point is added to the score. I added a script to the instantiated object that prints a message, to the console, when a collision is detected. The script also has a reference to another script holding the score variable.
The script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrackEgg : MonoBehaviour
{
public Stats stats;
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "BreakEgg")
{
stats.DepositMoney();
Debug.Log("I am actually working");
}
}
}
The Stats script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Stats : MonoBehaviour
{
[Header("Bank")]
public int bankAmount;
public int depositAmount;
public void DepositMoney()
{
bankAmount += depositAmount;
}
}
I know I have to have the Stats script attached to a game object(I have it attached to an empty game object). The thrown object is a prefab and has the CrackEgg script as a component. I try to drag the Stats game object into the Stats field of the CrackEgg script but it doesn't work. It only works if the Stats game object is also a prefab. The main issue I'm having is that even when I have the Stats game object prefab in the hierarchy, when I test the code, the bankAmount variable does not increase at all. As a summary, I want the instantiated object to detect a collision then run the DepositMoney() method, from the Stats script, but am not able to find a way to make it work.
Quick check: create a CrackEgg on the scene. Try to drag the Stats object into the field. It should work. Now drag this CrackEgg to the Project View in order to create a prefab. The Stats field is empty on the prefab. Why?
A prefab can be instantiated anywhere in your game, so it's possible this reference to a scene object is not valid in case the prefab is instantiated in another scene.
So you must get the reference to the Stats object in runtime.
You can accomplish that in two ways:
METHOD 1
Tag your Stats object with a "Stats" tag.
Then locate it in the scene whenever you start a CrackEgg.
class CrackEgg : MonoBehaviour {
void Start() {
stats = GameObject.FindGameObjectWithTag("Stats").GetComponent<Stats>();
}
}
METHOD 2
Make your Stats class static, and not a MonoBehaviour component.
public class Stats
{
private static int bankAmount;
public static void DepositMoney(int depositAmount)
{
bankAmount += depositAmount;
}
}
Then you don't add it to any object, since there's always a single instance of each parameter on the program. This is an usual pattern for score classes.
To access it, you don't need to store a reference to Stats, just use the class name:
if (collision.gameObject.tag == "BreakEgg")
{
Stats.DepositMoney(depositAmount);
Debug.Log("I am actually working");
}
Since you can't assign values to static classes on the Editor, I've suggested a modification where the caller defines the deposit amount when calling. You might need to think about the safety issues (don't allow values out of a range, etc).
Also, it's usually recommended you use CompareTag instead of ==: https://answers.unity.com/questions/200820/is-comparetag-better-than-gameobjecttag-performanc.html

Unity calling singleton which is from another scene without using dontDestroyOnLoad

I have singleton( which is monobehavior also same question for non-monobehavior) which is created at scene 1 , and it created without dontDestroyOnLoad. im calling this singleton from scene 2 , and getting/using the info inside without any problem.I have read something about ghost GameObjects in this case but couldnt find detailed info.
In Scene 1
using UnityEngine;
public class RefreshAccount : MonoBehaviour
{
public static RefreshAccount refreshAccount;
public string aString = "aaaaaaaa";
void Awake()
{
if (!refreshAccount) refreshAccount = this;
else Destroy(this.gameObject);
// it is not labeled as DontDestroyOnLoad
}
(...)
}
Scene 2
using UnityEngine;
using UnityEngine.SceneManagement;
public class testnewscen : MonoBehaviour
{
private void Start()
{
Debug.Log(RefreshAccount.refreshAccount.aString );
}
}
So will it cause any problem/error in the future of this app ?
Will there be any memory problem or performance problem?
If you use this solution, you cannot run scene 2 without run scene 1 before
If you dont need to set serialize variable / game object / prefabs to your singleton (RefreshAccount) I prefer to use non-monobehaviour singleton instead like
public class RefreshAccount {
private static RefreshAccount instance
public static RefreshAccount Instance {
get {
if(instance == null) {
instance = createInstance();
}
return instance;
}
}
}
If you need to use for read some serialize value (variable, config, gameobject, etc.) without behaviour ( awake, update, fix update )
You can use SerializableObject
SerialzpizeObject is similar static class or prefab but you need to use RESOURCE.LOAD to read it

Cant display array items in the inspector. Unity

I want to make a class array and see all these classes items in the inspector.
I have 2 scripts. 1 -set to prefab and requires MonoBehaviour to be included.
2 - script where I create the array but in the inspector, I see only Element0, Element1...
When I remove MonoBehaviour from the 1st script I'm able to see all the items in the inspector, but that way it doesn't work with the prefab...
1-
[System.Serializable]
public class LevelSetup : MonoBehaviour
{
public TextMeshProUGUI levelName;
public Image levelImage;
public bool locked;
public GameObject Description;
public string Text;
}
2-
public class LevelSpawn : MonoBehaviour
{
public LevelSetup[] levels;
Want to be displayed array with all the "LevelSetup" fields (that are public), but if I leave the MonoBehaviour and it works fine with prefab it displays array with the only Element0, Element1, etc.
Thank You!
When you put a field that inherits from MonoBehaviour the Unity's inspector expects an object that has "Behaviour", so you cannot assign the fields in the inspector because is not interpreted as a regular field.
For example, if you set a Material as a field, and you want to change the color property from the inspector.
public Material mat; //This is actually a class
In the inspector you will only be able to assign a material but you won't be able to access inside the class and change the color.

How to call a public static variable from another class, change its value and then check that its changed from its original class [duplicate]

So im trying to change a variable in another script by touching a cube.
Current setup
1x Player
1x Enemy
Each with their own script Enemy_Stats & Character_Stats
As you can see in this little snippet it's quite a workaround to access the variable from another script.
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
collision.gameObject.GetComponent<Enemy_Stats>().Health =
collision.gameObject.GetComponent<Enemy_Stats>().Health
- gameObject.GetComponent<Character_Stats>().AttackDamage;
if (collision.gameObject.GetComponent<Enemy_Stats>().Health <= 0)
{
Destroy(collision.gameObject);
}
}
}
Iam new to Unity, but isn't there a way to just refer it with something like:
collision.Health?
How to access variables/functions from another Class. The variable or function you want to access or called must be public not private.
public class ScriptA : MonoBehaviour{
public int playerScore = 0;
void Start()
{
}
public void doSomething()
{
}
}
Access variable playerScore in ScriptA from ScriptB. First, find the GameObject that the script or component is attached to with the GameObject.Find function then use the GetComponent function to retrieve that script or component that is attached to it.
public class ScriptB : MonoBehaviour{
ScriptA scriptInstance = null;
void Start()
{
GameObject tempObj = GameObject.Find("NameOfGameObjectScriptAIsAttachedTo");
scriptInstance = tempObj.GetComponent<ScriptA>();
//Access playerScore variable from ScriptA
scriptInstance.playerScore = 5;
//Call doSomething() function from ScriptA
scriptInstance.doSomething();
}
}
No since Health is not part of the collision object, but Enemy_Stats. You can cache a Component (that's what Enemy_Stats is) if you use it multiple times to save you some typing (and some performance, but that is rather marginal for this example). Also you can cache "known" components like in this case Player_Stats. You can do this e.g. in Start or with a public variable and the inspector.
What you should probably do though is to make the enemy be responsible for his life and not the player, so move the Destroy-part to Enemy_Stats (into the Health property to be exact).
The first thing to make this shorter (and eventually faster) would be to store this: gameObject.GetComponent<Character_Stats>() on Start() in a private variable (you should avoid calling GetComponent on a frequent basis if you can avoid it).
For the Health variable, a way of avoiding GetComponent calls could be caching: you create a Dictionary<GameObject, Enemy_Stats> and read from that as soon as this gameobject collided once
At the very beginning i mean in Awake() method you can find a game-object with tag
and get it's Heath after that in Collision() method you should just decrease the health but, here the condition is there is only one enemy and only one player.

How do I pass variable from one script to another C# Unity 2D?

For example I have a variable (public static float currentLife) in script "HealthBarGUI1" and I want to use this variable in another script.
How do I pass variable from one script to another C# Unity 2D?
You could do something like this, because currentLife is more related to the player than to the gui:
class Player {
private int currentLife = 100;
public int CurrentLife {
get { return currentLife; }
set { currentLife = value; }
}
}
And your HealthBar could access the currentLife in two ways.
1) Use a public variable from type GameObject where you just drag'n'drop your Player from the Hierarchy into the new field on your script component in the inspector.
class HealthBarGUI1 {
public GameObject player;
private Player playerScript;
void Start() {
playerScript = (Player)player.GetComponent(typeof(Player));
Debug.Log(playerscript.CurrentLife);
}
}
2) The automatic way is achieved through the use of find. It's a little slower but if not used too often, it's okay.
class HealthBarGUI1 {
private Player player;
void Start() {
player = (Player)GameObject.Find("NameOfYourPlayerObject").GetComponent(typeof(Player));
Debug.Log(player.CurrentLife);
}
}
I wouldn't make the currentLife variable of your player or any other creature static. That would mean, that all instances of such an object share the same currentLife. But I guess they all have their own life value, right?
In object orientation most variables should be private, for security and simplicity reasons. They can then be made accessible trough the use of getter and setter methods.
What I meant by the top sentence, is that you also would like to group things in oop in a very natural way. The player has a life value? Write into the player class! Afterwards you can make the value accessible for other objects.
Sources:
https://www.youtube.com/watch?v=46ZjAwBF2T8
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.GetComponent.html
You can just access it with:
HealthBarGUI1.currentLife
I'm assuming that HealthBarGUI1 is the name of your MonoBehaviour script.
If your variable is not static and the 2 scripts are located on the same GameObject you can do something like this:
gameObject.GetComponent<HealthBarGUI1>().varname;
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;
}
TRY THIS!
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;

Categories