CS 106 Winter 2018
Assignment 07: Randomness and Noise
Question 1 Pipes
In the provided sketch TenPrintRandomSeed, we drew a grid of "tiles", where for each tile we chose randomly between two possible motifs: a forward slash and a backslash. A ControlP5 slider provided a means of biasing that random choice.
Of course, other systems of tiles can yield interesting designs when assembled into a larger grid. In this question we will use two tiles: cross.svg, showing crossing lines, and arcs.svg, showing two quarter-circles:
Both of these tiles will appear in two different orientations. We'll use the orientation shown above, which is how they're drawn in the SVG files, and sometimes also draw them rotated by 90 degrees.
Create a sketch titled Pipes that produces random pipe drawings like the ones above. For each tile, the sketch should choose randomly between drawing arcs and drawing a cross. The choice should be biased continuously by the position of a ControlP5 slider: when the slider is all the way to the left, draw only crosses, and when the slider is all the way to the right, draw only arcs. Arcs should be oriented randomly (i.e., flip a coin to decide whether to draw it as given or rotated by 90 degrees). When drawing crosses, they should be drawn in a strict checkerboard of regular and rotated versions, so that a grid of pure crosses will produce the characteristic "basketweave" pattern shown above.
The sketch will be similar to TenPrintRandomSeed. You are welcome to borrow ideas from the sketch, or even to start your solution by copying that entire sketch and modifying it. Just be sure to put your name and student ID at the top of the file!
Your sketch should satisfy the following requirements:
Download the SVG files above and add them to your sketch in order to draw tiles. You should not create rotated SVGs outside of Processing; Use geometric contexts as needed to draw rotated tiles.
The sketch should run in a 800×600 window and draw an 8×6 grid of tiles.
For each grid cell, decide whether to draw arcs or a cross. The decision should be random, but biased by the current position of the slider, as described above.
When drawing arcs, you must always select one of the two possible orientations of the tile at random, with each orientation being equally likely.
When drawing a cross, you must strictly alternate the two orientations, as in the image on the right above. There's a nice trick to decide which orientation to use. Use nested loops, one counting rows and the other counting columns (as in TenPrintRandomSeed). If you need to draw a cross in a given grid cell, draw it rotated if X+Y is odd (where X and Y are the current column and row); otherwise draw it unrotated.
The sketch must set the random seed at the beginning of every frame, so that the pattern doesn't change constantly. Pressing a key should change the seed, which should cause a new pattern to be drawn.
Let's review how the logic works. For each grid cell, first decide whether to draw an arc tile or a crossing tile. The decision should be based on the comparison between a random number and a threshold, with the threshold computed from the slider. If you are drawing an arc tile, flip a coin to decide whether or not to draw it rotated. If you are drawing a cross, draw it according to a strict alternation so that you get a "basketweave pattern".
Save your work in a sketch titled Pipes in the A07 folder.
Question 2 Flappy Noise
Flappy Bird was a shockingly successful and difficult mobile game that rose to infamy in early 2014. In this question, you will implement a variation on Flappy Bird in which the obstacles are drawn based on the built-in noise() function in Processing.
Proceed according to these steps:
In the provided starter code, open the sketch FlappyNoise. Run it immediately. You will see a full implementation of an embarrassingly easy version of Flappy Bird in which there are walls at the top and bottom of the screen (the "margins"), but no other obstacles. Hold down the space bar to flap; otherwise you'll fall. If you touch the green areas at the top or bottom of the screen the game will end. Press the 'r' key to reset the game.
Familiarize yourself with the provided code. There are a lot of global variables; some are constants that control the behaviour of the game, and others are variables that keep track of the game's current state. Make sure you understand how those constants and variables are used. There are many comments to guide you.
In draw(), after drawing the top and bottom margins and before drawing the player, add code to draw the other obstacles in the game, like in the example video above. You can take inspiration from the provided sketch Noise2DDirectManip. You'll need two nested loops, one over rows of pixels and one over columns (you can skip the rows that were already part of the margins). For each pixel, make a call to noise() based on the x and y coordinates of that pixel, scaled by a suitable amount. Now, if that noise value is above a threshold of your choosing, declare that pixel to be an obstacle and colour it in (using set()); otherwise, just skip it.
Don't worry about moving the obstacles for now (if you're following along in Noise2DDirectManip, ignore tx and ty); just get a reasonable field of green drawn in the sketch window.
Tune the threshold and scaling factors for the noise function to your liking, so that running the game a few times seems to produce a reasonable distribution of obstacles.
Modify the drawing code in the previous step so that the obstacles scroll to the left while the game is running, making it look as if the player is flying to the right. Use the global variable scroll to offset the call to noise(), much as tx is used in Noise2DDirectManip.
Notice how, at the end of draw(), the local isTerrain() function is called to determine if the player's position is legal. At present, isTerrain() just checks if the player has wandered too high or too low, into the margins. Add code to that function to check if the player is currently over top of an obstacle pixel. You'll need to use the same ideas you used to draw that pixel: call the noise() function and check if the value is past a threshold. If so, return true.
(If you're clever, you can use isTerrain() in the drawing code too. This has the advantage that the drawing code and collision testing code are literally the same, avoiding any inconsistencies in the game.)
If this seems like a lot, don't worry: the entire solution can take as little as 10–15 lines of code on top of the code that's already provided. More of the work in this question is related to reading and understanding the code you're given to start with.
Once you get the basic game working, you can tune it to your tastes and desired difficulty level. Try experimenting with the different constants to control the game's speed and the maneuverability of the player. Feel free to experiment with colours, textures, or other additions. You can also modify your use of noise() to change the character of the game. As usual, creative and ambitious extensions will receive bonus marks.
Save your work in a sketch titled FlappyNoise in the A07 folder.
Submission
When you are ready to submit, please follow these steps.
Please ensure that any sketches you submit compile and run. It's better to submit a sketch that runs smoothly but implements fewer required features than one that has broken code for all features. If you get partway into a feature but can't make it work, comment it out so that the sketch works correctly without it.
If necessary, review the Code Style Guide and use Processing's built-in auto format tool. You do not need to use the precise coding style outlined in the guide, but whatever style you use, your code must be clear, concise, consistent, and commented.
If necessary, review the How To Submit document for a reminder on how to submit to LEARN.
Make sure to include a comment at the top of all source files containing your name and student ID number.
Create a zip file called A07.zip containing the entire A07 folder with its subfolders Pipes and FlappyNoise.
Upload A07.zip to LEARN. Remember that you can (and should!) submit as many times as you like. That way, if there's a catastrophe, you and the course staff will still have access to a recent version of your code.
If LEARN isn't working, and only if LEARN isn't working, please email your ZIP file to the course account (see the course home page for the address). In this case, you must mail your ZIP file before the deadline. Please use this only for emergencies, not "just in case". Submissions received after the deadline may receive feedback, but their marks will not count.