Transcript from the "Collectables" Lesson
>> So we'll save that. And now we need to add that script component to the player. So we'll go to the player here. I'll scroll down to Add Component, and we'll add this score script. And right now that's not going to do anything. It's not gonna change the functionality of the game in any way.
[00:00:24] But it's something that we'll need later. So let's keep moving. Collectibles, we created that tiny sphere that is going to be our collectible, but now we need to actually collect it and then move it around when it gets collected. So how are we gonna do that? Well, when another game object with a score component basically intersects with a collectible component, it's going to call increment score method.
[00:00:59] So when the player or the opponent runs over that trigger collider that we created earlier on the collectible, it's going to talk to the score component on the player or the opponent and call that increment score method to increase it by 1. And then after it does that, so that's this line right here where it says other.gameobject.get component, score, increment score.
[00:01:27] After that, we need to move the position of the collectible to a new location on the game board so there's a new place to chase it. And that's what this code is doing here. So we'll type all of this up in a second and look at it in more detail.
[00:01:43] But one thing I wanted to call out, and this could be a way that maybe you could improve upon this game after completing it. Is that admittedly spawning the collectible to a new random position on the board will sometimes result in spawns that might just be directly next to one of the players.
[00:02:06] Or in a spot that is maybe, say, right next to where the collectible was previously. So it'll still be on the game board because we're kind of bounding that to a range within the board, but putting it in just any random spot on the board is not necessarily the best approach.
[00:02:31] I mean, over the time span of a minute in a game where there's two players moving around, generally kind of evens out from a game play perspective. So it's not a huge deal here. But one approach to improve this, and maybe production ready game, is to have several predefined spawn points that would be transforms on the board.
[00:02:55] And then look at those in a list, and always choose the spawn point that's furthest away from all of the parties that are playing the game, right? So that's one approach. You could also just have predefined spawn positions that you pick randomly. You could just look at the position of the players and actually calculate a distance that's always a fixed value from all of them.
[00:03:22] A lot of ways to do that, but we're just gonna pick a random spot, it's fine. So let's go over to Unity and let's create the script. So in our scripts folder, I'm going to again create a new C Sharp script. And we're gonna call this collectible. And I will open that up in our editor, And don't need these namespaces at the top.
[00:04:00] We don't need the update method, but we are going to use the start method here. So first, I'm going to create a private float value called range and set it to 0.4 as a float. So the range is going to be the x and z range, positive and negative, in which this collectible can spawn.
[00:04:31] Now, why is 0.4? Well, the game board, if you recall, is a cube in Unity. And the cube has a size of one meter cubed. And if we're spawning in the positive and negative x, and the positive and negative z, then we actually want that to be something like, say 0.5.
[00:04:57] That's the size of the game board. We don't want this collectible to spawn at the very edge of the game board though. So we wanna set it to 0.4, so that it's just constrained a little bit to the board. So that's where that magical 0.4 number is coming from.
[00:05:16] So then I'll create a Vector 3 called start position. And that's going to be where the collectible is starting. And we wanna record that for when we reset the game. So when you hit the space bar and reset the game, we want that original position. So we'll record the starting position by recording the transform position.
[00:05:42] So this is very similar to what we did in the rolling movement script. And then we want another method that has a return type of void. And this method is going to be called onTriggerStay, and it's going to take an argument of a collider. And we'll just call that collider other.
[00:06:09] OnTriggerStay is a method on the mono behavior class, and it's part of every game object in Unity. And onTriggerStay is used to detect when a trigger collider is staying inside of this game object's collider. So this is the method that's detecting physics collisions. I should point out that there's also onTriggerEnter as a method, and there's OnTriggerExit.
[00:06:46] We're not gonna use those, but onTriggerEnter and onTriggerExit allow you to detect when a collider has entered a trigger collider, when it first hit it, and it will trigger once. And it also detects when a collider exits a trigger collider. So why are we using onTriggerStay, right? Why don't we say onTriggerEnter so that when it first hits the collectible, it gets collected and that's it?
[00:07:15] Well, it's because of how we're spawning these randomly, right? We're spawning these, they could spawn anywhere on the game board. And it could potentially spawn inside of one of the other players, in which case we want it to just get collected immediately and spawn somewhere else. Not really fair in terms of the game, but for simplicity that's how we're gonna do it.
[00:07:42] So onTriggerStay will avoid kind of just weird scenarios where it spawns inside of a player but doesn't actually get collected. So, inside of this method we want to do a couple of things. I'll write out a comment. So if the other game object has a score component, increment it.
[00:08:09] So there's this argument here, collider other. Other is the collider or the base class for colliders, and that's box collider, sphere colliders, and that's in Unity this thing. So on a player there's this sphere collider, right? That is actually inheriting from a parent class called collider. And so when onTriggerStay gets triggered by in this case one of the players in the game, that other collider is going to be the player or the opponent.
[00:08:52] That's the other, that's the thing that's colliding with the collectible. So we want to get other game object. We wanna get its game object because we want to look for components on that game object. And we're going to call get component and we're looking for the score component, okay?
[00:09:18] And then we can continue just chaining these methods. So once we have the score component, we want to call that increment score method that we wrote in the score component. So when a player hits the collectible, it will look for this other thing that's hitting it, the player.
[00:09:43] It's gonna find its game object. It's gonna look through its components, it's gonna find the score component. And then on the score components it's calling increment score. So that all happens in one line. Then after that's happened, we wanna move the position of this collectible to a new random position within the board bounce.
[00:10:06] So we already set what that range should be, but we wanna move the transform position of this game object to a new Vector 3, we're moving it to a new 3D position. And we're going to use a function that will generate a random number. So we're gonna call random, which is a class, and we want to call random.range, not random.random range, which is a deprecated method.
[00:10:42] So, random.range, okay? And we want that random range to be the negative range that we set and the positive range that we set. So that's going to create an x value for this Vector 3 that is somewhere between negative 0.4 and positive 0.4, okay? So what about the y position?
[00:11:13] So I typed a comma there and I went on to the next line here. Where should we put the y? Well, we already have the starting position. We could put it there, but the y position of this is never really going to move. So we can just call transform.position.y, and just use the one that we already have.
[00:11:38] It's the same thing really because, again, that y isn't going to move. So finally, for the z position, same thing. I'm just gonna copy and paste what we have in x and put it there in the z, because we want that same random range of -0.4 to + 0.4 but in the z space.
[00:12:08] So there's one more method we need to write. We need to be able to reset the position of the collectible whenever we might need to, such as when the game restarts. So I'll create another method here with a return type of void, because this is going to be public.
[00:12:25] Because this is going to need be called when we have input such as hitting the spacebar to reset the game. And we'll set the transform position to the start position. So you'll notice that this is the same type of pattern that we used in rolling movement. We get the start position in start, then we reset the position in reset position.
[00:12:55] And reset position by the way, that is not a special method name that's on mono behavior or anything like that, that's just what we call, but that method could be called anything. So there is the collectible script. I'm gonna save that, and we need to apply it to the collectible.
[00:13:20] So I'm gonna switch back to Unity. And on the collectible theme object, I'm gonna hit Add Component and I'll type in collectible. And it will add that script. There's not really anything on that script that we need to modify. So we can just leave that as is. And now when we hit the play button and we roll around, we should be able to collect this and the collectible should spawn to a new random position.
[00:13:57] And theoretically on the player component this is incrementing the score value, but we don't have any way to see that yet. That's where UI is gonna come in and allow us to actually see what's going on. But that's what the game should look like right now. One thing I did not mention earlier that is really cool about working in Unity, is that you can modify inspector values while the game is running.
[00:14:28] So on the player game object, you'll recall that we do have this speed value that we can adjust in the rolling movement component. If I set that to something like 0, sorry, if I set that something like 2, instead of 1, the player will move twice as fast.
[00:14:54] If I set that to something like 0.1, the player is going to move really slowly because it's multiplying by that movement factor. But you'll notice at no point did I stop playing the game and I was able to just modify that value. Something that's really important about serialized values in the inspector when you're modifying them, is that they will not be saved when you come out of play mode, okay?
[00:15:22] I'm gonna say that one more time cuz it's so important. So I modified this value, originally it was 1. I can change it to anything else like 2 and make the player move really quickly. But if I hit the play button again, it's going to lose that value.
[00:15:39] It's gonna go back to the default. So if I hit play again, you'll see that that speed value is now 1. So that's very important when you're tuning the game. If there's values that you wanna change and you're kind of experimenting with things while the game is running, you wanna make sure that you're writing that down.
[00:15:59] Or copying and pasting those numbers, or something like that, and saving them. There are a lot more advanced and sophisticated workflows and architectures that you can work within Unity. One of them is called scriptable objects, where you can save assets on disk and that kind of like play mode thing where it resets values doesn't happen.
[00:16:20] But that is kind of beyond the scope of this. Generally speaking, when you're changing inspector values, they're going to go back to the defaults when you come out of play mode.