Unity How to have only one source audio? - c#

I have a source audio with this code:
public class Sound : MonoBehaviour {
Static Sound instance;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
So when i change scenes the audio starts playing again. How do i limit it to having only 1?
Edit: How do i fix that? i get this error
1 - Unexpected symbol instance' in class, struct, or interface member declaration 2 - Unexpected symbol ;' in class, struct, or interface member declaration

Option 1:
The Singleton Pattern is likely to be your best choice when it comes to things like this. The intent of the Singleton Pattern is to restrict a class to only one Instance of itself. To read more about the pattern, see the Wiki on it.
It looks like you are already doing this (after your first edit) but the thing you're going to want to change is the capitalization of Static in your code. Static and static are two different things. For your sake, you are looking for static. This should fix your problem/error and allow you to use the Singleton Pattern correctly.
Option 2:
Also, another option if you want to avoid the typical Singleton Pattern would be to search through all GameObjects for any that have you Sound Class/Component on it. Then if there is already on in scene, have the GameObject that is trying to instantiate, destroy itself. You can do this with the following code:
public class Sound : MonoBehaviour
{
void Awake()
{
int numSoundInstances = FindObjectsOfType<Sound>().Length;
if (numSoundInstances > 1)
{
Destroy(this.gameObject);
}
else
{
DontDestroyOnLoad(this.gameObject);
}
}
}
In my opinion, this is way less efficient then using the Singleton Pattern. This is because using FindObjectsOfType forces the code to check every GameObject that is currently in the game. Depending on the amount of GameObjects in the game, this can be very taxing on the system.

Related

Unity - How to properly reference the GameManager in different scenes [duplicate]

This question already has answers here:
How to pass data (and references) between scenes in Unity
(6 answers)
Closed 1 year ago.
I am new to Unity, and starting on creating my first simple projects. For some days already I've been facing a problem and doing a ton of research but I still cant get it to work, here is it:
As far as I know, it is a smart idea to have a "GameManager" object with a "GameManager" script that holds the main functions of the game (please correct me if it isn't best practice). So lets put as an example I have Scene 1 and Scene 2:
Scene1:
-GameManager
-Label
in GameManager there is a function called ChangeLabelText()
Scene2:
-Button
-Scene2Script
in Scene2script there is a function called ButtonOnClick()
and here is my problem: how do I get ButtonOnClick() to call GameManager.ChangeLabelText()?
I always get a reference error.
I've tried to do it within the same Scene and it works perfectly, but not between different scenes.
Any ideas?
Thank you !
Changing scenes in Unity results in Unity destroying each instance. If you want to keep a specific instance/GameObject across several scenes, you may use the DontDestroyOnLoad method. You can pass the GameObject, this specific GameManager instance is attached to, as the parameter. You'd probably want to use a singleton pattern as well for two reasons:
You may not want to have two or more instances of the GameManager class at once. A singleton will prevent that.
You have to find a way to reference this instance nonetheless, since the components in your other class are totally new instances and they have no idea where this GameManager component is.
Example for a singleton pattern:
GameManager.cs
public static GameManager Instance; // A static reference to the GameManager instance
void Awake()
{
if(Instance == null) // If there is no instance already
{
DontDestroyOnLoad(gameObject); // Keep the GameObject, this component is attached to, across different scenes
Instance = this;
} else if(Instance != this) // If there is already an instance and it's not `this` instance
{
Destroy(gameObject); // Destroy the GameObject, this component is attached to
}
}
Example.cs
private GameManager gameManager;
void Start() // Do it in Start(), so Awake() has already been called on all components
{
gameManager = GameManager.Instance; // Assign the `gameManager` variable by using the static reference
}
This is of course only the basic principle. You may apply that in various slightly different variations if you need to.

Leveling in Unity

I'm new at programming and don't know how to make a level counter that can be accessed in every scene.
I created a 3D game. When the player has completed level 1, then I want level 2 to be unlocked using this method:
When the player has completed the level, the value of the level counter changes to 2 and the trigger can access that level counter.
The below is not my code, but is just there to make it more clear:
var level = "level counter which is 2 in this case"
if level == 3
active the trigger (trigger teleports the player to level 3)
else {
floatMessage("You haven't finished level (?) yet.")
}
Looks like you need a persistance system.
There are many ways to save your game state. The easiest and most accessible remains the PlayerPrefs, although it is not optimal for more complex saves.
You could save your amount of levels unlocked (assuming it is incremental) by using this call :
PlayerPrefs.SetInt("levelsUnlocked", 3);
and then you can retrieve the value by using :
levelsUnlocked = PlayerPrefs.GetInt("levelsUnlocked", 0);
Note : The second parameter here is a default value assigned in case you haven't saved before.
Hope it helps. If you're looking to upgrade your save game, consider writing your own save file class and serialize it using JSON. https://docs.unity3d.com/Manual/JSONSerialization.html
The former option remains convenient for a simple project.
There's a few ways to handle this. My recommendation is to store game progress data to a file or database outside the scope of the scene (a good file-based DB solution is SQLite - here's a wiki post I made on how I implemented SQLite in one of my recent projects).
However, if you only wish game progress to persist during the life of the game (it always starts at level 1 when you start it), then Singletons and DontDestroyOnLoad are also a good solution, as #BugFinder mentioned.
public class LevelManager : MonoBehaviour
{
private static LevelManager instance;
public static LevelManager Instance { get => instance; }
int levelNum = 1;
public int LevelNum { get => levelNum; }
private void Awake()
{
//Check to see if an instance of the LevelManager already exists.
if(instance != null && instance != this)
{
Destroy(this.gameObject);
return;
}
instance = this;
DontDestroyOnLoad(this.gameobject);
}
public void LevelComplete()
{
levelNum++;
}
}
As long as the above code is attached to a gameobject in your scene, you can call the following from another gameobject's script. You will notice that I encapsulate levelNum and instance. This is to enforce good practice in my other code. I know that the only script that can modify levelNum or instance is LevelManager, so I won't accidentally break something by changing one of those values in another script accidentally.
Be careful to only put the above script on a gameobject that is allowed to persist between scenes. I like to create an empty "Singletons" gameobject that just holds my singletons.
Example usage when defeating the final boss (if that's a way to beat your levels):
void BossDefeated()
{
LevelManager.Instance.LevelComplete();
}
Example usage when checking to see if a portal can be opened:
int portalNum = 3;
bool CheckPortal()
{
if(LevelManager.Instance.LevelNum >= portalNum)
return true;
return false;
}
Could you just use a Static int if you just want something quick:
public static int level;
Then from anywhere, call the class name i.e. LevelManager.level;
If you want to have it trigger something, you are better off having a callback of some sort, and making it private with a public get, which in turn calls something like a UnityEvent. This answer will probably not be very popular, but it is quick to do :)

Class to control two classes in Unity

I have almost identical classes, PaddleLeft and PaddleRight. I am tired of calling both of those classes when I need something done, I rather them be done all at once. For example, here is what I have to do:
public void pause() {
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
}
And here is what I want to do:
public void pause() {
GameObject.Find("Paddle Objects/paddles").GetComponent<Paddle>().setIsPaused(true);
}
This seems unnecessary, however, in my game, there are times where the same line of code are copied and adjusted to up to ten similar objects.
Question Is there a way to make a super class like in Java for these objects. I have searched the internet and have found info, however I can't seem to understand how to make it work because I can't extend MonoBehavior and a superclass in Unity.
Thanks in advanced!
I have almost identical classes, PaddleLeft and PaddleRight
But your code is totally saying different stuff
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
Maybe you want meant to write the code below?
GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>().setIsPaused(true);
I will assume the second code is what you meant to write.
When you have multiple GameObjects or Scripts with similar actions, you should create a central manager script that will make it easy to communicate with a those GameObjects or classes.
Since both your classes are called PaddleRight and PaddleLeft, You can simply call this class PaddleManager.
Don't forget that, of course, PaddleManager is just a script, it's not a "thing" in Unity. Naturally you will attach PaddleManager to some game object. You might ask "where should I attach it?" In a simple game, you might attach it to your camera, say. (Since you always have a camera, other developers working on your project always know to "look n the camera" for odds and ends like sound-effects, managers like this and so on.) Alternately, say that physically all your paddles are associated with (for example) an object that is the ping pong table. Then, a good place to attach PaddleManager.cs would be on the ping pong table. It doesn't matter where you attach it, so long as it is tidy. Some people like to make simply an empty object (you can refer to an empty object as a "marker"), just make an empty object named say "manager holder", put it at 0,0,0, and you can add scripts like PaddleManager.cs to that object.
Your PaddleManager.cs script:
public class PaddleManager : MonoBehaviour
{
private PaddleRight rightPaddle = null;
private PaddleLeft leftPaddle = null;
//Initialize variables
void Start()
{
//Get reference/Cache
rightPaddle = GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>();
//Get reference/Cache
leftPaddle = GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>();
}
//Call to pause and unpause
public void pause(bool pausePaddle)
{
rightPaddle.setIsPaused(pausePaddle);
leftPaddle.setIsPaused(pausePaddle);
}
}
Now, you can access both of your Paddles from one script, in another script.
public class YourOtherScript : MonoBehaviour{
PaddleManager paddleManager = null;
void Start()
{
//Get reference/Cache
paddleManager = GameObject.Find("GameObjectPaddleManaerIsAttchedTo") .GetComponent<PaddleManager>();
//To pause
paddleManager.pause(true);
//To un-pause
paddleManager.pause(false);
}
}
By doing this, you will avoid using static variable and also avoid using GameObject.FindGameObjectsWithTag("paddles")) in foreach loop like mentioned in the other answer. GameObject.Find... functions should NOT be used in the middle of the game because it will slow down your game. You need to use it once and cache the GameObject in the Start function, then you can re-use it without slowing down your game.
First of all paddle right and left are game-objects and not classes , the class name is paddle , and if the same script is on both the objects , the most simplest way would be to put it on another empty object and call it once and the code will work on all game-objects that the script is attached to . BUT! that is only regarding to what I cuold make out of your question , Here is what I really recommend , as you said "because I can't extend Mono-behavior and a super-class in Unity" . Ok so you have class A inheriting monobehavior , and you make class's B and C, then when you inherit them from A you will get all the abilities of a monobehaviour in class B and C and you can attach them to game objects , you can even make start and update functions as vrtual and override them in B and C and you can even call A's function use the keyword Base , So read on it , it will take time but in the long run makes you a better coder
Mm, wait. There is something wrong with your question:
YouPaddleLeft and PaddleRight are not classes. They are GameObjects existing in Unity scene. Class is Paddle to which you get reference by GetComponent<Paddle>() .
Now if you have a variable/function that affects all the instances of the class the same than you shell make them static. (Google static variables and functions if you don't know what they are).
So go to your Puddle class and change the declaration of setIsPaused(bool val) to this:
public static void setIsPaused(bool val) { /* implemenetation */ }
and then make a call to it via class token, not object:
Paddle.setIsPaused(true/false);
note that if the static function has references to class variables all those variables should be marked static as well. (e.g. if you have a bool isPaused than mark it static because it should be the same for all the objects all the time anyways)

Access static class directly or cache it?

I know that it's better to cache a component if you use it often during runtime. How about if I cache a component as a static variable and access it during runtime? Let me give you an example:
public class AudioManager : MonoBehaviour
{
public static AudioManager audioManager;
void Awake()
{
audioManager = this;
}
}
Then if I access it from another class, should I use AudioManager.audioManager or cache it beforehand (speaking in the terms of performance)?
P.S. Let me know if something isn't clear.
Edit: I guess I don't know what the hell I'm doing regarding Singletons, but to make it clear, this is a newbie question regarding performance:
1) _audioManager = AudioManager.audioManager in Awake and then use _audioManager.someVariable in Update
VS
2) AudioManager.audioManager.someVariable in Update
You don't need to cache your own component for speed in any case. A component won't pay a performance penalty for accessing itself.
The use case you may be thinking of is caching access to other components or objects so that you don't have to do lookup with GetComponent or GetComponentWithChildren. That does save time, but it's not a complex pattern: just do the lookup the first time you encounter the other component or gameobject, store it in a field inside this component, and you're good:
class Example: MonoBehavior
{
public GameObject _TargetCharacter;
private Transform _cachedTransform;
private Animator _cachedAnimator;
void Awake()
{
if (_TargetCharacter != null)
{
_cachedTransform = _TargetCharacter.transform;
_cachedAnimator = _TargetCharacter.GetComponent<Animator>();
}
}
void Update()
{
DoSomething (_cachedTransform, _cachedAnimator);
}
}
GetComponent and GetComponentInChildren are comparatively expensive you do don't want to do them every frame. However direct access to something set as a field is not expensive there is no need to cache it.
And making it s Singleton: in this context, you would need to make a separate class which is NOT a Component and have that be the singleton - you can't prevent somebody from attaching lots of a given MonoBehavior to things in the Unity Editor so you don't want to assume there's only one of the component floating around. In the AudioManager example, you'd have to assume that many different components might all be looking at the same AudioManager.
Here a good example comparing shared behavior using Singletons vs shared behavior in a static class. Two means to the same end, with slightly different strengths and weaknesses.
Update In response to OP's comment below:
If the point of the original code is to gain speed using the common Unity caching trick, it's not needed. If the point is, as OP suggests in comment below, to make the manager into a 'service provider' that other classes can call there are two routes to go:
The standard unity trick would be to add the caching behavior to the other classes that need to get to the AudioManager. For example:
class SomeOtherComponent: MonoBehavior
{
AudioManager _manager;
void Awake()
{
AudioManager[] AllAudioManagers = GetComponents<AudioManager>();
if (AllAudioManagers.Count == 1)
{
_manager = AllAudioManagers[0];
}
else
{
throw new RuntimeError ("Expecting one (and only one) AudioManager in scene");
}
}
}
Switching to a proper Singleton implementation more or less amounts to just taking the boilerplate in the Awake method above and centralizing into the singleton class, allowing you to replace it.
For an extended discussion of the singleton pattern in unity try this book
I live by a simple rule, if I am going to be calling a component a lot of times, more than 5, then I cache it. The same rule I apply to Singletons. If it is only one call then I just use the Singleton.getInstance().
What you should be really caching
Unity Components such as Transform.
The logic behind caching things like Transform comes from looking at the documentation. Transform is not a variable but a property, which happens to contain getters and setters. These are hidden from you, but that's the way it is implemented. This property happens to be written in C or C++. Therefore this will cost you on performance.

How to avoid casting from interface to class

In trying to design a collision detection component for a game, I came up with the following solution. I define an interface ICollideable that looks something like:
interface ICollideable
{
Sprite Sprite { get; }
int Damage { get; }
void HandleCollision(ICollideable collidedWith);
}
Basically, any game objects that want to participate in collision detection have to implement this interface, then register themselves with the detector, which maintains a list of ICollideables. When it detects a collision, it calls the HandleCollision method on the object and passes in a reference to the object it collided with.
I like this, because it lets me keep all my collision algorithms in one place, and lets the game objects themselves decide how to handle the collision. But because of the latter, I find I am having to check the underlying object type. For example, I don't want Players to collide with each other, so in the Player class there might be something like:
void HandleCollision(ICollideable collidedWith)
{
if (!(collidedWith is Player)) { // do stuff }
}
and so on, and I am wondering if this is telling me that I have a bad design and what the alternatives might be.
Second question, further along the lines of the first. For scoring purposes, if an Enemy is destroyed by a Projectile, someone needs to know the "Owning Player" member of the Projectile class. However, none of my other collideables have or need this property, so I find myself wanting to do (in the Enemy HandleCollision):
void HandleCollision(ICollideable collidedWith)
{
if (collidedWith is Projectile) {
Health -= collidedWith.Damage;
if (Health <= 0) {
Player whoDestroyedMe = (collidedWith as Projectile).FiredBy
// ...
}
}
}
I haven't a clue as to how to handle this with a better design. Any insights would be appreciated.
EDIT: I wanted to pull focus towards the second question, because my gut tells me a way of handling this will solve the first question. As for the first question, I thought of a way to abstract this behavior. I could define an enum:
enum Team
{
Player,
Enemy,
Neither
}
and have ICollideables implement this property. Then the collision detector simply doesn't register collisions between collideables on the same "Team". So, Player and Player Projectiles would be on one team, Enemy and Enemy Projectiles on the other, and the environment (which can damage both) can be on neither. It doesn't have to be an enum, could be an int or a string or anything, with the idea that objects with the same value for this property do not collide with each other.
I like this idea of modeling behavior with a simple attribute. For instance, if I want to turn "allow friendly fire" on, all I have to do is create Projectiles with a Team value other than the Player's Team value. However, I still may have cases where this is not enough. For example, a Player may have shields that are temporarily impervious to projectiles but will not protect against a direct collision with an enemy, and so on.
I think you're going the wrong way altogether in handling the collision inside of the class of one of the colliders. I would put this logic into a third object, outside of the entity objects. You could do all of the checking of the types in this third object, and even handle most of the logic there too. Why should a Ship or a Projectile have a monopoly over the logic that happens when one hits the other?
The following is how I might handle this, although it means using an object for each style of collision (Ship vs Ship, Ship vs Projectile, Ship vs Asteroid, etc.) You might be more comfortable putting all that logic into a single object, or even a single method on that object.
public interface ICollisionHandler
{
bool HandleCollision(Entity first, Entity second);
}
public class PlayerShipVsProjectile : ICollisionHandler
{
private GameOptions options;
public PlayersOwnShipHandler(GameOptions options)
{
this.options = options;
}
public bool HandleCollision(Entity first, Entity second)
{
// Exactly how you go about doing this line, whether using the object types
// or using a Type property, or some other method, is not really that important.
// You have so much more important things to worry about than these little
// code design details.
if ((!first is Ship) || (!second is Projectile)) return false;
Ship ship = (Ship)first;
Projectile projectile = (Projectile)second;
// Because we've decided to put this logic in it's own class, we can easily
// use a constructor parameter to get access to the game options. Here, we
// can have access to whether friendly fire is turned on or not.
if (ship.Owner.IsFriendlyWith(projectile.Shooter) &&
!this.options.FriendlyFire) {
return false;
}
if (!ship.InvulnerableTypes.Contains(InvulnerableTypes.PROJECTILE))
{
ship.DoDamage(projectile.Damage);
}
return true;
}
}
Like this, you can then do...
// Somewhere in the setup...
CollisionMapper mapper = new CollisionMapper();
mapper.AddHandler(new ShipVsProjectile(gameOptions));
mapper.AddHandler(new ShipVsShip(gameOptions));
// Somewhere in your collision handling...
mapper.Resolve(entityOne, entityTwo);
The implementation of CollisionMapper is left as an exercise for the reader. Remember that you might need to have Resolve call the ICollisionHandler's "Handle" method twice, with the second time reversing the entities (otherwise your collision handler objects will need to check for the reverse situation, which might be ok as well).
I feel this makes the code easier to read. A single object describes exactly what will happen when two entities collide, rather than trying to put all this info into one of the entity objects.
For the first case, I would add the following extra method to ICollidable:
bool CanCollideWith(ICollidable collidedWith)
As the name suggests, it would return true or false depending upon whether it can collide with the passed in object.
Your Player.HandleCollision method would just do its stuff because the calling method could do that test and not even call the method if it wasn't required.
How about something like this?
Collidable.cs
abstract class Collidable
{
public Sprite Sprite { get; protected set; }
public int Damage { get; protected set; }
protected delegate void CollisionAction(Collidable with);
protected Dictionary<Type, CollisionAction> collisionTypes = new Dictionary<Type, CollisionAction>();
public void HandleCollision(Collidable with)
{
Type collisionTargetType = with.GetType();
CollisionAction action;
bool keyFound = collisionTypes.TryGetValue(collisionTargetType, out action);
if (keyFound)
{
action(with);
}
}
}
Bullet.cs
class Bullet: Collidable
{
public Bullet()
{
collisionTypes.Add(typeof(Player), HandleBulletPlayerCollision);
collisionTypes.Add(typeof(Bullet), HandleBulletBulletCollision);
}
private void HandleBulletPlayerCollision(Collidable with)
{
Console.WriteLine("Bullet collided with {0}", with.ToString());
}
private void HandleBulletBulletCollision(Collidable with)
{
Console.WriteLine("Bullet collided with {0}.", with.ToString());
}
}
Player.cs
class Player : Collidable
{
public Player()
{
collisionTypes.Add(typeof(Bullet), HandlePlayerBulletCollision);
collisionTypes.Add(typeof(Player), HandlePlayerPlayerCollision);
}
private void HandlePlayerBulletCollision(Collidable with)
{
Console.WriteLine("Player collided with {0}.", with.ToString());
}
private void HandlePlayerPlayerCollision(Collidable with)
{
Console.WriteLine("Player collided with {0}.", with.ToString());
}
}
I think this is a good question #idlewire and I have to say that I don't think there is anything fundamentally wrong with your original solution. In asking whether object Foo should be allowed to cast the ICollideable to a Bar, the important question is only: is undesirable to have Foo knowing anything at all about Bar? If the answer is 'no' because Foo already knows about Bars (for behaviours other than collisions, perhaps) then I see no problem in the cast and, as you say, it allows you to better encapsulate the behaviour of both.
Where you need to be wary is only where this would introduces a dependency between two things you'd like kept apart - which would make re-use of either without the other (in a different game application for example) impossible. There you might want to either have more specific sub-interfaces from ICollideable (e.g. IElastic and IInelastic), or use properties on the interface as you have proposed with the Enum.
In short, I think your original posting shows good evidence of OO thinking, not bad.
Sometimes the simplest method is the best method. Unless you want to separate your collision interactions into numerous subtypes, you could instead place a bool IsPlayer property within the Interface.
The upside here is that you have a cheaper, and type safe method of determination over casting.
If (isplayer == true)
{
Handlethisway;
}
The downside is that you're still having to do some sort of state checking, but this is more efficient.
To avoid any state checks, you'd need to do the following: Make an ICollidablePlayer Interface which accepts generic Icollideable and handles them differently. Since the Icollideable is your injected dependency, the ICollideablePlayer dependencies are inherent. The objects of Icollideable would have no knowledge of this separate process, and interact with each other in the same manner.
ICollideablePlayer:ICollideable
{
//DependenciesHere
HandlePlayerCollision(ICollideable)
{
HandleDifferently
{
}
ICollideable
{
//DependenciesHere
HandleCollision(ICollideable)
}
}
}
In an interaction, the ICollideable will treat the player as any other ICollideable, but the ICollideablePlayer will reject the interaction when it does the check itself.
For things like shields and all that, You're talking about state changes which implies that those such things should be properties within either of those Interfaces such that something like bool ColliderOff to temporarily change the state.

Categories

Resources