Dana Vrajitoru
I355/C490/B590 3D Games Programming
I355/C490/B590 Homework 10 Godot
Due Date: Wednesday, November 20, 2024.
In this homework we will continue Lab 10
to implement the game Monster Run. Here is an an
example (http://www.cs.iusb.edu/~danav/teach/b583/monsterGL/) of
the intended result.
In this game, the player advances on a path where it can find tiles
containing either nothing special, or a treat (candy or pumpkin) or a
monster. They must start from the starting position and will win the
game when they reach the finish position. Here are the rules of the
game:
- The player advances by rolling a die and moving forward by the
resulting number of tiles.
- If the new position contains a treat, the player can take it or
ignore it. If they take it, it can be used in a monster fight as a
power up. Candy gives 1 point, pumpkins give 2 points.
- Only one treat at a time can be carried, so the player can choose
to ignore the currently available treat and keep the one they already
have.
- If the player lands on a monster tile, they can choose to run
away, in which case they go back 3 tiles.
- The player can also choose to fight the monster, with or without
the powerup that they carry. If they use the powerup, it is
consumed. This choice must be made before the fight.
- In case of a fight, the player rolls the die again to decide the
outcome.
- The monster's power is of 2, 4, or 5, depending on the type of
monster (1, 2, or 3).
- If the roll plus the powerup (or 0) add up to the monster's power
or more, the player wins the fight and their score is increased by the
difference.
- Otherwise they have lost and they need to go back a number of
tiles equal to the difference between what they rolled + powerup and
the monster's power.
- After this the player restarts from the initial roll to move.
- When the player is moved back either by fleeing from a fight, or
by losing a fight, its state goes back to idle. Thus, they cannot take
advantage of a powerup on that tile, nor have to fight a monster until
they move again.
The game can be summarized by the following finite state machine,
where R = player's roll (the die_value
in game_master), PU = player's powerup, MP = monster's power,
store = stored powerup.
Ex. 1. Implement the functionality of the game by doing the
following:
- Add all the necessary states in game_master in
the enum State list based on the finite state
machine.
- Complete the function set_buttons to show the 1, 2, or 3
actions available in each state. For example, in the state where you
landed on a monster, the buttons should display the 3 options: Roll &
use the powerup, simple roll, or run away.
- Complete the function action1 that contains the action
associated with the first button in each state.
- Add two more functions action2 and action3 that
contain the functionality of the second and third buttons in each
state and connect the pressed() signal of those buttons with
these functions.
- In the function _process, add a conditional (if)
statement based on the state and perform all the transitions that
don't require an action from the user. For example, if
clicking Roll from the idle state takes you to a
state moveRoll, and if you want to move without having to
press a button, then in _process, if the state
is moveRoll, then move the player by the amount of the die
value, then change to the appropriate state based on the tile you land
on, and call set_buttons again.
- Make sure that the score is updated and displayed properly and
that the info text displays the necessary information after each
action.
Here are some implementation suggestions:
Add attributes in game_master for the stored powerup, for
the powerup to use in a fight, the score, the monster's power.
Add a function move_by that moves the player by a given
number of tiles. This function would have to update the value
of player_pos, confine the value to the boundaries of
the tiles array, and then call place_player with the
new position. Note that when moving, if the result should be a tile of
a negative index, then you should place the player back at the
starting position 0. Similarly, if the resulting tile number is larger
than or equal to the size of the array of tiles, then you should place
the player on the last position.
For bigger actions, it's probably better to define a separate
function. For example, you could define two functions
called move_action and fight_action to handle those
actions. Then you can call them in the appropriate places from the
action functions.
The fight_action function would roll the die and then
decide whether the fight is won or lost. In case of a win, it would
update the score with the difference between the player's hit (powerup
plus die) and the monster's power. In case of a loss, it would have to
move the player back by the amount of the difference.
The move_action function first moves the player by that
number of places and then based on the type of tile it lands on, goes
into another state: monster, powerup, or idle. The buttons and info
are updated accordingly.
Ex. 3. (optional) Any additional features at your discretion
for up to 3 extra credit points. For example, you could make the
player move continuously from one tile to the next, or have the die
actually spin before landing on the face it's supposed to.
Turn in to Canvas: a zip file with the
script game_master.cs and a Windows build.