تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Design Player Display0:00

To get us started with our game board, I'd really like to display to the players who they're playing against and whether that player is online currently or not. It will allow us to get everything set up ready for them syncing moves in the next episode. We'll start by hard coding the Idea and then we'll fill it out with real information in a moment. So player 1, let's make this list item flex, item-center. And what do we need in here? Well, we'd want a span that would indicate whether you're crosses or not. So we'll start with a span that just has a cross in it. Then we'd have a second span. This would have the user's name. We'll say testUser. And finally, I want a little indicator light that essentially would tell us whether or not they're online. So we'll set a class for this. bg-red-500 by default. Let's put a size of 2 and rounded-full to make it

light that essentially would tell us whether or not they're online. So we'll set a class for this. bg-red-500 by default. Let's put a size of 2 and rounded-full to make it a circle. Yeah, there we go. So we need to work on the visuals of this, but that's essentially all the information I'd like for each player. So if we come back to flex-item-center here, we could on the unordered list, go ahead and set a max width of small and mx-auto, which I think would bring it more or less into the correct place. Let's set empty-6 to put a bit of space up top. And then on the span with the cross in it, we could say, let's say p-1.5 for a little bit of padding. And then along with that, we could set font-bold and we could set rounded and we could set a background-gray-200. See how that looks. Nice. Let's add a little bit of horizontal spacing between these elements. We could say

and we could set rounded and we could set a background gray of 200. See how that looks. Nice. Let's add a little bit of horizontal spacing between these elements. We could say gap two for that. There we go. I'm pretty happy with this. And my thought is that along with the indicator light going green, when a user comes into the game or leaves the game, we could also use the background of the cross or the nought to indicate whose turn it is. So in other words, if it was your turn to play and you were crosses, this would automatically turn to green at probably 500 and you'd get this indicator. So you know that it's crosses turn and not noughts turn. So I suppose the idea of this is that we would take this list item, we would duplicate it below and we would change this for a nought here. Let's put Luke in instead of test user because this would be player two. Yeah. And we need to change

Load Players From Controller2:24

item, we would duplicate it below and we would change this for a nought here. Let's put Luke in instead of testUser because this would be playerTwo. Yeah. And we need to change green in both of these instances back for gray, but that's looking pretty good. The last thing I'll do is add a little bit of vertical spacing between the items, maybe spaceY two. Nice. That looks great. So we have the basics in place there. We know what we want it to look like, but can we wire it up with real data? I think I actually want to fetch this data here about the User from the controller itself. So I'm going to head back into the GameController and if we find our show method, here we are, we're passing the game down. So how about at the same time we load the relationships, we'll load in the playerOne and playerTwo relationships, which means that those variables will be output.

the game down. So how about at the same time we load the relationships, we'll load in the playerOne and playerTwo relationships, which means that those variables will be output into the props of our page. So now if we go back to show.blade.php, we'll head down to our script and here at the top, I'm going to define some props. So const props equals defineProps() and I'm looking for that game that I can then make use of. Now we know for a fact playerOne will always exist because when you first create a game, playerOne is stored inside the table. So we'll start with that relationship. I'll replace testUser here for game.playerOne.name. Let's see if that works. Yep. You can still see it says testUser, which makes complete sense. playerTwo is a little different because obviously playerTwo joins the game at a later time. So to start with playerTwo will be null and

it says test User, which makes complete sense. Player two is a little different because obviously player two joins the game at a later time. So to start with player two will be null and then a little further after they've joined the game, player two will have a value. So we need to keep that in mind. Let's add a if conditional to the second list item and we'll say we're only interested in showing this if there is a player two in this game. Otherwise, how about we show a third list item? So we'll use else here and in this list item, we'll say waiting for player two. Let's see what that looks like. There we go. That makes complete sense, right? So when you first start the game, there is no player two. So that's what we see. However, if we go ahead and join test User's game, you can see that that information is now filled out. Player two has been set to Luke because as the second

Create Presence Channel4:43

that's what we see. However, if we go ahead and join test users game, you can see that that information is now filled out. Player two has been set to Luke because as the second player, I've joined the game, but because there's no dynamic updating Player one still thinks they're waiting for Player two. And the only way they'd find out that Player two had actually joined at the moment is if they refresh the page, which we don't want them to have to do. So let's make use of broadcasting once again, to fix this issue and dynamically update that status in real time. Let's make a start in channels.php where we'll declare a new channel to use. Let's call this games. And then I'm going to use curly brace syntax to define a variable, which will be the gameID. And then in the closure, I can accept the user, but I can also use model binding here, just like you would in controllers.

syntax to define a variable, which will be the gameId. And then in the closure, I can accept the $user, but I can also use model binding here, just like you would in controllers to be able to say, I want you to retrieve this game from the database. We need to authorize whether the $user is allowed to join the channel or not. And essentially the logic for that is, well, are you part of the game? Are you either playerOne or playerTwo? So why don't we say, look, if you are not in this array and the needle here would be the $user->id, the haystack would be playerOneId and playerTwoId. So we can say game->playerOneId and game->playerTwoId. If you're not in that array, we'll return false. Now, obviously in a normal channel, you just return true here in order to say you can join the channel, but because we're interested in ascertaining a little more information about the $user,

in a normal channel, you just return true here in order to say you can join the channel, but because we're interested in ascertaining a little more information about the user, we want to know whether they're online or not. We're actually making use of what Laravel refers to as a presence channel. And in a presence channel, you need to return an array of information about that user. For our use case, it's enough just to state what the ID of the user is. So I'll pass an array with an ID attribute, and then I'm going to pass the userID in as the value. That's actually all the work we need to do on the backend. We should now be able to join that channel from the front end and start listening for users appearing. So in our show.view component, I'm going to use echo here to join a channel. And I want to pass in the correct channel name, which is going to be game.

Track Players Joining6:55

users appearing. So in our show.view component, I'm going to use echo here to join a channel. And I want to pass in the correct channel name, which is going to be game, and then the variable, which is the gameID. So props.game.id. Once I've joined the channel, I can use the here hook. The here hook is going to receive all users who are currently in the channel, right? So any user who has already joined the channel, and I want to store this state somewhere in the component to make use of it later. So I'm going to come up to the top and where we have gameState, I'm going to create a new variable called players, which by default is equal to an empty array. It's an empty ref. Okay. We'll come back down and I'll say, once we joined this channel, once we're here and we have a list of users who have already joined, I want to take that players reference and set the value to those users.

I'll say, once we joined this channel, once we're here and we have a list of users who have already joined, I want to take that player's reference and set the value to those users. The second hook I want to integrate is joining. And as you can imagine, because Laravel is very good at naming things, joining is called anytime a new player joins the channel, which is perfect for our use case, right? Because we want to know when playerTwo joins playerOne. So how about inside this joining hook, we ask Inertia to reload the component. That's going to go back to our GameController. GameLoad will be called again, playerTwo now exists. So when it passes that down to our component, it will include the latest instance of that data. One thing to keep in mind because of how Inertia works, it's essentially a single page application. This function isn't going to be called again. So we need to do

of that data. One thing to keep in mind because of how Inertia works, it's essentially a single page application. This function isn't going to be called again. So we need to do that work manually after the reload takes place to make sure we've got an updated list of players. Let's use the onSuccess handler. And inside here, I can say players.value.push. And I want to push in the user that we've been provided with in the joining hook. We should hopefully now be able to see this in action on the front end. So if we join testUsers' game here, playerTwo has the latest information as expected. And I would expect this to work, but obviously it's not worked. We have a 403 Forbidden status. That's interesting. Let's take a quick look. We're joining the game channels.php. That auth logic looks correct to me. I'll hold in games.gameGate. There we go. That's

That's interesting. Let's take a quick look. We're joining the gameChannels.php. That auth logic looks correct to me. I'll hold in games.gameGate. There we go. That's it. Trying to join the wrong channel. Let's try this again. So we're waiting for player two. I'll come down and join the game. And immediately you can see that we receive confirmation that Luke is now in the game. Okay. So the last thing I'd like to do is update these indicators so that we can actually see if they're visibly on the page or if they've navigated away somewhere else and they're not actively playing with us. We can facilitate this using this playersRef that we've been keeping track of, which if you think about it is an updated list of who is in the channel, but we haven't handled the third hook, which is leaving. This allows us obviously to remove users that disappear off the page. So it accepts

Handle Leaving and Cleanup10:02

it is an updated list of who is in the channel, but we haven't handled the third hook, which is leaving. This allows us obviously to remove users that disappear off the page. So it accepts a user once again, and we'll say players.value equals players.value.filter(). And I'll filter down basically to reject this user here. So I'll use a bit of array destructuring just to grab the ID. And then I can say where ID is not equal to user.ID. And I think that should work just fine. One little thing to keep in mind, leaving will only be called when the channel is completely disconnected from, which in a single page application won't happen unless you actually tell it to happen. So what we'll do in view is use the onUnmounted hook here, and then inside I can say echo.leave, and I'm interested in leaving games.props.game.ID in order.

Update Online Indicators10:50

is use the onUnmounted hook here, and then inside I can say echo leave, and I'm interested in leaving games, and then I'll pass in that variable props.game.id in order to make sure we actually leave the channel. We should now be able to turn our attention to the indicators. We'll start with player one. So I think I'll use class object syntax here to state that I want to apply bg-green-500 under certain conditions, and I'm fairly sure that red has a higher specificity just from past experiences and being burned for many hours. So I'll use the !important modifier. I want to apply that class if the players object or the players array contains player one's id. So we could say players.find, and then I'm interested in the id, so I'll destructure that out of the player object, and then from there I can say is the id equal to the game.property.playerOneId, and I'm

and then I'm interested in the ID, so I'll destructure that out of the player object, and then from there I can say is the ID equal to the game property playerOneID, and I'm pretty sure that would be enough. Let's copy that object, and then let's pass that down to the indicator for playerTwo, and of course I just need to change playerOneID here for playerTwoID, and I think at this point we're good to test it out. So playerOne has created a game and is waiting for playerTwo. We can see the indicatorLight is green, which is a great sign. Let's go ahead and join the game, and you'll see that playerTwo has joined. We see the information and we see a green indicatorLight. Moment of truth. What happens when we leave the page? I'm going to go back to the dashboard and you'll see that the indicatorLight has automatically gone red, but if we go back and join the game again, what was

when we leave the page? I'm going to go back to the dashboard and you'll see that the indicator light has automatically gone red, but if we go back and join the game again, what was it, game 19, the indicator light once again goes green. Let's try it the other way around. So player one leaves the game, and you'll see that the indicator light has gone red, but if we rejoin the game /19, the indicator light has gone green again. Alright, cooking with gas. So player one is now informed whenever player two joins the game. Both players can see the online status of the other player so that they're not sat waiting for hours when someone's closed the browser and left, and we have the channels set up perfectly for our next feature, which is, well, real-time gaming, tic-tac-toe, using broadcasting. Let's tackle that in our next episode.

for our next feature, which is, well, real-time gaming, tic-tac-toe, using broadcasting. Let's tackle that in our next episode.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟