In this lab and homework, we will create a game of character cards duel. We have two players facing each other in a duel. Players take turns to roll a die and hit each other. They both start with the same number of health points. In each turn, they roll a die that gives them hit points. That number is subtracted from the other player's health until one player's health gets to 0. The other player is the winner. Here is a screenshot of the game:
Ex. 1. In this lab we'll create a project using images to create the nodes in the scene.
Create a project called cardDuel and a scene called main inside. Create a Node2D object called Root in the scene. Switch the scene editor to 2D.
a. Background
Choose one of the following images and download it, then drag it to the folder of the project. You can also find these images in Canvas - Files - Week 3.
You should see the file in the File Browser in the Godot project.
With the root node selected, add another node of type TextureRect and call it Background. Then drag and drop the frame from the File Browser onto the Texture attribute of this object (where it says <empty>). The node should now show this frame.
Let's resize this tile to cover the whole screen. Zoom out until you can see the dark blue outline of the viewport. Then pull the lower right corner of the image to align it approximately with the bottom right corner of the viewport. That way, the image should fill the whole screen when you run the application. Try running it to see if that is the case.
b. Character Cards
Download the following two images and add them to the project folder:
Then drag and drop each of these from the file browser to the scene to create nodes from them. They will look a bit different from the background, which is because they are added as Sprite2D nodes. These nodes can easily be moved around on the scene and even animated. They are meant for dynamic 2D characters. Rename these objects Player1 and Player2. Scale them down a bit so that we can add more elements around them, and place them facing each other.
With Player1 selected, add a label node with the text 20 in it. This will show the health of this player. Move it in the top left corner of the card and set its color as black or something dark so that it's well visible. Call this node Health1. Repeat the procedure for the second player.
If you look at these nodes in the inspector, under Node2D you can expand Transform and manually enter the same value for the scale and the same y coordinate for the two of them. That will make them look the same size and align them horizontally.
c. More Nodes
Add a couple of nodes of type Label placed above the cards, with the text "Roll:" and with the names Roll1 and Roll2, also as children of the card nodes. These will show what the die roll of each player.
Let's create a shape now to highlight which player's turn it is to attack. For this, we will use a node of type Polygon2D. Add such a node from the category Node2D. Make it a child of the Root node itself. Place it above the first player and to the left, and then click in the scene to add nodes. Create a rectangular shape that completely covers the player and the text above it. Set the color of the polygon as something light such as light orange or green. Name it Highlight.
Add one more label above all of them with a title such as "Roll Battle". Then add two buttons, one with the text "Attack" and one with the text "New Game". This is all the nodes that we need.
d. Node Ordering
Now we need to determine the ordering of the nodes properly so that the player card appears in front of the polygon. If you scroll down in the inspector to CanvasItem and expand Ordering, the Z indexes are set to 0 for all the nodes. This determines the order in which the nodes are displayed: nodes with higher z values appear in front of others.
Set the Z index of the polygon to 1. Set the Z index of the two player cards to 2, then the index of all the text items to 3.
e. Adding a Script
Add a script to the root node. In this script, start by declaring references for the health nodes, the roll nodes, and the highlight polygon, and connecting them to the nodes in the function _ready. Note that this time, the root node owns the whole tree. So for example, if the first health node is called health_ref1, we can connect it by writing
health_ref1 = find_child("Health1")
Select the attack button and click on the Node tab next to the inspector. Connect the signal pressed() to the node Root by double-clicking on it and let it create a new function.
Duplicate the function and add 1 to the name, then connect the New Game button's pressed() signal to this other function. For this, after you double-click on the signal, click on Pick and select the second function.
f. Player's Turn
Add a class variable to tell us which player's turn it is called turn, initialized as 0. This will be equal to 0 in the first player's turn and to 1 in the second's.
Then declare another variable called high_coords, initialized with an empty array. The goal for this array is to contain coordinates on the screen of the highlight box when it is placed over the first player (first two values) or the second one (last two values).
Click on the Highlight object. In the inspector, expand Transform under Node2D and place the values you find for Position in the array, separated by a comma. This will be its position on the left player.
To get the position over the right player, click on 2D at the top to go back to the scene editor. Move the highlight box over the second player. Switch back to the script and repeat the procedure, adding the current coordinates of the box to the array. Note that the y coordinate should probably be the same, if you have aligned the two player cards before.
Now go to the function _on_attack_btn_pressed() and add replace the instruction pass with the following code (assuming that the reference to the highlight box is called high_ref):
turn = 1 - turn
high_ref.position.x = high_coords[2 * turn]
high_ref.position.y = high_coords[2 * turn + 1]
Ex. 2 Declare a couple more variables in the class: two variables to hold the health value for each player and one for a random number generator. Initialize the latter like in Homework 2.
Write a couple of functions: new_game() and attack(). From the functions related to the button pressed signal, call these functions respectively.
In the function new_game, reset the health of both players to 20 and the highlight on the left player.
In the function attack, generate a random number between 1 and 6. Set the text of the Roll of this player to show what the roll was, then subtract the hit points from the health of the opposite player. Update the label of the player with this information. You will need a conditional to test which player's turn it is. At the end of the function, move the code toggling the player's turn and moving the highlight box into this function.
Note that to convert an integer to a string, we can use the function str. Also, the plus operator can be used to concatenate strings. So for example, if hit is the variable containing the current hit points, then we can turn it into a string to be assigned to a text attribute with the expression
"Roll: " + str(hit)
Finally, we need to check for a winning condition and do something when that happens. In the function attack, when the health value of the attacked player becomes less than or equal to 0, set it to 0, and set the roll label for that player with a message saying that they lost.
Take a screen shot of your running program, showing the content of the screen after a couple of attacks, and save it as png or jpg. Submit it along with the scene file main.tscn and the script file main.gd to Canvas, Assignments - Homework 3.