1
00:00:04,280 --> 00:00:09,260
In this lecture, we're going to solve this pesky little problem with our audio player, where when

2
00:00:09,260 --> 00:00:15,440
we change the scene, the track restarts and we're going to fix this using something known as the singleton

3
00:00:15,440 --> 00:00:16,070
pattern.

4
00:00:17,240 --> 00:00:22,580
So before we talk about the singleton pattern, let's actually understand what's happening in our game.

5
00:00:22,610 --> 00:00:28,640
In our main menu, we have all of the objects that exist within this scene, including our audio player.

6
00:00:28,940 --> 00:00:35,600
But if we go ahead and hit play and then change our scene by hitting our start button, everything from

7
00:00:35,600 --> 00:00:41,560
that original scene is being destroyed and then everything from our game scene is being loaded in.

8
00:00:41,570 --> 00:00:46,150
So our old audio player gets destroyed and we create a new one.

9
00:00:46,160 --> 00:00:49,900
And in creating our new one, we start playing our track from the beginning.

10
00:00:49,910 --> 00:00:54,980
So we're going to need a way of grabbing our audio player from our main menu scene when the game starts

11
00:00:54,980 --> 00:00:58,250
and pulling it across into other levels of our game.

12
00:00:58,580 --> 00:01:03,710
And if we turn to the Wikipedia article for the Singleton pattern, it says that the singleton pattern

13
00:01:03,710 --> 00:01:10,240
is a software design pattern that restricts the instantiation of a class to one single instance.

14
00:01:10,250 --> 00:01:16,190
And this can be very useful when exactly one object is needed to coordinate actions across the system.

15
00:01:16,370 --> 00:01:21,470
If we continue to read, though, it does also say that it's considered to be an anti pattern and is

16
00:01:21,470 --> 00:01:24,530
frequently used in scenarios where it's not beneficial.

17
00:01:24,560 --> 00:01:30,560
And that's because the true singleton pattern not only requires us to only have a single instance of

18
00:01:30,560 --> 00:01:36,400
an object in our game, but also that that instance is globally available to everything that needs it.

19
00:01:36,410 --> 00:01:41,870
And having global or public variables in our game can cause us some problems, especially when we're

20
00:01:41,870 --> 00:01:43,340
using the singleton pattern.

21
00:01:43,340 --> 00:01:46,640
So we have to be very careful about how and when we use it.

22
00:01:46,790 --> 00:01:52,430
But if we jump back into unity, I'm going to show you two different ways that we can use this singleton

23
00:01:52,430 --> 00:01:53,070
pattern.

24
00:01:53,090 --> 00:01:57,980
The first will create a single instance of our audio player, which will persist across our game but

25
00:01:57,980 --> 00:01:59,690
not be publicly available.

26
00:01:59,690 --> 00:02:04,850
And the other one will be a more traditional singleton pattern, which does have global access.

27
00:02:04,910 --> 00:02:11,120
So to get us started, let's go over to our audio player and then into our audio player script and to

28
00:02:11,120 --> 00:02:15,440
set up the non global version, we're going to do all of this in a wake.

29
00:02:17,190 --> 00:02:22,110
And in here we're going to call a method that we're about to write called Manage Singleton.

30
00:02:23,610 --> 00:02:28,860
Then underneath our wake method, let's write this method, which is going to also be void, and we're

31
00:02:28,860 --> 00:02:30,480
calling it managed singleton.

32
00:02:31,670 --> 00:02:35,330
And we currently have an audio player in every scene of our game.

33
00:02:35,330 --> 00:02:37,640
So we're going to have to do a couple of things.

34
00:02:37,640 --> 00:02:42,800
First of all, when we load into the scene, we want to check if an audio player already exists.

35
00:02:43,040 --> 00:02:46,940
And one way of doing this is to use find objects of type.

36
00:02:46,940 --> 00:02:51,290
So just like find objects, but with objects plural instead.

37
00:02:51,560 --> 00:02:56,060
And rather than using the chevrons like we're used to, we're actually going to use parentheses this

38
00:02:56,060 --> 00:02:58,820
time and we're going to say Get type.

39
00:02:59,390 --> 00:03:05,000
What this get type does is it will return the type of the class that we're looking at.

40
00:03:05,000 --> 00:03:07,490
So in this case, it will be an audio player.

41
00:03:07,760 --> 00:03:11,270
So we could instead look for audio players instead of get type.

42
00:03:11,270 --> 00:03:16,220
But this is a bit more generic so that if we want to use this in other scripts, we can just copy it

43
00:03:16,220 --> 00:03:18,860
in without having to amend too much of the code.

44
00:03:19,160 --> 00:03:25,640
So this as it is, we'll find all of the objects of type audio player, and from here we want to find

45
00:03:25,640 --> 00:03:27,470
the length of this list.

46
00:03:27,590 --> 00:03:32,150
Now this length is going to come in useful and help us get rid of the red squiggly error.

47
00:03:32,180 --> 00:03:36,290
Let's store this in an integer variable called the instance count.

48
00:03:37,430 --> 00:03:41,780
So this will keep track of how many instances of our audio player exist.

49
00:03:41,780 --> 00:03:50,810
When we load a scene from here, we can then ask that if the instance count is greater than one, then

50
00:03:50,810 --> 00:03:55,970
we've got more than one audio player in our scene and we need to start getting rid of them and we can

51
00:03:55,970 --> 00:03:58,340
get rid of objects by just destroying them.

52
00:03:58,340 --> 00:04:01,640
So we can say Destroy game object.

53
00:04:02,210 --> 00:04:04,970
And that's the game object with the lowercase g.

54
00:04:05,150 --> 00:04:10,610
Otherwise, if we don't have more than one audio player, we want to set this audio player up so that

55
00:04:10,610 --> 00:04:15,050
it can transition between our scenes and not get destroyed when a new scene is loaded.

56
00:04:15,410 --> 00:04:23,090
So to do this, let's say else don't destroy on load and pass in this game object.

57
00:04:23,300 --> 00:04:28,640
This will then mark our audio player so that when we change scenes, the existing audio player will

58
00:04:28,640 --> 00:04:29,570
come with us.

59
00:04:29,960 --> 00:04:31,580
So that's one way of doing it.

60
00:04:31,580 --> 00:04:38,750
But I am noticing a very small problem and that is that before we destroy a game object, we also want

61
00:04:38,750 --> 00:04:43,190
to set our game object set active to false.

62
00:04:43,700 --> 00:04:48,560
Now this might seem a bit redundant because we're literally about to destroy it, but because of the

63
00:04:48,560 --> 00:04:55,250
way unity executes its code, there's a very, very small chance other objects in our game may try and

64
00:04:55,250 --> 00:04:59,610
access this version of our audio player before we go and destroy it.

65
00:04:59,630 --> 00:05:04,940
So by disabling it in a wake, we're stopping anything else, trying to grab it and use it before we

66
00:05:04,940 --> 00:05:05,660
destroy it.

67
00:05:06,110 --> 00:05:10,760
Now, to see this in action, let's save our script and head over into unity.

68
00:05:11,330 --> 00:05:15,560
And now, if we go ahead and hit play, everything should work as it did before.

69
00:05:15,980 --> 00:05:20,150
But if we hit start, then the music continues to play.

70
00:05:20,300 --> 00:05:26,540
And if we look in our hierarchy, if we expand our game and let's pause for a moment, will not be able

71
00:05:26,540 --> 00:05:29,700
to find our audio manager in our game anymore.

72
00:05:29,720 --> 00:05:34,130
And that is because it's now under this don't destroy on load header.

73
00:05:34,490 --> 00:05:40,820
So this audio player in here is the audio player from our first scene rather than our currency.

74
00:05:41,150 --> 00:05:45,380
So with our audio player working as expected, we could leave things there.

75
00:05:45,380 --> 00:05:49,420
But I did say that there was another, more pure way to write a singleton.

76
00:05:49,430 --> 00:05:54,770
So let's jump back over into our audio player script and have a look at how we might do this.

77
00:05:55,070 --> 00:06:00,230
Well, it's actually going to be fairly similar, but rather than trying to find objects of type and

78
00:06:00,230 --> 00:06:05,460
then checking how long that list is, we're going to store a variable at the top of our script.

79
00:06:05,480 --> 00:06:08,390
It's going to be a type audio player in this case.

80
00:06:08,390 --> 00:06:13,730
So we're storing a reference to our own class type, and we'll call this the instance.

81
00:06:14,540 --> 00:06:20,970
And to get this working how we want, we're going to also add a new keyword in front of our audio player.

82
00:06:20,990 --> 00:06:27,050
So just like how we can have public or private, we can also have some other keywords as well.

83
00:06:27,050 --> 00:06:30,400
And one of those keywords is something known as a static.

84
00:06:30,410 --> 00:06:33,920
So this is currently a private static audio player.

85
00:06:34,100 --> 00:06:39,400
And static variables are interesting because they persist through all instances of a class.

86
00:06:39,410 --> 00:06:46,580
So if we had multiple audio players in our scene, they would all share this exact same static instance.

87
00:06:46,790 --> 00:06:48,560
This is great for our singleton.

88
00:06:48,560 --> 00:06:54,590
So in our managed singleton method, let's just comment out the first two lines for a moment and we

89
00:06:54,590 --> 00:07:02,630
can instead say that if our instance does not equal null, then we want to go ahead and destroy the

90
00:07:02,630 --> 00:07:05,320
game object that's trying to create itself.

91
00:07:05,330 --> 00:07:13,790
Otherwise we want to set the instance variable equal to this object so we can use the this keyword which

92
00:07:13,820 --> 00:07:16,850
indicates this version of the audio player.

93
00:07:16,940 --> 00:07:22,220
So the logic here is that if we're the first audio player to come along, then our if statement will

94
00:07:22,220 --> 00:07:27,560
be false and we'll set ourselves to be the instance of this static audio player.

95
00:07:27,590 --> 00:07:33,080
Otherwise, if we're the second or maybe third one to come along, then our instance variable already

96
00:07:33,080 --> 00:07:35,720
has a version of an audio player stored in it.

97
00:07:35,720 --> 00:07:40,130
So we know we're not the first ones to come along and we can go ahead and destroy ourselves.

98
00:07:40,370 --> 00:07:45,740
This instance, though, is still private, so if we scroll up to the top, a true singleton pattern

99
00:07:45,740 --> 00:07:48,110
would have this instance be public.

100
00:07:48,140 --> 00:07:51,500
So we could do this by either setting this to be public.

101
00:07:51,500 --> 00:07:56,540
But we would then have to worry about other scripts coming in and changing what this instance is.

102
00:07:56,660 --> 00:08:06,110
Or we could create a getter so a public audio player get instance and this would just return our instance.

103
00:08:06,820 --> 00:08:13,240
Making this global as it is, gives us some benefits that we can now reference the instance of our audio

104
00:08:13,240 --> 00:08:16,210
player dot any of our public methods.

105
00:08:16,210 --> 00:08:21,310
This means we wouldn't have to explicitly find our audio player in the scene first.

106
00:08:21,310 --> 00:08:26,800
We could just reference this static instance and have access to all of its public methods.

107
00:08:27,130 --> 00:08:28,480
To show you what I mean.

108
00:08:28,480 --> 00:08:35,049
If we head over to our shooter method very quickly, we're currently saying audio player play, shooting

109
00:08:35,049 --> 00:08:40,570
clip, and we're able to do that because we've already found a reference to the audio player in our

110
00:08:40,570 --> 00:08:41,230
scene.

111
00:08:41,230 --> 00:08:47,980
But if we want to bypass all of this storing variables and finding things in a wake, we could instead

112
00:08:48,010 --> 00:08:56,680
just say audio player, dot get instance, dot play shooting clip, and that would bypass any need to

113
00:08:56,680 --> 00:08:58,870
find that object in the hierarchy.

114
00:08:59,260 --> 00:09:04,840
So a couple of good benefits there, but also a handful of drawbacks which we haven't really discussed.

115
00:09:04,840 --> 00:09:11,290
By doing things this way and having a public instance available, we start to lose control of exactly

116
00:09:11,290 --> 00:09:13,090
where things are in our game.

117
00:09:13,360 --> 00:09:18,820
This is mostly fine for a small project like ours, but as your game gets much larger, you can have

118
00:09:18,820 --> 00:09:19,600
a lot of things.

119
00:09:19,600 --> 00:09:24,520
Interacting and trying to hunt down problems with singletons is an absolute nightmare.

120
00:09:24,520 --> 00:09:30,850
So where possible, always try and avoid globally accessible instances if you can get away with it.

121
00:09:30,850 --> 00:09:33,370
For our audio player, we definitely can.

122
00:09:33,370 --> 00:09:37,930
So let's not do things this way and back over in our audio player.

123
00:09:37,960 --> 00:09:44,560
We could keep our static instance if we wanted to, and in fact I think we will, but we won't create

124
00:09:44,560 --> 00:09:46,750
the public getter method for it.

125
00:09:46,750 --> 00:09:51,610
Then down in Manage Singleton, let's just clear out those two commented lines of code that we don't

126
00:09:51,610 --> 00:09:52,480
need anymore.

127
00:09:52,480 --> 00:09:57,400
And now if we jump back into unity just to make sure that everything is still working as expected,

128
00:09:57,940 --> 00:09:59,440
let's go ahead and hit play.

129
00:09:59,950 --> 00:10:04,180
Our audio player is now in Don't Destroy On Load and our music has started.

130
00:10:04,390 --> 00:10:10,330
If we change sane, our music continues to play and our audio player is still there, ready and waiting

131
00:10:10,330 --> 00:10:10,960
for us.

132
00:10:11,590 --> 00:10:16,900
So there's two slightly different ways of implementing the singleton pattern and also how to make it

133
00:10:16,900 --> 00:10:19,930
global if you ever wanted or needed to do that.

134
00:10:20,170 --> 00:10:25,090
And with this knowledge of Singleton in hand, the next step is going to be to look at other objects

135
00:10:25,090 --> 00:10:31,450
in our game that may or may not benefit from also being Singleton's so no challenge for this lecture,

136
00:10:31,450 --> 00:10:37,300
but before you go on to the next lecture, just have a think about which objects you think might benefit

137
00:10:37,300 --> 00:10:38,470
from being a singleton.

138
00:10:38,650 --> 00:10:42,670
And then in the next lecture, we'll start looking at some of the other problems that still exist in

139
00:10:42,670 --> 00:10:43,330
our game.

140
00:10:43,330 --> 00:10:44,680
So I'll see you there.

