Hula-Hoop on the KittenBot Meowbit
Below is the Hula Hoop game running on the KitenBot Meowbit.
Works great except that at a large number of hoops, it ran out of memory.
Changes Since Our Prior Post
Since the prior version of Hula Hoop, we fixed bugs that caused the hoops, in certain situations, to not be colored correctly. Now the hoops are launched correctly in color order from pink to brown (3 to 14). Also, in on overlap hoops, colors are retrieved correctly from the hoop colors list. We corrected the link to the code in the prior post. The link for the new version Hula Hoop 3.0 is https://makecode.com/_fViaJ0hxbfd5 .
How to Use Hula Hoop
Our previous blog post Using Hula-Hoop Game in MakeCode Arcade explains how to use the game. We will briefly describe it here.
Like real-world Hula Hoop, the goal is to keep the hoops moving. If all hoops stop, the player loses with score zero. Winning requires keeping the hoops moving through four levels, which are indicated by the hearts on the left of the screen: the more hearts the longest lived. The level advances when the current countdown reaches zero. Each level ls increasingly difficult. Not only is the countdown time longer; but new hoops are launched at a slower velocity and when two hoops overlap, one is more likely to follow the other. Both these features make the hoops more likely to reach an equilibrium that stops all hoop movement.
The up button adds one hoop. When a hoop is added, the current countdown starts over. The down button removes the slowest hoop; for example, a hoop that has stopped moving altogether. The countdown does not restart.
The Code for Hula Hoop
The main Hula Hoop code blocks show below are typical of an action game.
The main blocks are:
- On start initializes the program.
- On game update keeps things going.
- On countdown end advances a level or, if at level 4, ends the game.
- Up/down buttons add/remove a hoop.
- On overlap hoops, depending on the stickiness, makes one hoop follow the other and change the colors of the two hoops.
Initialization — On Start
Initialization is done in the following steps:
- Setting the five lists that define a hoop are set to empty. The lists are shown in the first table below.
- Initializing the variables shown in the second table below.
- Calling the function init_constants to set constant values used by the program. A separate function is used for this to make clear that these variables never change during a game. The constants are shown in the third table below.
- Calling the function show_instructions_question to display Hula Hoop instructions if the player desires.
- Calling make_one_hoop so that the game is launched with one hoop on the field.
|hoop_list||The list o sprites associated with hoops.|
|X_list||The list of x coordinates that correspond to the hoops in hoop_list.|
|Y_list||The list of y coordinates that correspond to the hoops in hoop_list.|
|distance_list||The list of distances traveled for each hoop since the last update.|
|hoop_color_list||The list of colors of the hoops in hoop_list at the time they were created.|
|New_countdown||New_countdown a Boolean variable that, if true, indicates that a new countdown should be initiated at next game update cycle.|
|Hoop_color||The color of the most recently generated hoop. Setting it to 9 causes the next color used to be pink, which is the first of the colors that are used. With each hoop, Hoop_color advances 1 until it is 14 (brown), then starts over at 3.|
|level||level is the current game level. It starts at 1 and advances at the end of a level countdown. When the level 4 countdown ends, the game ends and the player wins with the score being the number of hoops motion at that time.|
|Stickiness||Stickiness determines the likelihood of one hoop being made to follow the other when two hoops overlap. Stickiness starts at 31, which is the least sticky. It declines with each level until it is one, which is the most sticky.|
|max_velocity||This variable is the is the maximum velocity at which a new hoop is launched for the current level. Random velocities chosen for a new hoop a limited by max_velocity.|
|prior_time||This variable is set to the game time at which the prior on game update event ran the function count_hoops_in_motion. It is used in on game update to prevent the hoop count from running more frequently than 200 milliseconds.|
|levels||The number of levels in the game. We tested various values and found that we preferred four.|
|change_per_level||The change in the initial countdown for a level from the previous level initial countdown value. Thus levels 1, 2, 3 and 4 with have initial countdown values of 10, 20, 30 and 40 seconds respectively.|
|pi||The usual mathematical value pi; It is used in drawing the circles representing the hoops. The variable s_pi, which is the string representation of pi, was used to input the value of pi so that it could be pasted into the program. With my Grandma vision, I would never have gotten it correct if typed in as a numerical constant.|
|red||The numerical value representing the color red, which is 2. This constant is used for code clarity.|
The function shown below initialize game constants.
On Game Update
On game update shown below runs when nothing else is happening in the game. It always checks the Boolean variable New_countdown for true; in which case, it restarts the countdown with time depending on the level.
We found that if on game update runs more often than 200 milliseconds, the game is choppy. Because of this, the code requires that at least 200 milliseconds have elapsed since the last time the event ran the function count_hoops_in_motion.
If at least 200 milliseconds has elapsed, a function is called to count the number of hoops that have moved since the last time hoops in motion was counted. If no hoops have moved, the game is over.
The event on game update every ___ ms was not used because we think that this event runs even if something else is going on. We’re not sure that this is the case; however, just to be safe, we solved our problem another way.
On Countdown End
When a countdown ends and the level is 4, the game ends with a win for the player. If not level 4, the level is increased and the variables associated with levels are changed.
In addition to increasing the level variable by 1, max_velocity and stickiness are decreased.
The variable max_velocity is used as the limit when a random velocity is chosen between 10 and max_velocity; therefore, the velocity is likely to be slower as the level increases. This makes the hoops more likely to stop moving.
The variable stickiness is used to determine how frequently one of a pair of overlapping hoops will follow the other. A lower stickiness will cause following to occur more often, which causes he hoops to be more likely to stop moving. A lower stickiness means more following. Stickiness decreases with advancing levels.
An up-button press calls a function to make one hoop. The down-button press calls a function to remove one hoop.
On Overlap of Two Hoops
When two hoops overlap and a random number between 0 and stickiness is zero, one hoop s set to follow the other (othersprite). One thirds of sprite’s points and all othersprite’s points are set to othersprite’s original color. Thus, the sprite being followed is solid and the sprite that is following is two colors. This makes it possible to view a field and figure out which spites are being followed.
Supporting functions are those that are called by the top-level blocks described in the preceding sections. Supporting functions are described in the subsections that follow.
Make One Hoop
Making a hoop involves the following steps:
- Create a hoop sprite with a square image with an odd random number of pixels per side between 16 and 100 pixels.
- Position the sprite at a random position on the screen.
- Select a color for the circle to be drawn on the otherwise clear sprite. Colors increment from 3 (pink) to 14 (brown) and back to 3.
- Add the new hoop characteristics to the five lists defining the hoop including lists for the sprite itself, the launching x,y coordinates, the color and the most recently distance from the prior position. The distance is initialized to -1, a value that will not be tested as zero on the next update and, on the next update, will be calculated as a positive value.
- draw the largest diameter circle that fit in the sprite.
- Give the new hoop random velocities in both x and y positions and set it to bounce off walls.
- Set New_countdown to true, which, at the next on-game-update event, will restart the counter because of the added hoop.
We do not restart the counter in this function, because that caused issues that we didn’t fully explored, but were solved by only restarting the counter in the on game update event.
The function draw_circle shown below is called by make_one_hoop to draw a circle in a sprite representing a hoop. The function takes three arguments: the diameter of the circle, the number of equally spaced points with which to draw the circle and the color of the points.
The function calculates the degrees that will separate each pair of points and the x,y coordinates of the center of the circle. In the loop from 0 to 359 is one time through the loop for each degree in a circle. The guts of the loop is performed only for the points to be used when drawing the circle. Degrees are converted to x,y coordinates of the point on the circle by using the degrees, the desired radius, and the x,y coordinates of the center.
The function degrees_to_XY is called by draw_circle to calculate the x,y coordinates of a point on a circle given the degrees, the radius and the coordinates of the center of the circle.
The function get_random_velocity is called by make_one_hoop to return a velocity between – max_velocity and max_velocity omitting the values -10 to 10. max_velocity depends on the current game level.
Count Hoops in Motion
This function is called by the game loop. I think of it as the heart of the program. It loops through all hoops. As it does, It counts the distance that each hoop has moved since the last tie it was calculated. If the hoop has not moved, the hoop is colored red. If it has moved, a count variables is incremented which is returned to the game update block as the variable hoops_in_motion_return. If a hoop has moved, but had not moved in the prior update, its color is changed from red to its original color.
Hoop lists are updated with the new distances moved and the new x,y coordinates. These will be used in the next updates to determine new distances moved.
The function calc_distance_moved, which is shown below, calculates the distance that a hoop has moved since the last time its distance and coordinates were updated. The function argument is the index of the subject sprite in the lists of sprite characteristics (e.g., coordinates, last distance moved). The distance since the last position is calculated using the Pythagorean Theorem with the change in the x coordinate and the y coordinate. Changes in x and y are each squared, added and the square root of the result calculated. The result is the distance desired. The floor of the result is used so that the distance is an integer and that the ending pixel will exist, which we thought might not be so if rounding is used.
Remove Slowest Hoop
This function is called from the down-button pressed event. It searches distance_list to find the hoop with the minimum distance traveled as last updated. When found, this slowest hoop is removed by removing associated values from the five lists of hoop characteristics.
Get Hoop Color
This function is called from the on overlap event if one hoop is being made to follow the other. Hoop color is retrieved by searching for the sprite argument in the hoop_list. When found, the index is used to get the hoop color from hoop_color_loop. The color is returned as the global variable color_return.
This function is called from On Start as part of the program initialization. It asks the player whether to display instruction or not. If so, the instructions are built in a single string variable msg. This is more convenient than one big string because it is easier to edit and is more readable than one long, long string.