مرور آرام مانند یک نجوا0:00
The Brave Warrior traveled day and night to deliver the message to the server. The server placed the message on the Great Database, before locking it in the queue for seven score years plus ten. When finally the worker arose from his slumber, he claimed hold of the message and brought it before the Ancient Reverb, whose role it was to seek out those who have been searching for an answer via a loop. It's no wonder our game of tic-tac-toe feels a little bit sluggish, because there's just so much going on between clicking on a square and that message actually appearing on the opponent's screen. But it doesn't have to be that way, because there's actually a way with WebSockets to
Switch to WebSockets0:42
opponent's screen. But it doesn't have to be that way, because there's actually a way with WebSockets to talk directly between each of the players and avoid the server altogether. Let's take a crack at that in this episode. We send an update to other players subscribed to the channel using the Whisper method. But of course I don't want to whisper here, I want to whisper whenever a player makes a move. So what I'm going to do to facilitate that is cut out all of this echo code, and we'll head further up in the script, perhaps under this lines constant, and I'll drop the echo code in like so, and assign it to a channel, const channel equals, and then we can drop
Whisper Player Moves1:15
head further up in the script, perhaps under this lines constant, and I'll drop the echo code in like so, and assign it to a channel, const channel equals, and then we can drop the rest of the logic in here. And all of these methods return an instance of presence channel, so we can leave this existing logic in place. We will be assigned the correct instance here. Alright, so when we fill the square, we're sending this request to games.update, that's going to happen asynchronously. At the same time, I'm going to grab our channel instance, and I'm going to whisper to it. First of all, I need to provide the name of the whisper.
At the same time, I'm going to grab our channel instance, and I'm going to whisper to it. First of all, I need to provide the name of the whisper. I'm going to reuse this here, playerMadeMove. We'll drop that in as the first argument. And the second argument is an object which is our payload. So I'll say that I want to provide state, which is just going to be boardState.value. And that really is all we have to do. Now on the other end, we need to listen for this whisper so that we can update our boardState accordingly.
Listen for Whispers2:10
Now on the other end, we need to listen for this whisper so that we can update our boardState accordingly. And again, we can reuse existing logic here. Instead of calling listen to listen for playerMadeMove, I'm instead going to listen for a whisper. Now we're not past an event, we're past the payload of the whisper. You can see I've given this state object. So when I destructure, I'm instead going to destructure state directly and set boardState.value just like that. And I think, again, I'm not quite sure, we'll have to go and check it out.
dot value just like that. And I think, again, I'm not quite sure, we'll have to go and check it out. But I think that this should just work. So let's test it in the browser. Hopefully now as we play moves on the board, yeah, look how much faster that is. There is basically zero delay in you clicking the square and in that being repeated and shown on the opponent's screen. So much better than it was before. It feels like you're in the same room together. Of course, that means that we can actually clean up some of the server side stuff that
Remove Server Broadcasts3:04
It feels like you're in the same room together. Of course, that means that we can actually clean up some of the server side stuff that we did because we no longer need that event to be broadcast and placed on the queue. So in our GameController update method, we no longer need to broadcast this event seen as it's happening locally. Let's remove that. We have an import at the top here, so we can remove that too. And if we jump into the PlayerMadeMove event, yeah, see how it's grayed out in PHPStorm? That indicates it's no longer being used anywhere. So let's go ahead and just delete it entirely.
That indicates it's no longer being used anywhere. So let's go ahead and just delete it entirely. We no longer need that event because everything is happening locally. We mustn't forget that when we reset the game, we're also sending an update to the server. So we also need to update the opponent through a whisper. However, what I'm going to do is I'm going to extract this code here to a function that we can reuse in both places. So let's say const and why don't we call it updateOpponent. I know that we're also updating the server at the same time, but the real purpose of this is to update the opponent of what's going on.
I know that we're also updating the server at the same time, but the real purpose of this is to update the opponent of what's going on. And then we can place that code in there and we should be able to call it here, updateOpponent. And then of course we can also call it further down when we reset the game, updateOpponent. All right, let's test out this game on the front end one last time. Let's give crosses the victory here by placing a cross in the bottom left. Look how fast that modal pops up on both screens. It's basically identical in timing, thanks to the speed of web sockets. What happens if we click play again?
It's basically identical in timing, thanks to the speed of web sockets. What happens if we click play again? Does it all work? Yes, it does. The modal disappears. The board state resets. One last thing I want to check. If we get to that win state, I'm just going to quickly fill these out and then I reload the page. Ah, look at that.
Fix Modal on Reload4:51
the page. Ah, look at that. So the modal disappears. What we need to do I think is check for victory when the game first loads in case the state indicates that, well, there's already been either a victory or a stalemate that's happened. Let's do that in an unmounted hook. So anytime this component mounts, we're going to check for victory. And in fact, we could just pass checkForVictory as a callable like that. Make it even simpler. Let's see if it works.
Make it even simpler. Let's see if it works. So as we reload the page now, yeah, note that because X has won, because crosses have won, it's going to show that modal each and every time until we click play again, at which point the board is reset. And now if we reload the page, well, we don't see the modal anymore because we're ready to start a new game. So as far as I can see, that is a fully working online real time game of tic-tac-toe, which I think is pretty cool. And when you actually think back on it, it hasn't been that much work to implement thanks
Wrap-Up and Improvements5:47
I think is pretty cool. And when you actually think back on it, it hasn't been that much work to implement thanks to the power of WebSockets, Laravel Echo, Laravel Reverb, and of course, the toolkit that Laravel provides. There are some things that I want you to take away, perhaps to clean this up a little bit in your own time. At the moment, we will just have endless games in our games table. So perhaps pruning models at an appropriate time would be a good thing to integrate. What else can I think of? If you leave a game, we have the little red indicator light that the opponent is no longer
What else can I think of? If you leave a game, we have the little red indicator light that the opponent is no longer there, but it would be nice to kind of force you to finish a game. Maybe you use some middleware, for example, to redirect back to the game board until you click finish, at which point it would delete the game from the database and redirect both players to the dashboard. So just a few little cleanups like that. We're not going to discuss them in this series, but if you want to just carry this on, polish it up and perhaps even put it on a website somewhere for people to enjoy playing, go ahead, be my guest.
it up and perhaps even put it on a website somewhere for people to enjoy playing, go ahead, be my guest. I hope you've enjoyed our little exploration and foray into real-time events with Laravel Reverb and WebSockets. I'm sure you can think of many more applications than a game of tic-tac-toe, so if you've got a cool use case for them, be sure to put that in the comments down below. I'd love to hear about them at some point. All right, it's been great having you with me. Thanks for watching. I'll see you all later.
Thanks for watching. I'll see you all later. Take care. Bye.
