Basic Game Functionality
Start course
2h 36m

In this course, we begin building a game in Solidity, and more specifically, we begin to look at defining the mechanics and the components of the game.


So, in this lecture, I want to continue where we left off in the previous one. We have now, the very very basic game interface. And if you didn't follow along in the last lecture step by step writing their own code, then and you want to join now then you can find the code where we left off in the previous lecture in our course repository in the folder SO2. The game is really the NCO2 basic game functionality. There are all the files so you can join in now if you want to. What I want to do now is when we deploy the GameManager and we are going to start a new game, then it should actually deploy a new instance of our free neural game and set our player player1 to some storage variables so we can later on know who is the player1. Obviously, we have a gameCost which should be applied at this point. And then I guess I want to stop there. Now, if you feel like you want to try this yourself, you can do this. Obviously, there's not a lot of magic going on here but we haven't learned everything in order to do that. So, if you feel like you want to take on a challenge and really try this yourself, then just post the video and do it. And if you want to follow along, then just keep watching. It's not the official challenge of this lecture here. First of all, when we want to start a new game, then we are going to call the function startNewGame() with 0.1 ether in our GameManager. So, our GameManager is going to be always deployed and he's always sitting on the same address and somebody can start a new game by calling this function and it should deploy a new ThreeInrow instance. And to do that we have ThreeInARow, with a capital letter which is depicting our contract and then ThreeInARow with there is a typo with a ThreeInARow with a lower case letter which is then saying this contract should be in this instance. So, this is going to be a variable and this is going to be our contract very similar to object oriented programming languages where you have. This is a class and if you want to create any object then save it into this variable, is a new three in a row instance. Now, the problem with this is, first of all, we have a couple of constructor arguments which we would have to give it in here, our case. Our ThreeInARow contract has to construct arguments. One address for the GameManager itself and one address for the player who is going to play. You should be able to do it like this. (address (this)) gives you the address of the current contract we're in and it's going to be the GameManager. So, we get the address of the GameManager and the msg.sender is the player who is going to be playing. Now, unfortunately and I will leave it like this. But unfortunately this will not work fully because we will have a constructor or we will have a game that costs something. So, we would have to find a way to actually forward money which was sent to the startNewGame() function in order to start the game and more or less in the second. And then the next thing which we haven't discussed yet in the previous lecture. So, I'm just going to define something called an Event and the event will be emitted during this transaction execution. So, don't be surprised that we haven't discussed this in more detail yet because events are somewhat a little bit more complex. If you look at it from a theoretical point of view and we're going to discuss events in depth in the next section and just bear with me. We have to define an event at the same section where are the storage variables? And events start with the keyword event and I'm going to call this event EventGameCreated() and then they can emit arguments. And the reason for these events in general is, if you have a writing transaction, then writing transactions cannot really return any information at all. Except they get back on a transaction hash once the transaction is mind that you're done. But that's it. So usually, you cannot access any return variables from outside and that's where events come in. So, if you are looking from the outside world, outside of solidity. So, from JavaScript from Java, from PHP, from any programming language you want to access your smart contracts, then you would usually wait for an event to be fired and that's where events come in. So in our case, we are going to have an event that emits the address_player and the _gameAddress and if you want to emit an event, then you start with a keyword emit and then you just basically say, emit the EventGameCreated() and our address_player the person who called this startNewGame function and the gameAddress is the address of ThreeInARow. So, if we are going to run this smart contract, I'm going to the run tab over JavaScript VM. I select the GameManager. Hit Deploy. It's going to deploy the GameManager. It doesn't cost a lot of gas yet 1/2 a million gas and I get these functions and I can start a new game. That's great. I get back inside the transaction. If I open the transaction, I can see the locks down here and that is where the events are being emitted and I can see that my game. So, the ThreeInARow instance was deployed on a new address. So, if we are using this new keyword, then it's like deploying a new instance of a smart contract inside a smart contract. So, that is pretty cool. And with this, we can then use the this ThreeInARow contract with this interface in order to interact with our smart contract but we're not done here. The problem is now we can make a new instance of a ThreeInARow smart contract. But first of all, we didn't save to player1. Second, we don't have any costs yet defined for our smart contract. The first one that I want to do is, I want to have an uint256 with gameCost; and we are going to make this public so everybody can see how much it will cost. In this case, I will let security take care of this get a function and we're going to say this one will cost 0.1 ether. And now, in our constructor, we can say we require that the msg.value which is sent along is the same as the gameCost. And if it doesn't, then "Submit more money! Aborting!" and now, we can go back to our GameManager and we will see if we deploy our GameManager now and we startNewGame. I don't even have to give any either actually starting a new game, it says Aborting!. There's a revert "Submit more money! Aborting!. The problem is even if I sent along 0.1 ether. Now, I started a new game. It's still start supporting. So, why is that? Because when we are creating a new instance, we're not sending the ethos along and there is a workaround. I personally think it's a very ugly workaround but in order to send ethos, you have to make this contract by creating a new instance in around brackets. Then you say value and we're going to send along whatever was the value that was sent from our person outside to the smart contract. And at the end, you also have been around practice the actual constructor arguments. So, when we deploy this smart contract and now we give it 0.1 ether. Then it will create us a new game. And inside this transaction, we see the logs which are emitted from the startNewGame function. One thing is missing and that is the challenge of this lecture. We're not saving this player variable somewhere. So, what is missing is create a new storage variable address and save this player variable. If you want to do the challenge, then post the video now and I will show you in a second how it's done. So essentially, we have actually two players so that the challenge was save the address of the player one. But this one if you try this, this one will not work because if you say player1 is player1, then it will or it should not let us do this because player1 is not payable here. So, we would have to say this is payable in order to make it work later in order to pay out this person something. And we also have a player2 for our joining the game which we're going to discuss in a second and I'm going to make both of them public in order to get access to the actual players. And now, we are going to deploy this, preparing your GameManager, startNewGame. We see our smart contract here is deployed on a specific address and I'm going to select this and if I copy this and I go to my ThreeInARow smart contract here, then I can say this ThreeInARow smart contract is running under this address. So, you have to copy the gameAddress, go to your ThreeInARow and then paste the gameAddress here where it says At Address. And then when you hit At Address and you scroll down a little bit, then you have your threeInARow smart contract or you have a way to interact with your threeInARow smart contract. And you should see that you are player1. Everything else, I know you see the gameCost. That's it. getBoard is set to the default values but it doesn't do anything. Player2 is empty yet we're going to talk about this in the next lecture and the rest of the functions, they are not doing anything yet. In the next lecture, we are talking about how to join the game from a second player and if you have any questions or if anything is unclear, feel free to reach out in the Q and A. We are here for you. We are answering questions. I know at the beginning, it's a little bit harder but once you wrote a little bit of solidity code, it actually keeps repeating and it will be much easier once you figure out how to get the new instances, how to call the functions, and where are my actual variables stored. I'll see you in the next lecture.


About the Author

Tom is a CTO, senior back-end developer, and systems architect with over twenty years of hands-on development experience in a variety of languages and systems. He has a CS master's degree and has been working with Ethereum and blockchain technologies since 2016.