Collab4 (Fri 9-Feb)

Collaborative, in-person, in recitation.


Notes:
  1. The same basic rules as collab1 apply here.
  2. Be sure to read this entire write-up before starting!
  3. Do not use lists, dicts, sets, or any topics not covered in Week4 or Hw4.

Part 1: Play Sine Runner on CS Academy
For this collab, you will be building the game Sine Runner. A playable demo version is available here or can be played below. You should play the game at all difficulty levels and with the scrolling version to understand what you will be making.




Part 2: Create Sine Runner
The main task today is to create the Sine Runner game.

Recommended Feature Implementation Order:
  1. Draw functions (without scrolling mode)
  2. Dot movement through user input
  3. Dot location check (if within bounds of waves)
  4. Game timer and display of elapsed time
  5. Game over condition and screen
  6. Scrolling mode

You should open the following starter code in your Sandbox. The starter code includes important hints!
Starter Code:

from cmu_graphics import *
import math, time

def onAppStart(app):
    app.level = None
    app.gameOver = True
    app.scrollingMode = False

# These functions define the path!
def easyF(x, t):   return 75*math.sin((x+t*10)/40)
def mediumF(x, t): return 100*math.sin((x+t*10)/35)
def hardF(x, t):   return 50*math.sin((x+t*10)/25) + 50*math.cos((x+t*10)/15)

def getPathCenterY(app, x):
    if app.scrollingMode:
        return 200 - app.fn(x, app.elapsedTime)
    else:
        return 200 - app.fn(x, 0)

def startGame(app, level):
    if level == 'e':
        app.level = 'Easy'
        app.fn = easyF
        app.startX = 100
        app.endX = 300
        app.dx = app.dy = 2
        app.pathHeight = 70
    elif level == 'm':
        app.level = 'Medium'
        app.fn = mediumF
        app.startX = 75
        app.endX = 325
        app.dx = app.dy = 3
        app.pathHeight = 60
    else:
        app.level = 'Hard'
        app.fn = hardF
        app.startX = 50
        app.endX = 350
        app.dx = app.dy = 3
        app.pathHeight = 50
    app.startTime = time.time()
    app.elapsedTime = 0
    app.gameOver = False
    app.x = app.startX
    app.y = getPathCenterY(app, app.x)

def redrawAll(app):
    # TO DO: 
    # Draw game over screen
    drawTitleAndInstructions(app)
    
    # TO DO:
    # Implement draw helper functions
    if app.level != None:
        drawSineWaves(app)
        drawDot(app)
        drawLevelAndElapsedTime(app)

def drawTitleAndInstructions(app):
    drawLabel('Sine Runner!', 200, 15, size=14, bold=True)
    drawLabel('Press e for easy, m for medium, h for hard', 200, 30)
    drawLabel('Use arrows to move right, up, or down', 200, 45)
    drawLabel('Go fast, but stay inside the curves', 200, 60)
    drawLabel('Press s to toggle scrolling mode', 200, 75)

def drawSineWaves(app):
    # TO DO:
    # Draw Sine Wave paths
    # Hint: the function getPathCenterY might be useful here!
    #       For speed of the app, draw sections of the Sine Wave 
    #       at 3 pixel intervals, using a change in X to draw 
    #       these short line segments!
    pass

def drawDot(app):
    # TO DO:
    # Draw dot
    # Hint: Resize dot based on path height, to make it easier to play 
    #       levels with narrow paths (we use app.pathHeight / 8)
    pass

def drawLevelAndElapsedTime(app):
    # TO DO: 
    # Draw Level message and elapsed time message
    # Hint: To print out a decimal to a certain number of decimal points
    #       Experiment with the following code:
    #           number = 17.3333089
    #           print(f'The number is {number:0.1f}')
    #           print(f'The number is {number:0.2f}')
    #           print(f'The number is {number:0.3f}')
    #       Using f-strings, you can choose the number of decimals following a
    #       numeric variable by adding ":0.xf" after the variable, where x is an
    #       integer!
    pass


def onKeyPress(app, key):
    # TO DO: 
    # Implement Game controls for starting game, changing modes
    pass

def onStep(app):
    # TO DO: 
    # Implement method to check the time elapsed
    # Hint: time.time() will provide the current time in seconds. Try 
    #       printing out time.time() and then printing it out again after a bit
    #       of time has passed!
    #
    #       Check in startGame for an app variable that could help you
    #       keep track of how long it has been since the game started
    #
    # Hint: When should you check if you have won? When should you check
    #       if the dot hit the edges of the sine curves?
    #       (Maybe use a helper function!)
    pass

def onKeyHold(app, keys):
    # TO DO:
    # Implement method to move the dot.
    # Hint: Reference the 'right' in keys case when coding the 'up' and 'down' case
    # Hint: When should you check if you have won? When should you check
    #       if the dot hit the edges of the sine curves? 
    #       (Maybe use a helper function!)

    # Move the player based on user input
    if app.level != None and not app.gameOver:
        if 'right' in keys:
            app.x += app.dx
        if 'up' in keys: 
            pass
        if 'down' in keys: 
            pass

def main():
    runApp()

main()
                    


Part 3 (optional): Share your game!
You can share the playable version of your game canvas through a link generated by CS Academy Sandbox.
  1. Run your animation in CS Academy Sandbox
  2. In the top right corner, click on the three dots (they are to the left of the X button)
  3. Press "Share canvas link"
  4. Press "Copy link and close"
If you're unsure how to do this, feel free to ask your TAs for help!
Time permitting:
If you finish the creative coding task above, you and your partners should add features and experiment with this game. Some ideas could include: Be creative and have fun!