I have a Unity Project which should create a HoloLens Application. Now i want to test some of my Code in Unity with NUnit. I created some PlayMode tests
public class Test
{
private GameObject empty;
[SetUp]
public void BeforEveryTest()
{
empty = new GameObject();
empty.AddComponent<MainController>();
}
// A Test behaves as an ordinary method
[Test]
public void MainControllerGetInstance()
{
Assert.IsNotNull(MainController.Instance);
}
}
This is the Singleton I want to test
public class MainController : Singleton<MainController>
{
[SerializeField]
private GameObject SomePref;
private void Start()
{
SomePrefab.SetActive(true);
}
}
I get an error that SomePref is not set to an instance of an object, but I can't set it up because its a private seralizedfield.
Now what is good practice to erase that error. I know, I could use Resource.Load in the Start Methode from MainController, but is this the good way?
Related
I am trying to use GameObject.Find within a prefab to reference an object that exists in the scene. The name of the object is exactly the same as the actual object.
LoseLives loseLives;
GameObject loseLivesing;
private void Awake()
{
loseLivesing = GameObject.Find("MasterManager");
}
private void Start()
{
loseLives = loseLivesing.GetComponent<LoseLives>();
target = Waypoints.waypoints[0];
}
loseLives.LoseLife();
Null Reference
I get a null reference when "loseLives.LoseLife();" runs.
Any help with solving the no reference problem would be greatly appreciated!
If you think there is a better way to create the connection between a script on a prefab and a script on a in-scene gameObject could you please explain it or point me to a tutorial, because in all my research I did not have any luck.
Thank you!
It seems like your LoseLives is a singular, constant object.
First Method
Simply making use of the inspector by exposing the fields.
public class YourScript : MonoBehaviour {
[SerializeField]
private LoseLives loseLives;
// ..
private void Start() {
loseLives.LoseLife();
}
// ..
}
It comes with the problem of needing to constantly drag your constant object into the inspector whenever you need it.
For a Prefab, it works if the target object is part of the Prefab, or the Prefab is generated in the same scene as the targeted object.
Second Method
Using singletons.
LoseLives.cs
public class LoseLives : MonoBehaviour {
public static LoseLives Instance {
get => Instance;
}
private static LoseLives instance;
private void Start() {
instance = this;
}
public void LoseLife() {
// ...
}
}
YourScript.cs
public class YourScript : MonoBehaviour {
// ..
private void Start() {
LoseLives.Instance.LoseLife();
}
// ..
}
This works if you have a global, singular instance of LoseLives object.
Even though it might not be the best approach, I found a workaround for my issue.
I am using a static variable that resides in the other script (CurrencyManager), calling it from the LoseLives script.
Instead of:
loseLives.LoseLife();
I do:
CurrencyManager.playerHealth -= 1;
Where CurrencyMananger is the other script and playerHealth is a static variable that is in the CurrencyManager script. This works because a static variable does not require the objects to be referenced in the inspector.
From now on, when I have a problem where I want to reference a gameObject within a script that is on a prefab, I will consider using static variables in my solution.
I'm trying to make an audio player in Unity.
I first created a ResourceManager, that has a
AudioClip[] array.
public class ResourceManager : MonoBehaviour
{
public AudioSource audioSrc;
public AudioClip[] clips;
private int trackNum = 0;
public void Awake()
{
audioSrc = GetComponent<AudioSource>();
audioSrc.Stop();
...omitted...
public void LoadClip()
{
audioSrc.clip = clips[trackNum];
}
}
So that they appear in the Clips drag-and-drop box.
However, I want to make the AudioClip array static in ResourceManager static, so other scripts (e.g. PlayPause.cs can access clips statically (via function calls).
But the problem is once I make clips static, the drag-and-drop for disappears.
Is there a way to fix that? Or are there some better design patterns? Thanks.
You can e.g. simply do
public class ResourceManager : MonoBehaviour
{
...
// This is the one in the Inspector
// Usually I keep the Inspector private and only provide public access
// where needed via properties
[SerializeField] private AudioClip[] clips;
// This will be set in Awake to the ones from the Inspector
// readonly for others, only this class can assign it
public static AudioClip[] Clips { get; private set; }
public void Awake()
{
Clips = clips;
...
}
}
The alternative suggested is make the ResourceManager a so called singleton like e.g.
public class ResourceManager : MonoBehaviour
{
// Here you store your own instance reference
// and provide public readonly access
public static ResourceManager Instance { get; private set; }
[SerializeField] private AudioClip[] clips;
public AudioClip[] Clips => clips;
...
public void Awake()
{
// Make sure only one instance exists at a time
if(Instance && Instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
// optional: Don't destroy this instance when the scene is switched
// Careful: Make sure this applies also to the AudioSource instance!
// For now I assume it is either attached to this object or a child
// if not simply do the same DontDestroyOnLoad on it as well
DontDestroyOnLoad (this.gameObject);
...
}
public void LoadClip()
{
audioSrc.clip = clips[trackNum];
}
}
And then access everywhere ReaourcesManager.Instance.Clips
Or a built-in alternative to the singleton is using FindObjectOfType so any other script in the Scene can actually simply access
FindObjectOfType<ResourcesManager>().clips
without you having to change anything at all ;)
Except as said I would make it
[SerializeField] private AudioClip[] clips;
public IReadonlyList<AudioClip> Clips => clips;
depending a bit of course what exactly you want to do with the clips but this way the array can not be altered by any other script
public class GameControl : NetworkBehaviour {
public GameObject localPlayer;
[TargetRpc]
public void TargetGetLocalPlayer(NetworkConnection conn)
{
localPlayer = GameObject.Find("Local");
}
public override void OnStartServer()
{
base.OnStartServer();
TargetGetLocalPlayer(connectionToClient);
}
}
i have a script attached to a server object which should be able to grab the local player GameObject (which i denoted by changing it's name to 'Local' once it's spawned in another script) from the client but when i try to call TargetGetLocalPlayer , i get the following error :
Exception in OnStartServer:Object reference not set to an instance of an object at
UnityEngine.Networking.NetworkBehaviour.SendTargetRPCInternal
(UnityEngine.Networking.NetworkConnection conn, UnityEngine.Networking.NetworkWriter writer,
System.Int32 channelId, System.String rpcName) [0x0002e]
i am totally new to networking in unity and i feel like i should have gone with photon instead of unet , it seems like no one is interested in unet anymore and the docs suck at explaining anything and i will be very grateful if anyone could answer me , thanks in advance
I think a better solution would be to attach a script to each player. and make it so that when a "new" player joins it runs a method in your GameControl to add the player to a player list. like this:
//this is on your gameControl.
public List<Player> players;
public void AddPlayer(Player player)
{
players.Add(player);
}
this is working if you have your GameControl as a singleton. if you do not know how to do that check the last piece of code.
//this is on your Player script called player(if you have another name change all
//Player scripts in here to that name
public void Start()
{
GameControl.AddPlayer(this);
}
Or
Instead of making the players list a List you can make it a dictionary and make a key for each player who joins to make it more accesible.
How to make a script a singleton and why.
why:
if you have a manager class/script you always want there to only be ONE instance of it so you can call its methods easily and without problems.
How:
Basically you make it so that Only THIS script can change values and variables in the manager, and other scripts can get/call methods and functions. this makes it easily accesible and you will have less problems.
private static GameControl _GameControl;
private Player player;
public static GameControl gameControl
{
get
{
if(_GameControl == null)
{
Debug.LogError("Game Control is null");
}
return _GameControl;
}
}
void Awake()
{
_GameControl = this;
player = GameObject.Find("Player").GetComponent<Player>();
}
Well i see what you mean, well create a method that can be run by any script like a singleton. then you pass in the gameobject that you want to add like this:
public class GameManager
{
public GameObject _player;
//this is a singleton.
private static GameManager _gm;
public static GameManager gameManager
{
get
{
if(_gm == null)
{
Debug.LogError("Game manager is null");
}
return _gm;
}
}
void awake()
{
_gm = this;
}
void GetPlayer(GameObject player)
{
_player = player;
}
void AddPlayer(GameObject player)
{
//add it to whatever you want to.
}
}
call the method this way:
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
GameManager.gameManager.GetPlayer(this.gameObject);
}
}
I have an array of prefabs and I want to be able to Instantiate randomly picked prefabs thru Zenject Factory and perform their bindings in their sub-containers.
What I want to do is the same as in this code sample from Zenject documentation, but for randomly selected prefabs.
https://github.com/modesttree/Zenject/blob/master/Documentation/SubContainers.md#using-game-object-contexts-no-monobehaviours
using UnityEngine;
using Zenject;
public class GameInstaller : MonoInstaller
{
[SerializeField]
GameObject ShipPrefab;
public override void InstallBindings()
{
Container.BindInterfacesTo<GameRunner>().AsSingle();
Container.BindFactory<float, ShipFacade, ShipFacade.Factory>()
.FromSubContainerResolve().ByNewPrefabInstaller<ShipInstaller>(ShipPrefab);
}
}
I was able to partially make it work with
[SerializeField] private GameObject[] ships;
...
Container.BindFactory<float, ShipFacade, ShipFacade.Factory>()
.FromSubContainerResolve().ByNewGameObjectMethod(SpawnShip);
...
private void SpawnShip(DiContainer container, float speed)
{
container.Bind<ShipFacade>().AsSingle();
container.Bind<Transform>().FromComponentOnRoot();
var shipPrefab = ships[Random.Range(0, ships.Length)];
var ship = container.InstantiatePrefab(shipPrefab);
container.Bind<ShipHealthHandler>().FromNewComponentOn(ship).WhenInjectedInto<ShipFacade>();
container.BindInstance(speed).WhenInjectedInto<ShipInputHandler>();
}
But it's awkward and in this case I guess I'm not using an advantage of sub-container. And also prefabs spawns in an empty GameObject.
What I want to achieve is to be able to use ShipInstaller for sub-container binding.
You're right, there wasn't really a very elegant way to choose the sub-container prefab dynamically.
I took some time to make this better today with this commit. If you use the latest version of Extenject then you can now do things like this:
public class QuxInstaller : Installer {
float _speed;
public QuxInstaller(float speed) {
_speed = speed;
}
public override void InstallBindings() {
Container.BindInstance(_speed);
Container.Bind<QuxFacade>().AsSingle();
}
}
public class CubeInstaller : MonoInstaller
{
public List<GameObject> QuxPrefabs;
public override void InstallBindings()
{
Container.BindFactory<float, QuxFacade, QuxFacade.Factory>()
.FromSubContainerResolve().ByNewPrefabInstaller<QuxInstaller>(ChooseQuxPrefab);
}
UnityEngine.Object ChooseQuxPrefab(InjectContext _) {
return QuxPrefabs[Random.Range(0, QuxPrefabs.Count)];
}
}
I am working in Unity 3d and I made a player script. Now I want to have different kinds of players but they all have the same movement behaviour. Since my object in inheriting from Monobehaviour I can't inherit from something else. How would I solve this, because I don't want to have to redo every player later on when I change something about the movement. I can solve it with namespaces but is that a good solution?
You have basically two options:
Create an abstract Player class, that inherits from MonoBehaviour, implementing only the movement. Then let the concrete player classes (e.g. Wizard or Warrior) inherit from it and handle the specific locig in those
Create a Player class and use the "Strategy-" (and maybe "Factory-") "Pattern", to create different types of players (you may also read up on "composition over inheritance")
An implementation of the first approach might look like this:
public abstract class Player : MonoBehaviour
{
public void Move() { /* Movement logic here */ }
public abstract void Attack(MonoBehaviour target);
}
public class Wizard : Player
{
public void Attack(MonoBehaviour target) { /* Attack logic for a wizard here */ }
}
public class Warrior : Player
{
public void Attack(MonoBehaviour target) { /* Attack logic for a warrior here */ }
}
// ---
// How to create players
var wizard = new Wizard();
var warrior = new Warrior();
And for the second approach:
public interface IAttack
{
public void Attack(MonoBehaviour target);
}
public class WizardAttack : IAttack
{
public void Attack(MonoBehaviour target) { /* Wizard attack logic here*/ }
}
public class WarriorAttack : IAttack
{
public void Attack(MonoBehaviour target) { /* Warrior attack logic here*/ }
}
public class Player : MonoBehaviour
{
private IAttack attack;
public Player(IAttack attack)
{
this.attack = attack;
}
public void Move() { /* Movement logic here */ }
public void Attack(MonoBehaviour target)
{
this.attack.Attack(target);
}
}
// ---
// How to create players
var warrior = new Player(new WarriorAttack());
var wizard = new Player(new WizardAttack());
As you can see, the second approach gives you a lot more flexibility, because you're of course not limited to having only an "attack strategy", but can create as many different ones as you like and - more importantly - combine them in any way imaginable. You could even "outsource" the movement logic into its own strategy and change it on the fly. For example, when the player picked up a power up. With inheritance, you would really struggle to have a Priest, which might combine traits of a Warrior and Wizard.
This also fits in nicely with how Unity was designed; that is, combining different components (e.g. Rigidbodies and Renderers) for increased functionality.
As for solving it with namespaces: How? Namespaces are nothing more as a way to organize code and avoid naming collisions. They don't solve the problem of having duplicate code.
solution for you is to use aggregation instead of inheritance. Unity very good support Entity Component System paradigm. To not duplicate check this thread
http://answers.unity3d.com/questions/669643/entity-component-system.html.
There is a ready framework to work with ECS for unity, you can check out to get a better idea of approach:
https://github.com/andoowhy/EgoCS
https://github.com/sschmid/Entitas-CSharp
I haven't use any of those, but I hope it helps to get into it. I would really recommend to go with it, regardless of the way you will implement it.
Just start thinking in a way of components, which mean if you have a several types of players, only difference is which components they construct of. Then you can have a movement component and use it on every player ;)
You can achieve this by simple and easy way by making a separate MoveScript, which will only have the move behaviour that is same for all players. Other variable behaviours you can write separate script (WizardScript and WarriorScript). So there will be two scripts on all players one MoveScript and one script (WizardScript and WarriorScript) related to their specific behaviour.
Sounds like a good time to use the strategy design pattern.
But first, let's generalize the players.
public abstract class Player : Monobehaviour
{
protected PlayerMovementStrategy moveStrategy;
protected void Start()
{
moveStrategy = new SimplePlayerMovementStrategy(this);
}
protected void Update()
{
moveStrategy.UpdateMethod();
}
protected void MoveTo(Vector3 location)
{
moveStrategy.MoveTo(location);
}
}
Obviously, from this we can create different types of players:
public class Archer : Player
{
//...
}
And how will the PlayerMovementStrategy class look like?
public abstract class PlayerMovementStrategy
{
protected Player _player;
public PlayerMovementStrategy(Player player_)
{
_player = player_;
}
public abstract void UpdateMethod();
public abstract void MoveTo(Vector3 location);
}
For an example:
public class SimplePlayerMovementStrategy : PlayerMovementStrategy
{
protected bool _move;
protected Vector3 _destination;
public SimplePlayerMovementStrategy(Player player_) : base(player_)
{
_move = false;
_destination = Vector3.Zero;
}
public override void UpdateMethod()
{
if (_move)
{
//_player.transform.position..
}
if (destinationReached) _move = false;
}
public override void MoveTo(Vector3 location)
{
_destination = location;
_move = true;
}
}
The advantage here is that you can write new movement strategy classes (that should confirm to PlayerMovementStrategy) and just assign them to your player class, whilst your MoveTo() method in your player class is completely controlled by whichever derived movement strategy you assigned it.