Unity : decoupling data from behaviours, using a model-view-controller design pattern. | Fred Moreau | Skillshare

Unity : decoupling data from behaviours, using a model-view-controller design pattern.

Fred Moreau, Unity Instructor, Agile Coach

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
19 Lessons (2h 20m)
    • 1. Course Overview

      0:35
    • 2. An overview of Design Patterns

      6:37
    • 3. Mocking up the Track View

      13:29
    • 4. Saving UI Elements as Prefabs

      3:11
    • 5. Shaping the Track Data (Model)

      5:42
    • 6. Separating the data from the component

      4:13
    • 7. Making the data a custom Asset type

      4:18
    • 8. Generating random data (for testing purposes)

      10:54
    • 9. Editing the data with a Custom Property Inspector.

      17:17
    • 10. Setting up the Track View component

      7:21
    • 11. Reading the Data and populating the View

      6:40
    • 12. Animating the Track View Scrolling

      4:41
    • 13. Handling custom inputs using Keycodes

      11:35
    • 14. Implementing Gameplay tempo mechanics.

      6:46
    • 15. Implementing Gameplay input controls.

      6:12
    • 16. Sync'ing the TrackView with the Controller track.

      10:09
    • 17. Adding the Gameplay visual feedback.

      12:36
    • 18. Course Retrospective

      2:10
    • 19. Refactoring.

      6:00

About This Class

This training is the first of a series of training on Unity, focusing on team work between designers, artists and programmers.

Every training in this series will touch on a specific subject of the game industry.
This course will touch on design patterns, and especially the model-view-controller pattern and how to implement it with Unity.

We're going to start from scratch to build a Guitar Hero, or Tap Tap Revenge like game.
We'll touch on data structure and gameplay mechanics, which overlap design and programming, and data-gameplay graphics, which overlaps art and programming.

We'll begin with a quick overview of the known patterns (MVC, MVVM, MVP)
Then, we'll mock up the view with Unity UI tools, before we work on the game architecture.

We'll design the Track Data structure (Model), then we'll display and edit it with a Custom Inspector, and randomly generate sample data to work with. We'll touch on reusable data with the ScriptableObject class.

We'll then work on the Track View, populate it with prefabs UI objects, and animate it.

We'll then work on the GamePlay Controller, that'll handle inputs from the Player and all Game Play mechanics, and update the view so the Player knows how he's doing.

At the end of the course, artists will know better what they can do with UI components, and programmers and designers will know how they can author custom game data, right from the editor, for use at runtime.

Transcripts

1. Course Overview: in this training, we're gonna touch on design patterns and especially the model view controller pattern, which is widely used in Aptiva lawmen and can be very useful in game development to we're going to start marking up the U. Y using the unity y tools. Then we're gonna touch on inscrutable object, which allows us to safety data indie editor and use it every time. And then we're going to touch on the game controller to take the inputs from the player and send feedback to the player to let him know if Blade right or wrong for this, we're gonna use a tap tap revenge or guitar hero kind of game. So with that further Aito opportunity and I'll see you in the next video 2. An overview of Design Patterns: During this first chapter, we're going to touch on the model view controller, which is going to be the ground base for the coming chapters off this game project, which is going to be a kind of guitar hero or tap tap revenge sort of game where the player has to play different inputs and rhythm with the music. And so what Ah, we can see here is that the gameplay is a very data centric gameplay. So it means that we're going to have to handle data for the tracks. And so we're gonna have to Ah, Thor, the data. And then we're also gonna have Teoh to use this data and in this chapter, working to touch on handling the data, creating some some basic data. And what we see here is that Ah, we have a series of expected inputs are displayed is Colin And so we're gonna make it very simple for now where we have just one input by it one in. But such is up, down, left, right Then the displaced girls down with a set beat per minute perimeter in the player, Miss pressed the buttons and riven with the music and the input representations will change to reflect the players action Such as Did I miss? Did I get it right? Did I get it wrong? The player has to know if it's played right, and if it's played, probably he's got to get some rewards. If you replace probably. So let's have a good overview of what we're gonna be touching on the chapter. We're gonna have a quick of a view of the known patterns, which are the envy sees, which is the model view controller or the M V M for Model View View model and the M V P for Model View presenter, which are designed patterns. Then we'll see how weaken quickly mock up the view in unity, using the U Y tool so that we can give ourselves a pretty good I idea pretty good representations off what the view is going to be like, and then how the data is going to be like with it. Then we're going to touch on the track model. So it's we're gonna touch on the data structure. We're going to make it so that the data is independent from the gameplay we're gonna touch on reusable data and touch on on civilization we're going to touch also in generating simple data, Randomly said that we don't have to create our own data at the very beginning of the development. In were been to touch on data display in editing as well. And then we're going to touch on the track view, which is representing the track in the game view, using some discipline models that we're going to reference. And then we're going to populate the view with those prefab subjects. And then we're going to animate the view. And later we're gonna touch on the gameplay controller, taking the inputs from the player handling all the gambling mechanics were going to touch on the singleton pattern, which loses to access a controller or excess a game component wherever it is in the scene without having to manually reference it. And then we're gonna touch on the beach views is what we want to do is to update the views when the player plays, said that the player knows if he's played right around. So let's start with a quick overview off the model view controller. The model view controller tells us that we separate as opposed to a competent architecture , a common. It is self sufficient, so confidence gonna work with each other's. But there are self sufficient. Very often a competent has its own data. It has hits on representation of the data, and it handles the inputs from the player in a band innately so it's It's old, self sufficient in a design. Better, we tend to separate things so that they're more modular so that do weaken change things. The idea off a model view controller is that you can swap a controller vory quickly and very easily without having to change another component off the ecosystem. In this pattern, what we see is that we have a model, which is the data itself, and on the other end there's the user, and in between there is a controller and a view. The view is will take. The model will take the data from the model and will present the data to the user in a given form. And then the controller, on the other hand, will take the input from the user and will modify the data. And so whenever the data changes, then the view of dates and so on and so forth. This is the model view controller. This is a design pattern that is widely used in APS development. Now there's a few other patterns that are very similar to that model view controller patter and such is the model view view model where what you can see here is that there's a different layer of abstraction between the model and the view where you have a view model, which is okay. We know that data and we know the the view. But what we want to do here is to make sure that you can have a view that somehow is able to adapt to a model. So you could have, like a very generous view, and so of you could potentially display different kind of data. And this is the idea off the Model View view model, which is also used in game development. Sometimes another design pattern, which is again very similar to this, is the middle view presenter, the model view presenter, as opposed to the original model view controller. You can see that the presenter is in between the model end of you, so it's not the view that really dates on the model, but the view updates based on the presenter, the prisoner is the manager is the global manager, and it handles the data and gives the view. It gives it the data to be displayed, and the view will then display the data, and it will take the inputs from the user. So that being said, these are just designed patterns. They're not just like something that you have to follow very precisely. It's something that you can play with and change is you need, though it's usually good to know those design patterns, probably, and to understand them so that whenever you want to create your own design veterans, then you don't end up in somehow recreating a pattern that already is a falling in the traps of unknown design patterns. So with all that fuel relayed out, it's time to practice. And this is what we're going to do in the next video 3. Mocking up the Track View: So, as we're going to start working on this model view controller pattern, we're gonna have to ah, work in all three components at the same time. But we have to start with one of them. And there will always be people who, like Teoh, begin by the end. And, uh, usually, I kind of like Teoh. Start with the view, which is more as to what the what the view is gonna be looked like, uh, in the end and what its and has came to work and how it's going. Teoh, behave. So I like to muck up the other view first. There. I'm just talking of Ah, fresh new, are you? Why, Trudy, project with unity And I have just added, Ah, simple canvas here. Ah, kind of a studio. So what we're going to do here is start Mokin up the view and then we're going to start working on the model, uh, right after. So what I'm going to do here is come in the create panel and I'm going to go into the you want and asked to create a new canvas. I'm creating two canvases because the canvas I already have is a canvas to D and it's a screens pays overlay and the one I want Teoh Handle now is going to be a canvas three d So and I'm actually going to rename it Canvas three D like this and and now what I want to do here is and say I want to take it from screen space overlay to screen space camera so that I can handle three D projection. And there I'm just going to use the main camera here, and I'm going to keep the plain dissed ends and every other settings to their defaults. I'm actually just going to say that I want to scale with the screen size and I'm going to give a reference resolution off 10 80 by 7 20 for saving 20 p resolution. And I'm also going to said that want toe match the height here and that I want to give a reference pixels per unit off 128 pixels like this. Now that I've got this, I'm going to import a couple of sprites on, and so I'm just going to going important the custom you need a package that you will find along with this training and there this is going to give me the set off inputs and also a trigger zone that we're going to set up and put together. So there we go. We've got those sprays here, the down life right up a rose and also a trigger zone, which is just a plain square. But it's got settings here, as we can see in this predator so that we've got a margin and a border so that we can create a holo square from there. What I want to do Here's then start mocking up a few show I'm going. Teoh said that, uh, I'm going to reset the zoom to this new canvas cure and what I want for now, I'm just going to, uh, that get the same view will bigger And from there, what I'm going Teoh create is what is going to be our attract view, which I'm gonna make a mock up of a track view. And so for this I'm going to go in here and simply said that I want to create a panel and I'm going to get rid of the background, sort of see images like this, and I'm just going to. I give it like a default background. I'm gonna make it fully a bake and give it like, uh, a grey background like this so that we get to see it. And now I'm going to set its Ah lineman. So first I'm going Teoh rename this to track as you like this and I'm going to change this so that it's ah lined at the very bottom like this and I'm going to give it a with off 3 20 like this. So this is going to be the representation off the track. And now that I've got this, I'm going Teoh start adding some sub you elements like we saw that we want to have every beat represented as a serve elements. So what I can do actually is simply duplicate this element here, and then I'm going to call it beat view like this, and I'm going to parent it to the drive you like that and I'm going to reset its position and reset its scale like this person reasoned, the skill is Teoh changed and I'm going to change its height. So I'm gonna give it like a height of 40 and this is all gonna be customizable later. But for now, I'm just gonna sit it in here. And so what I've got here is ah is a sub view in here. And what I'm going Teoh do here is to add on the track view, I'm going to add another component, which is a vertical layout group. And so what? The Dodge is that it will automatically lay out all the Children of this object. So now I'm going to take this 100 here, and I'm going to give it, like, a different color that I'm gonna make it blue. And now what we can see here is that if I don't placate this object a couple of times, then it will automatically lay out those objects in there. Now we can see that this compartment will automatically distribute this object along its height. So I'm also going to add another component here, which is a constant size, common size, fear and the condensates future. Or lose me to say that I want to fit the size of this object based on the content of this object. So based on the Children of the subject and there, I'm going to say that vertically. I wanted to be the minimum size. And so what you can see here is that now all the objects are going to be taken back together as this object is now the height off all the objects together. And I still have access to the spacing here. So if I wanted to space them, like with 20 pixels each like this, then I could do it like that. So this is Ah, this is a very, uh, Foley Andy on to do this way and this lose me too. Then simply take this track here and then I'm simply going to have this track stroll down as we as we go through the game. So what we're going to do is that at the very beginning of the game, we're going to initialize the view with all the information that we get from the track, and we're going to fill this up with all the different information. Is ah, up, down, left, right. And then we're simply going to make it move down like this. No, what? I'm also going Teoh to do Here's and said that I want this to control the ah, the China ties and I wanted to control the width, but I don't want it to control the height. I just wanted to control the with. And so what we're also going to do here and now as then say that we want to change the views of a little bit so that we have representation off the left, right, up down inputs. And so to do this, I'm simply going to, uh, add Or actually, I could just duplicate this and then I ran it. And then I'm going to set this to fully take, ah, all its parent transform like this. And now I'm going to replace the source image. I'm also going to reset the scale like this and there I'm going to change this to using of the, um, left Earl. And I'm also going to say that I wanted to preserve, uh, the expect and I wanted to also be white. Otherwise, it's blue against blue, and it's not very much she able And so I've got this. Now, this is this is gonna be my down things is gonna be my left input view. And so I'm going to rename this to left, and I'm going to rename this to left a room like this and I'm going to get rid of all this . And now that I've got this, I'm going to duplicate this a few times, and all I've got to do now is ah and say, take this one and I'm going to say right, uh, and down. And so, as you would expect, I'm going to bring this to great Perot and wrote and down I really like this. And I'm going to replace the source image to use the down, sprayed and up Sprite like this and right like that. So now I've got all these, um, objects that I will be able to use later. And I'm simply going to just change, can realize that got to reset the scale again for all the other objects. So you may want Teoh make sure that you don't add up with those values like this. And now I'm going to say that I won't have different colors for the year. The left rate up and down. So basically, I'm just going to take arbitrary colleges that match the the colors of the PlayStation four controller. So I'm going to set it that the left is going to be somehow pink and the down is blue. The right is red like this, and the up is going to be green like that. But you can actually just choose any color that you want. In a further video, we'll see how we can actually take advantage off multi platform inputs and have different sets of sprites for the PlayStation, the Xbox and PC and other versions. So this is, Ah, pretty much all I wanted. But I also want to be able to tilt the screen so that we've got some perspective is we could see in the the original mock Up. We don't want this to be a very two d very much to D game. We wanted to be more kind of a three d game. And so to do this, I'm actually going to We'll go again in here, and I'm going to add a new panel like this to the track view, and I'm going to call it Tilt View. And so the deal view is going to remain a to root of the canvas three like this, and I'm simply going to apparent the track view to the tilt of you like that. And there with the till view. What I'm going to do here is and say that I want a little bit of a new offset from the bottom, like 100 pixels and maybe same thing at the top, like 50 pixels also. And no, what? I want to make sure there's that I will put the pivot at the vory bays And so I'm simply going to said the other pivot to, ah zero like this, and I'm probably gonna have to reset this now, too. 50 and 100 like this. And what this allows me to do then, is to rotate the screen here like this and to tilt the view. So I'm going to use a an arbitrary value off 60. And so what that always made it doing now isn't to change the position of the track view. And as you can see, then the travel is going to move in a three D space on this is this is what I wanted. And so yet again, I can you know, it Just duplicate this a few times, and I'm going to get, uh, the effect that I wanted Teoh to have little interest and do this and that. It saying the next day have deal. We're gonna be, ah, preparing the pre fabs that we can use to instead she eight letter and we're also going to start working on the on the model script. 4. Saving UI Elements as Prefabs: Okay, so now that we've got our a moke up off the tribe, you what we also want Teoh to do is to add the trigger zone, which is going to tell the player where two and when actually to to trigger, uh, the the inputs. And to do this, I'm simply going to take the left object here, and I'm going to duplicate it and I'm going to repair and it to the to the chilled You like this and just going to reset. It's, ah position like this 200 And I'm also going to reset the scale 111 and like this. And now I'm going to change this to be at the root like this and mostly going to align the position and the people like this. And so with this, I'm going to rename this to trigger zone like this, and I'm going to get read off the child object here and there. I'm going to change these back to white, and I'm also going to change this to use the trigger zone Sprite. And there you can see that in the image site we have this beautiful said Teoh sliced, and I'm simply going to uncheck feel center and by UN checking field center would have dies that if we have looked at the spread here, This right has some some borders and it will simply just make it fully transparent within the borders. So with with this, this is going to let me target this this zone here and as we later want to be able to populate, attract view with objects, we obviously don't want to have this object or really in the track view. And so they're all set up in here. What I'm also going to do here is then simply select all those objects in there. I'm going to uncheck the recast target because this is not intractable. So I don't need to ah, have the other breakfast target option on there. What I'm going Teoh do. Here's and simply just going in here and creating new a folder which I'm going to call pre fabs like this. And I'm going to come in here and drag and drop the last and right and and down pre fabs like this. And so I'm going to give them in the view now, just you keep an ideal fellow where I'm going and what I want to do. But later we're just going to get rid of them and re populate the view with the data that comes from the track. And so in the next video, we're gonna start working on the track model. So on all the data that we want to put in a in a music track 5. Shaping the Track Data (Model): Okay, So in this video, we're gonna be working on the on the track pattern or the track model off the of this model view controller Better. And so to do this and simply going to create a new folder which in Canticle scripts like this. And in this folder I'm going to go and create a new C sharp script and I'm going to go it track like this, and I'm going to start editing the track like that. And so what I'm going to start with, I'm actually just going to get rid of all this, and I'm going to, um this all in the name space a kind of like to do this. It makes it is your letter to, ah, handle the project. And so with this here, I'm just going to keep the track to be immoral behavior for now. And we can think of it as being a track player somehow. And I'm just going to think of what is the data like? So the model in the model view controller is very important because it's the data that we used to display the view. But it's also the data that we use in the controlled or two controlled the game play. And so it's very it is the very root off a model view controller. And so what? I'm going Teoh start asking. Here is what is a track? What all of the information's that we want to have in a track. So very obviously we could start thinking enough. Ah, well, it's got a title and it's got an author name and it's got a description. It's got an album, name and so on. And so this is all pretty of yours, and I'm just not going to put them in here. But we will probably do these in a later chapter, or to start displaying collections of tracks and letting the player to truce between several tracks. But they're what I really want Teoh to focus on is, what is this track going to do in my controller? It's going to tell my track view. What is the information to display? And it's going to tell my and came controller how to use this information, and so basically it's going to be a list off information because it's simply going to be in the information that say's every beat we want to take an input and we want to display an input and we want to take an input and make sure that the player is played. That inputs. So I'm just going to represent it as a list of integers. I could create some smarter data as to what is the beat. Maybe it's got an input in the time and so on, but this is something that we're just going to get into. Ah later, I guess. But for now I'm just going Teoh, make it very simple. It's going to be a list of integers and still, if it's zero, then it's going to be left. It means that we expect the left input. If it's one, then it's probably, Ah, down. And if it's too, it's up. And if it's three, it's right. And I'm also going to use a default, a value of minus one to represent an empty beat. Eso a beat that we just don't want to play. And so for this I'm just going to say that I want to create this a public list of integers that I'm calling beats and that's it. And so whenever I get back in here, I'm now going to create a new a game objecting here so that we can have a look at that. Have the data is represented. And I'm going to call this track a player like this, and I'm going to add a component track. And what we can see here is that this is already ah, Sarah realizable. So I can just say that I want to have three, and then the one is not to be played. And the second is to play the year the left input and the next one is to play the down input, for example. And this is this is the data structure. This is what we we want Teoh to handle as a data structure. And there's also a very important information. As for the game controller is the beats per minutes because it's going to tell the gameplay . What is the bit per minute? What is the speed of this track? And this is another information that I want to add in here, and I'm going to put it above eso that we if we have like a very long track, we don't want toe find this information all the way to the bottom. So I'm going to say public image or B p m equals and I'm going to give it a different value of 120 like this. And so whenever I get back in here, then I get the BPM information here. So this is it. And what we see here is that in this ah track component here we have all the data and we could start adding all the making X. If you were in a component based architecture, we would start adding a lthough mechanics that will display the track view and then would also addle the game play mechanics. But because we want to separate the data from the view and the controller, one of the issue that we have here is that we do know wanna have a game object for every track. Ah, that we want to be able to play. And so we don't want this script here to reference a model behavior, and this is what we're gonna be doing in the next video. We're going to change this track into a data model instead of being a motor behavior 6. Separating the data from the component: Okay, So in this video, we're now going to turn this ah data model into a real data model and totally an abandoned from the mode of behavior that handled it. So what I'm going to do here is then say that I want to create a new class of objects. I'm gonna make a new public class, and I'm going to call this track on, and I'm going to call the track data so that it doesn't, uh s so that it is in the same name is the other one and so in there and simply going to take those two lines in here. So I'm going to take the properties from there in the trade data and in here, I'm going to reference a public track trying data, which I'm going to go the track like this, and whenever I do this note is that if I go back in the editor now, you can see that everything is just going to disappear, and it's going to disappear because this track data is not survivable by default. So it means that it cannot be saved in the file format of unity and so we need to change this. I'm going to call system Sarah Realizable. And so this is an attribute that tells that this class is NASA realizable and so every properties can there be sterilized. And I'm now going to go back in the editor, And what we see is that we now have the track. And so the track is here and so we can change, uh, the perimeters that we that we had and I could have multiple tracks also, For example, I could make it a list of tracks. And what I'm now getting Teoh ad is as we go through, I also want to be ah, able to decorate this inspector a little bit. I'm going to use a header like this, which Duncan too cool laid back. I'm going to go this play that settings like this and I'm also going to add a thought it just to make sure that people users of the editor will understand what this is. And so I'll just add number off beats per minute like this. And I also want to add a range attribute so that we cannot go, for example, at zero Bittner minute and so I'm going to use it range range. It's reviewed. And so the range attribute will simply take a minimums. All just say 30 and maximum is going to be 360 Which should be difficult enough, I guess. And so that it? No, If I get back in the editor, we can see that they're gonna have the playback settings and the the tool tips. This is Ah, this is already pretty nice, though, Um, it makes it kind off difficult to save because, ah, this is all in one scene. So I could basically there The information is still in reference in the motor behaviour because the it's the money behavior that references and creates and Cyril eyes a new track data. And so this is not very handy to manipulate in the editor. If I wanted to be able to swept tracks reasonably and neither at runtime, because at one time I definitely want to be able to just keep one player and just swept the discs somehow. So I just want to be able to sweat the tracks and just not having to swap the player to swept the track that it references. And so this is what we're gonna be touching in the next video when a Baluch Annette had to Tom Lee isolate the track medal from the motor behavior. 7. Making the data a custom Asset type: So in this video we're gonna be looking at how to totally isolate the track medal from the motor behavior so that we can reference any track keeping the same one of behavior player. And so what I'm going to do here is then come back in the truck script here and basically, I'm just going to get rid of this here like this. And I'm going to take away this back into the track like that. And I'm simply going to get rid of this too. And now I'm going to say that the track is no longer inheriting from one of behavior, but inheriting from descriptive will object. Descriptive will object, represents data. So it's a Cerulli Zobel object there other ways to several eyes objects you can use XML centralization. You can also use Jason civilization if you want to exchange data. Ah, totally outside of unity, it's very easy to ah to exchange data using other formats. But the easiest way that within unity to do this in the editor in at Runtime is to use the script, herbal object and so discreditable object and lose me to create custom data within the Unity Editor and to reference them later. And so what I'm going Thio Thio do here is then if I do this, then if I get back in theatre than this will no longer work. So I'm simply going to get rid of the track player. As we can see here. The track component on tells me that the Associated script cannot be loaded because it's it's no longer a motor behavior. So no, I'm simply going to get rid of this object here. And there's a very quick shortcut that lose me to create the data. And I do this by adding the create asset menu. Ah, attribute here and there. I'm going to give it a Munyon name. And so the money name is going to be I'm just going to say unity Coach Flash beats flash a new draft like this, and I'm also hoping to give it a default fine name and the default file aim is going to be no beats track dot asset and because of this is just gonna be an asset. It has to be saved, doesn't asset. And so I'm just going to do this like that and close the attributes statement and now when I get back in here. Yeah. What you can see is that I'm not going to come in here and I can never create in the final menu here, you need a coach beats new track. So first I'm going to create a new folder and I'm going to call this tracks like this and in the tracks, I'm going to go and create a new a new track. I'm going to call this 120 bpm like this and you can see that I've got now the ability to do pretty much what I was doing before. But this is now in a data format. It's now in the file that I can later use. And I can also, uh, save this and distribute this very easily. It's very easy to handle indie editor and very easy to look at runtime now that we have Ah , this one of the major thing that we need to do when we create data model is quick ways to generate somehow fake data or tasting data because it simply just don't wanna have to go in here and say, Well, I wanna have five and the first with three is going to be minus one and so on. I want to be able to generate this thesis testing data before we create any kind of editor data loses to both or the data within the the editor, which we're going to touch on later. But I want to be able to generate some test data real quickly, and this is what we're gonna be touching on in the next video. 8. Generating random data (for testing purposes): So in this video, we're going to be looking at how to generate tasting data real quick from the editor. So to do this, I'm simply going to go back in the, uh, track model here, and what I'm going to do here is, then I'm going to start adding some information to generate this data. You would usually not put the information that generates the data in the model itself. You would put that into a netted A class because the editor class will be responsible to generate the data. And so the data should not contain the paramedic errors that you used to generate the data . Unless you want to be able to regenerate the data and you want to centralize it there quickly, and so to make it very easy, I'm just gonna put that into the track model itself and the most again to put the data generation methods in the track model itself so that we could eventually use those methods at run time and be able to generate some random fade data at runtime. But you would usually otherwise keep this out of the track. The data model to put this into edit classes that used to generate the model itself. What I'm going Teoh to say here is that I'm going to first reference a static public integer, which is which I'm gonna call input and that I'm going to make it difficulty for because I want this to be as generate is possible. And so for now we've defined that we wanted to be able Teoh use inputs to for left up and right and down so it makes four inputs. But we could possibly use different versions like a stream down versions, a simpler version with only two or three inputs or a more complicated like an advantaged Ah user, an advanced player like a pro, you pro player sort of inputs. And then we would have to handle more than just four inputs. So I need to reference the number of inputs that I want to use to generate the data so that it goes from 0 to 3. Or it could possibly go from 0 to 7 if I wanted to have, like, eight different inputs. And there I'm simply going to copy based, uh, this because this is just going to take too long to type. But let me Just explain what I've got here. So this is gonna be the pre roll. The pre roll is how maney empty beats do we want to have at the beginning of the track. Because if we don't want the track to begin with gameplay in Stanley, we want to let the player take the time to see the notes common. So this is going to be the number off empty beats not to be played at the beginning of the track. And then we're going to add notes. We're gonna add beats by blocks. And so this is how maney minimum beats do we want to have in a block. And this is how maney maximum number of beach we want to have per block. And there this is the minimum number off empty beach we want to have between blocks and this is the maximum and number off empty beats between between blocks and at the very end, wages have the number of blocks that we want to generate. So the idea here is that we're just going to make a big loop and we're going to start adding beats based on rend um, value random numbers to do this. So to do this again, I could put the randomize method. I could put it into an editor class so that it's only available within the unity aided or no longer available at for in time on and still keep the perimeters in the class itself. But I'm just gonna put this in the track for now. And so it's ah, always a handy Teoh to use this on run time if we wanted to generate some random data. So there I'm going to declare a new public divide, and I'm gonna call it Run demise like this and in randomize. The first thing I want to do is then said that beats equals new list off integers. The first thing I need to do is to reset this. Otherwise, I'm just going to keep adding to ah, the list and they're what I'm going to do here is then start by the pre roll. So for the peripheral, I'm going to make a full loop, and I'm going to say for interred your B equals zero and B being a less than pre roll and then be incriminated every Luke. Then what? What am I doing that I'm doing beats add because it's ah, it's a lists. It is very simple. And then I'm going to say beats add minus one. So this is going to add the minus one data that I want to say for the GMT beats and then we'll see later how we can handle this. Now What I want Teoh also do isn't say four and they're all safe for integer. And I'm going to call this B l Caylee Block equals zero, Then block being less than the number of blocks and again block being incriminated every time. And now I'm going to say that I want to define a new block length Like how? Maney, How many ah beats are we gonna have in this block? And so there I'm going to define the gonna call this block length and look length is going to be rend um range. So I'm going to use the random range and you can see that they're one of the things that I've seen many times, actually, uh, where people kind of that struggle is to understand that there's two implementations of the the range method. There's wonderful the floats and one for the integers and the one for the integers tells us that the maximum is exclusive. So if you say random 01 you will Onley get zero. You will never get one. So if you want a value that is randomly zero on one, you have to say random range 02 so that it will go from 0 to 1. And so there I'm going to use, uh, simply minimum block and maximum block like this And and Granger said, plus one so that we, ah, used the other the maximum value. Now I'm going to say that for integer be equals zero and then be being a less than Google claims and then the plus plus, I'm going to start adding some beats. And so there I'm going to say ended your be equals Brendan Range kind of the same thing. Random wrench. And there this time I'm going to use zero, and I'm going to use the input, um, inputs here value that have created Ah here. So this is this is a static variable so that it's shared amongst all the tracks, and, uh, we can just change it later if we want. And so there I've got this This new, uh, random number generated. And so because of the this is zero based, then I don't want to do plus one, because otherwise that would end up with, um, value. There would be out of the out of the euro and there will say, uh, beats add in there cause interest past the beat that I just created like this. And so now that I've got this, uh, what I can also do is then I'm just going to do the same thing with the interval and with the interval, I'm just gonna go this enter hole planes like this end of a length, and there this is going to use minimum interval and of the maximum animal like this. And this isn't going to use Interval Blaine's for the maximum. And there it's just We're just going to, uh, this time say that we want to add minus one like we did for the pre roll. And so what? This is what this is going to do here is then say that we're going to get into this loop here for every block that we want to create. So we're going to start creating one block, and then one interval one block, one interval, one block when interval. But we don't wanna have an interval at the very end. We don't want to end with an interval. And so what we what we can do here is then say that if block So we're gonna said if block Ah, pickles the number of blocks minus one. Then we're just going to do a break so that we break out of the cell loop. If we've reached the last block and so that it We've got this random ah generating function that we can that we can later use. And so for now, the only way that we can use it if I get back in theatre just to make sure that everything is smooth there I get to see all the perimeters that have. But that's it. The only way that it can generate this data is by using another script, that runtime. And so this is why working to start working on a custom editor to add a custom button here which loses to click on this bottom and generate that random data. And this is what we're gonna be doing in the next video 9. Editing the data with a Custom Property Inspector.: So in this video, we're going to create a custom made either for the track class that loses Teoh, Add some some buttons in here that'll is to trigger the randomized method that we've already implemented. So let's ah, go in the script here. And I'm going to create a new set folder which I'm Canticle 80 there. And it's very important to name it editor like this so that, uh, the scripts that are in this folder will not be evaluated at run time. And so whenever you build, every script that is in an editor folder will not be taken along. The building will not generate errors as you use and reference some edit classes. And in this editor folder, I'm going to go and create a new suit, short script, which I'm going to go track editor just like this. And now let's see what we can do when I, uh, get back in here when you can see is that the ah, in one of developed you can see that this, uh, object tragedy it or is now a part of the assembly. See, sharp editor uh, here and not part of the ah, the other one, so you can see that it doesn't exist in here. So it's in there. And so it will only be built for use in the editor. So what? I want to ah, to do. Here's and, uh, just add the same name space like this and like that. And now I'm going. Teoh said that this is going to be in 80 the class, so it's going to inherit from editor and you can see that editor doesn't exist for a simple reason that I've got the and the using Unity editor. And so now I can just say editor like this and with a native class, we also need to add the custom it'd or attribute here to tell what type of object it can get it And there were just going to say that it is meant to, um, it it the track like this. And now we are going to reference attract from within the utter. That's the first thing that we want to do is that we want to reference the object that the editor is currently editing. So there I'm getting to reference a new track, which I'm gonna cool track there. We have some message methods that we can use such is on enable and so on. Enable is going to be triggered whenever we select an object in the editor that displays the data. And then I'm going to say track equals and then also used Target and Target is an inherited member off the end of the class because it's just a knob Jek to I'm gonna have to cast it back to a track like this. We also what we can also do is at a an override to the method that is cold on Inspector Gree like this and on the inspector gooey. If I just do the of a ride like that and then I come back in here and now select the track . We can see that we've lost all the data simply because we're just not showing the data. And so if I want to display the data, I can simply call the bays on Inspector buoy. And by doing this, I'm calling the inherited member the I'm calling the inherited version off on Inspector Goofy. And so now I'm going to get Thea the data displayed again. And now what I want to do is to add more features to this and so to do that, what I want to do is then check if we already have some, ah bits information in the track, so I could just do if trek dot beats dot counts equals zero, then I want to do something in otherwise probably display a different message and offer different, different things in there. What I'm going to do is go and add in, ah, editor going use editor gooey layout to display a help box. And in the helm, Boggs. I'll say that the track is ng's always just empty track on this In on Pass a message tape, I'll say message type information like this. And so we can only really check this. For example, if I come back in here and I would say that I want to zero. Then I've got this information here. It tells me that the track is empty and so this is Ah, this is one thing. And now what? I also want Teoh out here isn't say on gooey layout grilling out button. And then for the people who have already used in the past the old Gu Easy Stam. It works like the glasses work very much the same as the old greasy stem. So I'm calling this method that is going to display a button and also return the state of the button whenever it is clicked. And so it'll return true when we click on this button. So they're also just said, Generate Random Trek and we'll pass a passen editor style. It is a style and use the many, but in many button style for this in. So this is going to display the button. So if I get back in theatre now, we should see this body and generate random tracks. But it doesn't do anything. It will only do something if I put all this in an if statement like this and then say what I want to do and what I want to do is and say track randomize like this. And this is the reason why I have put this method before I created The method is a public method so that it could be easily assessable from the track editor because if it was, if it were private than the tragedy of her class could not access it. And so now that I've got this. I can also just simply copy paste this and there I'm just simply going to change this and there I'm going to set a date random track like that so that we get we get a different message and there we go. So now I've got generate random track. I click on this, and as we can see, the method works pretty well. And we've got all the all the beats and the random settings, the very bottom. So maybe we want to actually take this, um, differently. But actually, what I really want is not to display all the all the beats like that. And before I do anything else, what I'm also going to to do here is then add a something very important. Which is it? Either utility and I'm going to. Usually the method is called set dirty and has the track object. And this is very important because whenever you save it, project in immunity. When you save a project and go on, do save nudged the scene but saved the project. It saves all the data that it knows it has to save. And if you change something to an object like such as a data you change. You've changed data in an object and you have to tell the editor that this object is now dirty. So it has to be saved whenever you save the project or one of you save whenever you quit the editor. And so now what I also want Teoh to do here is then come back in the ah, in the track object here. And I'm simply going to add a and the attribute here to say hide in Inspector because I don't want to display the bits Information in the inspector or at least I don't want it to be displayed just like that. So now what I really want Teoh you have here is just the playback settings, the random settings, the random generations headings and then the bottom. And so what I'm going to do Here's and go back in there And I'm also going to take the own inspector gooey method. I'm gonna take it all the way up so that it it comes up first. And so what we can see here now is that we've got this body in here now in what I can do here is started displaying the data in a different way. And so to do this, I'm going to ah, come back in here and I'm going to say that I want to have an 80 there going to use editor gree layout, and I'm going to use the big in scroll view. And I'm going to begin his cool view like this because I don't want ALS the bits to be displayed in the vory in a very long way. So I want to go to to display this, um, within a scroll view. But as we can see this cruel of you expect a vector tude to know its position. So I'm gonna have to reference here. I'm going to reference a victim, too, that I'm gonna call position like this and but there I'm gonna pass the position like that . And now I'm also going to use it Did agree lee out again. And there this time I'm going to do the end scroll view like this and in between whatever. Whatever I put in between will be automatically date out within that scroll views. I'm going to do a loop and I'm going to do the loop for integer. I equals zero. I being Liz. Then the number off beats in the tracks of beach that count like this and I being incriminated every time I want to display. So I'm going to use Editor Gooey late. Yeah, but again. And I'm going to use the indigenous lighter. So we have really different ways to display an indigenous which is a field, or pop it and so on. But I'm just going to use the indigenous later. And so the imager slander is asking for value and a minimum and a maximum value. So there I'm going to say that I want to pass track dot beats and then take ah, the current be it information. And then I'll say that the minimum value is minus one in the maximum value is going to be track dot in bitch. And actually, this is going to be the glass track inputs minus one, because it's ah tracked it in, which is a, um, a static property. So it's a sensible at the class level, not the instance level, and so that it I'm just going to do this like that, and if I get back in the inspector, then I get to see within a scroll view all the information. What we can actually not is, though, is that the scroll view is not scroll herbal. And it's not scalable because we tell it to display a scroll of you giving it a position. But we never assigned this back so and this is the way that most of the editor of widgets will work. Is that the allure you to display escrow view, given a position, and then it also returns the new position. So we can just simply update it like that. And as we're at it, what we can also do isn't say that we can. Now it it the randomly generated data. By doing this, I will simply say that we display the value. But if this land of changes, then we update devalue as well. And if I do this, then only I can now scroll in here. But I can also update and change the value if I want it like this. And so to finish this, what I'm also going to do here is then add some other decoration to ah, potentially filter the information. So I'm also going to add a new bull value, which I'm going to call display beach data like that. And in there we only want to do all this if we have some information because otherwise, if we don't have any information, it doesn't make any sense to try to display it. And so I'm going to do something like this if we want to display the data van I'm going to and getting to this. And now I'm going to and another widget, which is editor Ah, 80. There Greeley out, and it's cold, full doubt and ah, we pass it the value and we pass it simply the name. So I'll just say, just play beats like this in, of course, updated the value so it displays the value and it updates the value. If we click on it and then we say, if this is true, then we display the rest off the EU wide. So I'm going to say this comeback in the editor. And now what we can see here is that we have a nice full doubt that loses to display or not display deadbeats like this, and I can update the tracks. And so I could, for example, now go and create a new track to test this and what we can see now. Here, that's that's interesting. Ah, what we what we see here is that, uh, yeah, ofcourse, whenever we create for the first few frames that we just created Ah, this. Ah, this object, then This list has not been a shit initialized yet. So the inspector is trying to access the other property of the number of the account property of that list, and but the least has not been initialized yet. So what we can do Here's and say track. They've track that beats dozen equal. No. And the count is ah, zero and otherwise actually will just do something else. We'll just do If if this is no, then we return like this. That's even easier and safer. We just would display would display the beige on Inspector gooey. Ah, And if it's not initialized, then we just exit the method. And so let's try this again. I'm going to get rid of this and do it again to make sure just gonna clear this. Go and create a new track. And there we go little work. So and I'm going to call this 90 bpm like that and change this value here. I feel like this in there. We can see that the track is empty and then we can just go and said Generate random track. Okay, so that's it for the model. For now. In in the next videos, we're going to start working on track view. 10. Setting up the Track View component: in this video, we're going to start working on the track view. So on the view port of the model view controller, uh, pattern here. And so what I'm going to do Here's and get back in the scripts folder and at a new C short script, which I'm going to go track of you like this, and I'm going to sort it. It it now, same thing. I'm also going to put it in the name space beats this. Okay, like that. And now in here just going to get rid of all of this for now. And in here. What I know is that this component requires a few other competence to work properly. So I'm gonna start adding the require components attributes and using a type off. And I know it requires a vertical, and I don't find the vertical. Uh, simply because I'm not using the unity engine. You Why? I'm gonna add using you to the engine. You I first and then I can No, you use vertical layout group. And so this is the first thing that I want Teoh just specify. And I also wanted to, uh, use here. I know that it also requires a content common size fever, toe work probably. So I'm gonna add this so that whenever I add these component to any object and it will automatically add those components if if they're missing, and I know that it's also common and that has to be put on a, um on a u Y object. So I'm also going to add one with direct transform like this. So same thing again. Just making sure that I'm gonna have all the components and assess to access to all the comments that I need. Now what I want Teoh. The first thing I want to do here is into reference the track, of course. And for now, I'm just going to make a direct reference to to the track and we'll see that later. We want to have a new indirect reference to the track, but there I want to have a reference to the tracks and we're gonna make a a reference to a track object, which I'm gonna go track and it's gonna be private, but it's gonna be so realizable. So we're gonna use the serialized filled attributes and it's it's private because we don't want to have any other common and start to mess with. This member usually is a good idea to just use private variables. And if you want to exist, it then I had some properties, like getting set methods. But I also know is that I want to reference the pre fabs that I'm going to. Instead, she ate, such as the left up, down right objects that I need to instead she eight based on the data that I found in the track So again I'm going Thio Thio direct transform. I know that these objects need to have a red transforms. I'm just good. Instead of just referencing a game object, I'm going to reference a wreck transform So they lose me to make sure that the object that I put in has a record from component. And then I'm going to call this left like this and again, I'll use the, uh, several eyes filled attributes and there I'm just going to do the same thing with right up and down like that. And I also need to reference another one, which is going to be the reference to the empty space er or divider or you name it I'm also gonna make a reference to another wreck transform, which is going to be the restaurants from of the current object I'm going to call this are transform. Now I'm going to start adding I could use the awake method, but I'm not sure that the drive you is going to be initialized on awake and I don't I want to be able to control whenever it is initialized. So I'm gonna a new public provide method that I'm going to call bin it and it's going to be initialize herbal with a track. So that was another object, another component to initialize this track view, given it a track. And so I'm gonna call this track like this and like that and but there I'm going to add also the story message, and in there I'm going to start doing the in it and then I'm going to pass the track that I reference locally in the in this component and in there, the first thing I need to do is say that or transform equals the transform off the subject , but as a direct trench one like this so I can never go back in. The editor here, and I'm going to select the track of you, and I'm going to add the component try view like this. And there it's got a reference to a track. So there we can see that even if I click on this here, this unity will automatically show me, uh, the the serialized of objects that match the other type. Uh, here. So I'm going to choose the this one here and there. We can see that we've got left right up, down and empty. And so what I'm going to do here is they go into the pre fabs and I'm going to take one here, which I'm going to duplicate. I'm going to call it empty and showing the subject what I'm going to do. Here's and simply deactivate the image components so that it doesn't show. But we keep the wreck transform with the size, which is going to separate the other object. And I'm also going to get read off through the operable here. So to do this, probably I'm just going to drag and drop this in the tribe. You here and then get rid of the Perot. I will say that it will break the brief happenstance, I'll say yes. And then I'll click apply to, uh, date the subject here and now in the track view in the references here. What I'm going to do here is in Dragon dropped the down into the down, laughed into the left and right into the right and up into the up and the M g into the empty reference like this. And I'm now going to get rid of the prefects that I had in the tree view. So we now have everything we need to start populating the TRAV. You with the information that we've got from the track, and this is what we're gonna be doing in the next to deal. 11. Reading the Data and populating the View: So now that we've got all the references to the objects that we want to unstained she ate set up in the editor. I'm gonna go back in the track view class here in In the In its method, I'm gonna start adding the ah, the instance creation methods. So first thing that we want to do is to make a reference to a game object. So I'm gonna do a game object reference, which I'm gonna call that dreary, and then I'm going to start a new for each. It's usually said there that it's better to use a for loop than a for each loop performance ways. But as this is going to be down only just once, the for each is gonna be just is good. And so I'm going to dio integer the in track that beats. So for all the information, all the bits information that we have in the in the track I want to do I want to instance she ate a new object and there I'm going to reference a new game object and I'm going to do switch be. And so I will say that the case zero. So if the information is zero. It means that we want to do left and again, totally arbitrary. Have decided that it would be left down up rate. But it could be it could be anything. So I'll just say G equals left. And remember, the left is erect France warm. So I need to access its game object property like this. And so this is gonna be this like that. So and then I'll just do break like that and then from there again, just go and copy based company based in copy based for all the different cases. And then I'll say that if this is one or two or free, then this is going to be left down. But and right and there, instead of adding the case minus one, I'll just you use the default case. And so it means that if we for some reason we added some, like other integer numbers, that we do not support it, then we would just default to, uh, the other object and there were going to use of the empty object. So they're basically I'm doing you luv. I'm creating a new reference to a game object and selecting the game object based on the beat that I yet and now what I need to do is and simply instead, she ate this object. So I'm going to do game object in Stan. She ate and then all past G, and then I'll pass the transform. So all say, take the transform of this object like this. I'll pass the current transform of this object eso that it gets in. Stan. She hated in this object as a as a child of this object. And this as we saw, because we have the, uh, the other two components the vertical layout group in the Constant Sezer future, this will automatically set of the view. Probably. So let's try that. And so now we've got this. We've got the reference to the track. We've got the reference to all the other object. And so as I start, then I should get all the information set up. Probably now, uh, we can see this, And though one thing that we ah, that we can see is that it obviously begins by the first object. So it begins. It adds that the 1st 1 then the 2nd 1 that the 3rd 1 and so on and so on. And so the issue that we have here is that the track is somehow reversed because we started adding it by the baby via the beginning. So there are two things that we could do Thio Thio to fix this The 1st 1 is that we could simply replace the for each with a full loop in a count backwards from the end to the beginning and the other way that we can do and which I'm going to prefer because it letter a little meteo handle. The object that we created is to take a reference. So I'm gonna take a I'm gonna make a reference to a transform and I'm gonna call it the View, and I'm going to say that it's going to be equal to this that transform. So I'm making a reference to the transform off the object that I just created. And now I'm going to save you. Don't sit as first sibling like this. So it means that whenever I add an object, I will add it to the top off the of the Harrick E. And so, by doing this whenever I started this again by doing this then it will add it and take it to the top because otherwise it's added to the bottom. So I add it and take it to the top. I didn't take it to the top and so on and so on. And so this will simply reverse probably the track. And then what we can see is that the track will automatically begin by the pre roll. Okay, so now I'm simply going to reset the default position of the tribute to zero on Why? So that it begins at the very beginning of the screen and eso there again and what we can see that this three D. U. Y system is eyes for a nice really loses to say that that we wanted this screen to tell that the 100 pixels from the bottom off the screen or 200 pixels and so on and and then we really get Teoh to tell and where the where the track is going to end up on the, uh resulting two D screen. Now that we've populated the track with ALS, the bits information we want to have the track to scroll automatically Talwar at the camera , and this is what we're gonna be touching on the next video 12. Animating the Track View Scrolling: So now that we have the track view populated with all the information from the track data model, we want the trying view to also scroll automatically with time. And so to do this, I'm going to go back in the tribe. You script here, and I'm going to start making some references to its position and modify its position. The first thing that we see here is that the position of ah object in Ah, you I two d is referenced by a victim, too. But I just don't want to manipulate both continents. I just want to manipulate one of the two components said To do this, I'm going to use a little bit of, ah, trick, Teoh, make a reference to the position. So I'm gonna make a victor to reference that I'm going to call position and so it's gonna be a private by default. And there I'm going to add an excess er so I'm going Teoh do basically I'm going to do a property. So there I'm going to use a code snippet to quickly create a property and have a really touched on creating your own code templates. In my previous training there and basically, I just want to say that I want to make it a float, and ah, there. I'm gonna call it position like this, but I'm not going to use this. I'm going to use. I'm gonna make a little bit of a trick where the viable is a victim too. But the excess er is afloat in there. Whenever we access the value position, we want to return the my position. And whenever we modify the value, then we want to compare the new value to the Y position. And if it's different than we want to assign the y component of the position to value And what we're going to do here is that whenever it would do this, we want to change. We want to change the position off the wreck, transform. So I'm also do Richt transform don't anchored. Position equals and they're all go and say position. So position anchored position is a victim too. And this is what we want to update. But we don't want to update both competence. We don't want to handle the X component. We just want to handle the one component. So we make a float back, Sister which returns the Y position and that changes the Y position off the anchored position whenever we ah, whenever we change it. And so now what I want to do is ah, liver beginning whenever I, uh, initialized the view, I want to say that position equals our trains for him dot anchored position. And I do There's just to, ah to initialize it in, just in case we would have had a, um, and offset the beginning. And now when I do this, I'm also going to add a new, uh, update message doing this And there I can say position minus ical, al, just past time. Don't build a time and multiply this boy and arbitrary value for now, before we get into the game controller to define all the all the proper timing based on the bits per minutes and so on. So I'll just multiply this by two for now, just Teoh to see what this does. Okay, so we see that it's moving, but it's moving very slowly, so I'll just multiply this by 20. Okay, so it's moving, but it's against moving various lonely, so I'll just multiply this by 100. All right, there we go. We've got our preview now. Work. And I could have had a speed multiplier to the track view. But it's not the point because this track view is only going to be driven by the the game controller. And it's the job of the gun there, the game controller to tail. Would this speed off? The traveler should bay. And now the track view itself. And this is what we're gonna be doing in the next video as we're going to start working on the game controller, part of the model view controller. 13. Handling custom inputs using Keycodes: So now that we've got the tribe you work in, we want to start working on the controller part of the model view controller, which is going to control the view and the model. In this example. It doesn't have to update the model, which is part of the model view controller paradigm at the very beginning is that the controller would a day the data there, it doesn't really have to update the data. It simply has to read the data and also work with work out the mechanics, which is somehow taking us to a slightly different version of the model view controller that, like, way know it. What I'm going to do here is in create a new game object which I'm going to call game plain manager or a controller. Bring this and I'm going to reset its position on, and I'm going to add a new confident which in clinical gameplay, controller like this and they're almost looking to reposition. This is script here in the script folder and then I'm gonna start it. This this gameplay controller first thing again, going Teoh at the name space here so that old classes are within the same name, space. And now I'm going to start working on this eso I'm gonna keep the this toward, uh, message in the update messages. Well, one of the rule of the game play controller here will be to take the inputs soon enough. You want to take the inputs part out of the game play controller so that you can have a game play controller that is totally independent from the platform. And this is something that we're going to touch on in the later chapter as to have to handle multi platform inputs and management, multi platform inputs and display settings. But for now, we're just gonna put the inputs and the gameplay controller. And basically, when I want to do within, the update is to test if sexual such key has been pressed where such a such button has been pressed. And there are two ways to do this in an immunity, you can either use the input sittings or you can use a key code. And what I'm gonna do here is use a key code because it loses to use either a keyboard or a game pad as well. So there I'm going to start using a hitter and alcohol. Ah, this here. Inputs like this in their own add a, uh, new key code field, which I'm going to call left like this in the same thing. It's gonna be private, and it's going to be serialized. So I'm going to do this like this, Bruce, and and so left, uh, down, uh, and right like this. So these were gonna be my four key codes to trigger in this, putting this in the inspector, then lose me whenever I come back on the Campbell controller here. This allows me to choose which key I should be using in there. I can use the herbal keys from the keyboard, but I could also use on any other game pad, buttons and things like that. So they're going to use the left arrow and the down room and the op Arrgh! On the right road like this. And these are gonna be my in Butch. And so I'm gonna call this inputs like this in their also getting to make a reference to the track. So there again, I'm looking to replicate this and go visit the track. And there I'm going to use a serialized field put for a prayer. Viable? It's gonna be a private track, which I'm going to call track like that, and this is gonna be the reference to the track. And now, because this is the reference to the track, I also want to let other components access the track, but I don't want them to be able to change it. So what I'm going to do here is then create an excess er like this and I'm going to make it a public and it's gonna be of type track. And I'm gonna go it track like this with at the end of scored and there I'm going to implement against, but no set. So implementing you get like this. I was just saying return track. So by doing this, I I'm a lowing other comments to access this track, but without being able to change it. And so where this is something that we're going to set in the editor and that we cannot change from another competent and well, obviously change this later when we want to let the player choose a track at run time and we wanna have like, a ah track Pekar view be able to assign a new track to the gameplay manager with the gameplay controller. So what I'm also getting Teoh to do here is that add a This is another quick trick here, but I'm going to add a new, uh uh, summary here. So this allows me to, um, gets, um, uh, information as to what this property is doing here. So I'm just going to do this. I like that. And I'm going to call this the current track event. And so if I get into another component than I want to know what this track property is, then I, uh this is this is the information that I can get. It's pretty much the same thing is a tool tip or so when I do tool tip like this and said the tool tip for beats track to play, I think that. And so this is going to show up in the editor and this will show up in a motor behavior whenever I come in over a property. There's another thing of the day want to do just to make thinking very tighty. I'm gonna use a region. And so I'm gonna call this the moto be behavior, uh, methods like this. And there I'm going to end the region like this. What a moments we're going, Thio added later, is another region so And I'm going to call this gameplay. So I'm going to split this into different regions, regions or reverie, Handy as you can later going here and then choose a region. It's like shortcuts that take you to different regions in the code. So what I'm going to do here is then say that I want to have a new method and I'm gonna call it, uh, plate beat like this and it's going to take a and in boot, which is gonna be an integer. And then I'm going to add a debug log off that input like this, and now I'm going to put in the date. I'm going to say, if input, this is the input class of unity get key down. Which is is that key being pressed on that frame and not in on Lee The first frame that it was pressed and they're all say left like this. Ah, Then I want to say play beat in all pass zero, because the left key is basically the matches, the other the zero. And so I'll do the same thing with all four. And so all say one to and three. And this is going to be down and, uh, and right and there I also have to ah, end this region with n region and not another region and region like this. Using regions is very, uh, yes, full. Whenever you know that your class is gonna have, like, a different set parts off making exit is the motor behavior and the gameplay. So there I'm just want to separate. What is the initialization part? And where is the gameplay specific methods and members just splitting this into two different regions. But this is just really just to help me eso this out in when in the mornin develop. So now I'm gonna get back in the editor and there I'm going to reference a track. So I'm going to reference the same track as I have in the, uh in the tree view like this I'm gonna save, and then I'm going to start playing. And there if I pressed the keyboard arrow keys, then I get to see that I've got this debug output here, and if I double click on it, it'll take me in there. So I get to see that this is triggering the play bit method on display. But method is going to be the method that I'm going to add Maura code into. But in the update, I don't have so much code to add. I'm just taking the inputs and then passing it into the play bit. This is somehow some pre work, as I know that later, I want to take this apart into another component outside of the gameplay controller. So now that we've got this, uh, those inputs, we want to add the mechanics that said that every beat moves on the next beat and then we want to make sure that whenever we play something, whenever we press and input, we want to be able to ask the question is the input that we just pressed, the one that is to be pressed now and this is the making X that we're going to start adding in the next to deal 14. Implementing Gameplay tempo mechanics.: in this video, we're going to start working on the beat management off the gameplay controller. So what we want to do is Teoh keep track off which current beat has to be played on eso for this. What we're gonna do is that we're going to start working in here and we're gonna start. I'm gonna add a new, uh, method here when sure I'm gonna call a vote, I'm gonna call it next beat. And so basically, this method is going to, uh, step to the next beat every time I call it so And there I'm gonna go and put a debug log in there, and I'm going to simply debug this saying tick. And so from there, what I want to do is then Now I wanna go back into your I'm gonna behavior methods and then in the story I want to use invoke here, I want to use, invoked, riveting and in vogue, rebutting. I'm going to say that I wanted to go for next beat, and there I want to be careful because this isn't so safe, is we're using some text, and so they're basically I'm going to say that I wanted to be called Avery beat. So for now, let's just do a quick test and saying that we wanted to start right away and then we want to call it every second. So basically, we're passing a perimeter for the interval as to, ah, the frequency that we want to call invoke repeating at. So now let's go back in the editor and let's see how this works. All right? And so what we can see here is that we now have one tick every second. So now what I want to have is some quick successor to theme the number off seconds per beat and the number off beats per second that I can use. And so what I'm going to do here is ah, simply do a couple of ex sisters. I'm gonna make a public float, and I'm going to go this seconds per beat, and this is going to have to get and a private set so that I can modify it within the instance. And on Leigh read it from other classes. And there I'm going to do the same thing here with another one that I'm going to go beats for a second now I want to initialize those values. And so for this, I'm going to implement the awake method like this and in awake, I'm simply going to say seconds per beat equals track. And then I'm gonna go get the track bpm information, and I'm going to divide it by 60 like this. And so, basically, how many seconds per beat? It's the number of beats per minutes divided by 60. And then how many beats per second, then this is going to be 60 divided by the track that BPM. And so these are going to be quick X issues that we can use in other components to simply refer to the number off seconds Perbet in the number of bits per second. And there, Now, I can use this and say that I want to use beats per second. And actually, I'm gonna have to, uh, rename this and so I can now go back in the editor and try this out. And there we can see that it goes a lot faster. As we've said, the number of Pittsburgh minutes 220. So we basically have a tick. Every health second. Now what I want to do is to implement a another Exeter, which allows me to access the current beat that I should be playing. And so to do this, I'm gonna go back in the game, play region, and I'm going to add a new properties. I'm going to use my property exist, sir, and it's going to be of type and injure, and I'm going to call it current like this. And so what we see here is that when we do get, then we simply return the value of the variable. And when we do, A said, we make sure that the values changed and then we re assigned the new value, and I also want to see if we have completed the track. So whenever we reach the end of the track than I want to be able to cancel the invoke and also, uh, stop the gameplay probably in some sense, um, events later to say that we've finished the track. So what I'm going to do here is in first, say if, uh current is equal to the track. Bitch. Count. Then I want Teoh use. Cancel, invoke, and then I'm going to pass, uh, the next beat method and I also want to store some some value to say that if we have completed the track then later I want to be able Teoh, use a simple Boolean just said If we have completed then I no longer want to take the inputs into one. So what I'm going to do here is then had a are private bull that I'm going to go completed and in there I can now say we cancel the invoke in. Then we say completed equals two. And now that I've done this, every time we call next beat, what I'm going to do now I say currents plus plus And so this is going to increments the current beat to be played and then this is going to trigger all the mechanics that we want Teoh use later. So now that I've got this, I want to make the match between the beat information and the inputs that we're getting from the date and this is what we're gonna be doing in the next to deal 15. Implementing Gameplay input controls.: So now that we've got the beat Tickin, what we want is Teoh dignity, inputs and make the much between the inputs and the current beat. The first thing that I'm going to do is get back in the game, play controller here. So what I want to do in the next beat is Teoh know if the player is played and if it hasn't played then unless it was an empty beat, then I want to log some missed information. I want to say that there was something to be blade and that we missed it. So what I'm going to ah do is then come back here and also add right before the completed I'm also going to add another 1,000,000,000 that I'm going to call, played and like this. And now with this, I'm going to say that if no played like this and I'm also going to say track and there I'm going to go get the beats and there I'm going to pass the current beat. So the one that we were supposed to trigger does not recall minus one, which is the value that we have assigned the empty beats. Then I want to log some information that says that we, uh, that we have missed what I'm going Teoh to do here is and say D bog debug log And in the typical, I'm going to use the string for Mitt Method in which we're going to past here. Uh, a key word of this and I'm going to say, missed just to say which which bit was missed. And there I'm going to pass it the trek that beats and current so that we know if we missed ah, left and the right or a knob down and so on. And so like this. And then Now he also want to say that played equals falls like this Indictment Teoh to put it this way. And so now that I've got these played 1,000,000,000 information, I'm going to use it to filter in the date so that I make sure that we cannot play twice within the same beat. And so to do this, it simply going to say, if played like this or uh, completed, then I simply want to return and quickly exit the update. Inter. Now that I did this, I'm going to also go back in the blade be, uh, method here. And basically, I'm going to say that if for the trick the bigs and using the current it calls minus one, then basically we played untimely. We played as we were meant not to play. So I went Teoh, I want to look something here. And I'm also going to say else here else if and there I'm going to say that if this equals the input then we played the right the right combination in Otherwise it means that we played. But we played the wrong combination. And so I'm simply going Teoh, take this. Uh, here and I'm simply going Teoh copy Paste it like this and like that and I'm going Teoh, use it here and there. I'm going, Teoh simply pass the input like this. And I'm going to say that we played on dying really like this and in this one, working to say, played right and there were going to say laid and we're gonna pass the second arguments and we're going to say expected this. So we're gonna say that, uh, which one was played in which one was was expected, And so we're gonna pass input and then uh, the current that we have here and there. I'm going to simply basking input here. So basically, if it was minus one then and we played, then we simply say that we blade untimely. And then we logged the in. But otherwise it's if the current is the input, Then we played it right. And then we display which one was played, right? And then if we, uh otherwise, then we show which one was played, and then which one was expected? And so this is this is what we need for now was for the controller. And then we'll later make the match with the traveler so that the track view shows us shows the player if it's played the right beat or not. So I'm now going, Teoh, test this rule quick. And the editor and so there. We can see that we've got a, uh, left to play first so I can plan right up, up, and then we see that we, uh we get the message is in here. I obviously missed a lot simply because of the track view Is not playing at the proper speed. If you remember. Well, we had the track view to play here at an arbitrary speed. So the gambling controller and the track view are actually not quite. Sink it. And this is what we're gonna be working on in the next video. 16. Sync'ing the TrackView with the Controller track.: So in this video we're going to start linking the gameplay controller and the tribe You. And so the first thing I want Teoh to do here is to complete the gambling controller and by making sure that it stops whenever it reaches the end off the track. I wanted Teoh just top. So what I'm going to do here is at a and I in a Meritor that I'm going to use for a courage in because I want the I wanted to stop at the end, but I want Oh, I wanted to wait enough time so that the tribe you completely goes out of screen. So what I'm going to do here is and say that I wanted Teoh to yield And so I'm going to either. Here, um, simply going to add a private wait four seconds, which in grand ducal wait and stop like this and in awake, I'm going to say Wait and stop equals new Wait for seconds in all pass here the simply the bits per second times two so that it waits for two beats and I could just use different information. I could use the number of beats in the patrol, for example, or something like that. And so I'll just, Ah, come Mai here and then say that I wanted to yield return, Wait. We didn't stop like this and then also be enabled, equals falls so that it turns itself off whenever it's finished playing the track. And now what I'm going to do here is then said that after it's completed here, then I'm going to say Stored co routine in their all Pass the weight and stop, wait and stop Make it here. So now that I have this, I want to be able to fully bind the track view with the gameplay controller. And there's whenever you have two components in a dependent architecture, you have one component that is dependent on the other. You don't wanna have mutual dependency, and it's always better when you do not have a competent to assign another or create another . And it's always better when one is simply saying that it will look for the other one, and it will eventually subscribe to its events and things like that. So for this, what I'm going to do is that say that the game pulling controller is most probably the one component that will always be there. This is the one that references the track, and this is the one that will dictate most of the behavior of the gameplay. So this is the one that we want to have all the time. And so what I'm going to do here is then said that I want this to be a singleton, and this singleton is another paradigm that is totally compatible with any other design pattern. Actually designed patterns are just like references, and you can modify them and make them somehow the way you want there, just like patterns and just like fixed architecture that you cannot modify. So what I'm going to do here's and use a a quick, ah, good snippet that I'm using here and which will lose me to say that I want a gameplay controller, which is the instance. And so if we have a quick look at what it does here is that it references a static, uh, reference to a gameplay controller, and whenever we access it, whenever we gonna access the instance, then it will go. And if it doesn't already exist, if it's not already assigned than it's going to go and look for one in the scene. If it doesn't find one that is going to go in, create one. And so creating one here doesn't make so much sense because it requires to have information such as which track it has to play and so on. So I'm simply going to get rid of this and simply say, um, they're here that I want Teoh get rid of that and they're all just say, if the instance is no, then I want to go and find it in this and that's it. And then I want to return it. And this is Ah, this is like some very common better. Ah, here. And what I want to do here is and say that I want the instance to equal this in awake. And so this is what I'm going to do here, what you got And one important thing is, ah, when you do ah, single dense is to make sure that whenever you unloaded, seen, for example because you load another scene or something, then you want to make sure that when you do undistracted and actually I used on disabled, But I'm going to do on destroy instead on destroyed than instance equals no. And then I'll just use the underscore one So that I can get rid of the SEC is that I don't want any other component to be able to change the instance to the gambling control of the game play controllers set up in the scene. So let's just quickly go back in the editor here and make sure that we are that everything runs, uh, smoothly, all right. And now what I want to do is then go back in the track, you here. And so instead of having to assign a track viewer to assign the gameplay controller to the track view and say, Hey, track view, this is the gameplay controller and on the other hand, I would be doing like an Gimpel controller. This is a track view. I don't wanna have to do all this kind of bindings. I wanted to be automatic. So to do this I know the traveler will never exist without a gamble controller, which may not be true. In the other way around, we may have a game played control without a track view, but not the other way around So what I'm going to do here is then say that I want to initialize whenever I'm going to go in the initialize here, I'm gonna go into start. And for example, instead of initializing the track view with its own track property, I'm gonna go and say gameplay controller dot instance dot track. And so it's gonna go and find the instance of the gameplay control and then find the track property. And so which lose me to simply get rid off this manual track reference that I had so far here. This is pretty, uh, very useful pretending because I don't wanna have to handle different track informations. One in the drive, you one in the game controller and so on. Within the method, I went to reference the size off one bid view and the size off the spacing because I know that the beats in the tribe you can be laid out with some spacing. So what? I'm going to ah, to do. Here's and simply say that after this position here, I'm going to add a float which I'm going to go beat, Have you size in another one that I'm going to go spacing like this. And whenever I initialized this, then I'm going to say bigger size equals and I'm simply going Teoh, use the empty and I'm gonna go get the direct information here and the height of the rectangle off the empty transform. And there I'm going to say that spacing equals get component and they will pass. Uh, here, Vertical only out. Doug. Spacing like this. And I know that I've got averted a little layout group because I've added before the you require component vertical layout grip. And so I'm taking the spacing here. I'm assigning the other the spacing, flood value and the big view size. And so basically, what I need to do here is then say that using the time Delta time, I also want to multiply this My I'm actually going to multiply this by Campli controller. Instance Dodd seconds per beat. And I want to use the seconds burbey because I'm going to use the beat, view, size and the spacing together, which is the amount of translation that I need to do whenever we move forward of one beat. And so I went to multiply this by the number of seconds per beat so that we can multiply this bite the Delta time. And so we should get a a translation that follows the, uh, the proper speed. And so there I'm simply going to say, uh, Biddy Assize plus spacing. So now let's go back in theatre here and let's have a quick look at the tractor component here and we can see that the Tribune only references a track. It will automatically find the game controller and bind itself to it and find its track property. And so now, if we do this, we should see that it takes probably, and the speed I should be able to get a lot more right combinations that before. So now, instead of relying on the console to see if we've played properly or not, we're actually going to make it so that the track view displays and changes the display for every beat. When, whenever we play them properly or not, and this is what we're gonna be doing in the next video 17. Adding the Gameplay visual feedback.: in this video. We're now going Teoh a day, the view with events from the gameplay controller. And I'm going to stay away from the sea Sharp events for this training course, and I'm going to touch on that in a later chapter. But basically what we want to do here is that we want to try view to be notified from to to receive notification from the gameplay controller whenever we've played something, whenever we've missed something and so that it can update the current you and give the feedback to the player as to whether his, uh, missed or played probably or just played the wrong. But so what we're going Teoh to do in here is first of all, we're gonna go back in the track view, and I'm going to add a new, uh in elm. And so I'm gonna add a Nina Teoh. Uh, here, this I'm gonna make a publication, Um, that I'm going to call Trigger. I'm gonna make this this trigger so that it can be of different types. It's just missed or right or wrong. So basically, we're gonna have some very basic information to say. Whenever with played something right or wrong or whenever we've missed something and then I'm going to add a new ah method here, I'm gonna make a new public method so that the game controller can access it and it's gonna be, ah, avoid method. And I'm going to call it trigger beat view like this, and it's going to take a an integer for the index because this is what the game controller knows about, uh, all it knows is ah, the current beat. And so what? We want Teoh to pass that, and we also want to pass a trigger. So I'm simply going to pass the trigger type here like this. And in there I'm going to make a switch and a switch based on the trigger. Think this and say case trigger missed. And they're what I want to do like this in case trigger right whips missed and trigger right and break in case again, trigger wrong and this and break again. Now what I need to do is to reference the image component that I know exist on the beat views the the pre fabs that we've instead shooted in the tribe. You Well, what I'm going Teoh do here's and come here. And I'm going to add a new list off image compartment like this, and I'm going to call this bit views. And when I come to the initialization here, what I'm going to ah, to adhere is a, uh, bid use equals new list of image like this. And there you see that I've already got the reference toothy instance created object, and I'm creating a reference, a direct reference to the transform component. But the transform component has already a successor on its very easy to access. So instead, what I'm going to do here is and say that this is going to be an image and there I'm going to say, get component and pass image like this and say that I now want to take this instance created game object, and then I want to get to the image component that is on it from there. When I can say is view dot uh, transform dot set s first sibling. That's very easy. And now with this, I can also say biff views that ad and then I can pass the view which is now of type, uh, image components. And so there I'm building this list of image component from there, and so is it's very easy for me thing to do, to reference it later. And so what I'm going to do here is that say that if we've missed, then I want to go into the big huge and I want to past the, um, the index that I'm given and then I want to change the color component that change the color property of that object. And there I'll just a collar that gray. Let's say that we turned them gray when we miss them, and then I'm going to do the same thing here. When we get them right, I'm just going to say yellow. And when we, uh, play the wrong bit, let's just use another corner that we haven't used till Forest, which is a Salyan. And so with with all this the that, the track view is now able to excess individual bit views that are simply just image components, the image components that are on the pre fabs and change the colors based on a trigger type , which is an annum that we've added here. And so now I can go back in the game play controller and in the gameplay controller. What I want to do is to create a quick reference to the tribe you. So I'm going to come here and I'm going to add a new, uh, dragged your reference like this and I'm going to call this trey view, and then I'm gonna go in the wake goal here and in the awake. What I'm going Teoh to do here is that it's a track view equals find objective type in the Hollinger's past try view. So basically, it's saying find the first try view that defined in the scene and that it and then what I can also do is ah then say if, uh, track view here, I'll say it just if not, try view, which basically says, If trav you is no, then I want to issue a debug log warning so that, uh, we know that there's no track view in the scene, So I'll just say, uh, no Frank view found and the current scene like this. All right, so this is Ah, this is just a safe way off of doing it in a later chapter. Altach on C sharp events and all touching on all the bindings that we can that we can do in . Basically, what we would actually want to do is to use events so that the track view subscribes to the game play controller and so that the gambling controller Newton and doesn't even have to know about the track view. So this is this is even better to do. But in a proper model view controller there it's It's ah, usual that the control and news about the view because it's their old tight to each other. And so now that I've got this, what I'm going to do is then come in the next bit here where we see that we've just missed the bit and they're also a track for you, and then I'll just go get the message. There's a method that I have here Trigger bid you and then all pass the current, which is the current beat that we were supposed to play and then pass. Trev, you try view trigger mist like this, and then I'm going to do the same thing when we also play the beats here. So obviously, when we play untimely, then there's there. There's no there's nothing to show. And then maybe we would like you to show something else. But this is something that I'm going to talk young deeper in the later chapter as to manage the other. The visual rewards and also audio rewards that you want to give the player whenever the player plays properly or not. And so in there. I'm simply going to say that there we've played the right, uh, bit here and there. We've played the wrong beat here. And so what happens here is that we excessive the track of you whenever we initialize. Then we we find the first traveller that we confined in the scene. And then whenever we play, we go when trigger the big view. And so the Trevi will receive. This message will receive this this coal to this method and based on the type of trigger, it will change the color appropriately off the current beat. So let's check this out. And he had it works. One of the things that is pretty nice that we can do about this is that we could also say that whenever we miss, for example, I could add a d bog break, So let me just do this. And then So this means that whenever we hit that debug break, it's going to put the editor on pause, just like if I had clicked on the pause button here. But it does this automatically here. And so what we can see here is that basically the trigger zone that would display is just ah, a little bit. There's just a little bit of an offset. And we've just placed it in a way that tells of the player that his meant to play were. In fact, he has just lost his just missed. And so this is Ah, this is the mistake that we had. So they're just going to move this about the size of the trigger? Uh huh. Like that. And so I guess that now I should be able to, uh, play this with that missing anything. So there we go. And actually, what we just saw is pretty interesting is that as you can realize, there I've got a little about is I've played it, and yet it goes, Ah, on a break. And this is ah, simply when we Ah, this is simply about this. There you can see that that when I whenever I play the beat, I do not set the played viable to true, which causes it to actually said that we haven't played whenever we reach the next meet. And so what I need to do here is then say played equals true in the play, but method. So I've done. I've done this. And so now what I'm also going to do is simply get rid of all these, um, the bug logs here as I don't really need them anymore for now. So I'm just gonna get really awful this and I'm gonna go back in the tray view here. I'm going to get rid of that D book right here and now I'm just going to try this again and that we can see that it's played right. Missed, missed on. Let's try to play it wrong there. I'm just going up, up, up, up, up. So and I'm doing just up so that we can see that whenever I reaching up. Then the turned the yellow, which means that they've been played probably, and other ways they turn Zion, which means that there were played wrong, and if I just don't do anything than the train gray, which means that they were missed. So this is it for now. And in the next video, I'm just going to do a quick wrap up on DSM up off all that we've touched on the training and I'm also going to touch on future training is coming on the same project to take it further. 18. Course Retrospective: so to wrap this up, let's review what we've learned throughout these. Of course, we've had a quick overview of the different model view controller like design pattern. Such is the model view controller, as well as the model view, view model and the model View presenter. And then we got into this and saw how we put this into unity. We saw that the model class Onley stores the data and that there's noted to make it and motor behavior, that it could be a serialize herbal class and that deriving from script herbal object offers is the convenience to handle data within the editor and that it's, ah, lot easier than having to manage Jason or XML civilization. We touched on the view class and we saw that the few class only displays the data, so it makes sense to make it a motor behavior. It could also be a U. Y behaviour, and we saw that it updates when the data changes or it can also receive events from the controller. Then we touched on the controller itself. We saw that only is meant to manipulate the data that it can handle the input, although that in a multi platform scenario. It is recommended to separate inputs from the controller and that it can reference the view , although it's preferable to have the view subscribe to its events. And this is something that we're gonna touch in a later chapter on Lean All we saw that design patterns are only suggestions there, just religious patterns. And that being said, we saw that we could create our own pattern here, where the model does not update the view. It's the control of that updates. The view and the View will simply take the data from the controller and will update from events sent from the control or so to go further. You can subscribe to my newsletter and receive exclusive offers. Union also join Unity Workshops Group on Facebook, and if you want to follow me on Twitter, it's at Unity Coach on Facebook. Same thing at you need a coach or Facebook that comes last. You need a coach and in the unity community, or such as answers collab and Connect, you'll find me with AD. You need a coach or a friend room until next time. Thanks for watching 19. Refactoring.: in this video, I'd like to bring if you fix to the scripts that we ended it with the end of this chapter. The first thing that I wanted to point out if you Dan, with the final project, you've probably already noticed those fixes here. But remember that I was using here in the on Inspector gooey Method A was using this Teoh, actually prevent the error that we got when that we created a new track in the Inspector. And in fact, I realized that initializing this list here the very beginning simply gets rid of this error in exactly much simpler. Teoh, do it this way. Another thing that I want Teoh point out. And that is actually being brought to my attention by one of the students here on you dummies, thanks to John who, uh, actually pointed out that seconds per bid and bits per second or actually swapped. So even though we used them in the right places in the proper voices which say's that it works, probably the meaning that they the carrier is actually swept. And if we think about it like bits per second is actually how many beats in a second, so it's not 60 divided by the number of bits per minute. But it's the number of bits per minute divided by 60 and voiceover says seconds per bid is actually the other way around. If it was the value that was actually reversed, then I would simply change the sign in here, and that would be pretty simple. The thing is that there it's just the it's just the name off, the viable, so everything is fine. But the name of those variables and access er's are actually misleading. So we we want to rename this and so to do this, what I'm going to do here is to use one of the feature that is pretty powerful in modern developed that's called a reflector. So I can right click on this and go and say, rename when you do this on something that is actually private or that is within this class . So, for example, if I was to do this on, uh, the instance, then I would get this. I would get a simple rename because this does not exist and cannot exist because simply because it's private, so it cannot exist anywhere else. In another class, and then I can just simply rename this and it's going to rename all the occurrences off this thing's name. But there, what's a little different is that this is probably used somewhere else, and it actually is. We know that it's used in the track view where we use it here as seconds per bid here. So what we can do here is I'm actually going to close this file here, and what we can do here is that simply highlight this and then simply go and say rename. And when I do this, then instead of just renaming all the organs, is within the final. It's going to prop up this dialog where I can change the name and they're what I'm going to do here isn't if I change the name for bits per second that I would end up with two properties bearing the same name, and then I could no longer renamed the other one. So what I'm going to do here from now is simply at an end of score to this one, and I'm also going to copy this and then I'm going to say, OK, now I can do this here I'm going to go on, do rename and then I'm going to rename this two seconds per beat like that. And then now I can go and rename the other one and rename it as beats for second. Well, like this. And then it's going to rename this everywhere in the fire, but actually everywhere in the solutions we find up in the track view again. Then there we can see that where I had seconds per beat. I now have bits per second instead, and this is why I closed the file before I would do it before, because if I did it with the final Open, it would actually have done it. But then, very oven. You want Thio Thio have it not have Teoh to save the file that it's changed. If I had done it like actually I can do it. Just Teoh demo the purpose here if I do this here like this and I renamed this with like a couple of underscores behind. What you can see here is that it's changed this file, but it hasn't saved it, so if I never go back in the unity aided or very often you'll end up with an error because you save the file that you've modified. But you didn't save all the other fires that it's modified automatically. So and also when Nice thing is that you can actually do this in any file. So you do not have to do this in this fine here. You can also do it. Think they're so there. I can simply go and say rename and then remove the into scores and then it's going to do it the other way around. So this is, Ah, very powerful feature that I wanted to show here in this video. And so again, thanks to John, who actually pointed this out, it was my mistake. Eso It's now fixed and I will abate also the files of the final project and the fathers of the other chapters of this training as well. So as always, Thank you very much for your feedback. And thanks for watching