What if you put extra efforts on video game assignments----3
A downloadable game
Ball Catcher V2
Project Description
A simple falling ball catching game with advanced (compare to original V1) , without using OOB. Use keyboard to control the catcher. Further, there are other types of balls either worth more points or give extra lives.
Assignment Rubrics
- 4 points - use arrays and loops to programmatically move the falling objects (that means more than one falling object!)
- 1 point - the catching object must move based on player input (using the same method as last time is fine)
- 4 points - collision detection between the two objects now done with loops and arrays (distance or rectangular, depending on visuals)
- 1 point - the falling objects respawns to a random location when caught or fall off the screen
- Extra Credit (1 point) - display a score and design a more complex scoring system (eg. different point values, multipliers, etc.)
- Extra Credit (2 points) - add hysteresis to the player controlled object and/or the score display (check out the first minute or so from this video to see what that might look like: Super Mario 64 Coin Count (Links to an external site.))
My Code
#Falling Object Game V2(PesudoVer) import copy #Create dict for normal ball normalBallDict = { "posX":random(20,580), "posY":-20, "rad":15, "speed":2.3, "ballType":"normal", "ballColor":"#ffffff", "score":10, "refreshInterval":200, "minimumRefreshInterval":30, "intervalIncrement":10, "acceleration":0.03, "accelerationIncrement":0.001, } #Create dict for slow big ball slowBallDict = { "posX":random(30,570), "posY":-30, "rad":30, "speed":0.1, "ballType":"big", "ballColor":"#ff6524", "score":100, "refreshInterval":600, "minimumRefreshInterval":60, "intervalIncrement":20, "acceleration":0.1, "accelerationIncrement":0.1, } #Create dict for fast w/ extra life ball fastBallDict = { "posX":random(30,570), "posY":-20, "rad":10, "speed": 10, "ballType":"fast", "ballColor":"#84f23f", "score":50, "refreshInterval":800, "minimumRefreshInterval":100, "intervalIncrement":30, "acceleration":0.2, "accelerationIncrement":0.5, } #Create Catcher's dict catcher = { "posX":0, "posY":0, "acce":2, "maxSpd":15, "curSpd":0, #define moving to left as "negative" speed, and vise versa "width":200, "height":20, "cornerRounding":10, "btmDistance":100, "yTolerance":10, "color":"#ffffff", } #Game Status, 0 = menu, 1 = in-game, 2 = failscreen (showScore) gameStatus = 0 #Create list to store all ball's info ballList = [] #Create some global vars for current playing match gameInProgress = False #gameInProgress = True #DEBUG playerLifesConst = 5 playerLifes = playerLifesConst trueScore = 0 displayedScore = 0 highestScore = 0 frameSinceGame = 0 normalBallRefreshInterval = normalBallDict['refreshInterval'] slowBallRefreshInterval = slowBallDict['refreshInterval'] fastBallRefreshInterval = fastBallDict['refreshInterval'] screenResolutionWidth = 600 screenResolutionHeight = 800 playerPressedKey = "nothingPressed" #have 3 type, nothing/left/right def interfaceSelector(): if gameStatus == 0: drawMenu() elif gameStatus == 1: drawGame() elif gameStatus == 2: drawScore() def drawMenu(): #TODO: make menu here, change gameStatus to 1 when player click play drawColorfulBackground() drawTitle() drawInteractiveButton("Play") def drawColorfulBackground(): cirRad = 50 for column in range(screenResolutionWidth / cirRad + 2): for row in range(screenResolutionHeight / cirRad + 2): fill(frameCount % 255, (frameCount + column * cirRad) % 255, (frameCount - row * cirRad) % 255) circle(column * cirRad + frameCount % cirRad, row * cirRad + frameCount % cirRad, cirRad * 3) def drawTitle(): #f = loadFont("TheBomb-7B9gw.ttf") #textFont(f) #Nah, font won't work textSize(100) fill("#4f099e") text("Catcher", 150, 300) def drawInteractiveButton(inputText): global gameStatus, trueScore, displayedScore #the box should be 400 x 100, on 300, 500 if (mouseX < 500 and mouseX > 100 and mouseY < 550 and mouseY > 450): fill("#1483a8") rect(300, 500, 460, 130, 30, 30, 30, 30) fill("#3ccafa") textSize(100) text(inputText, 210, 520) if mousePressed: gameStatus = 1 trueScore = 0 displayedScore = 0 else: fill("#3361a6") rect(300, 500, 400, 100, 20, 20, 20, 20) fill("#6ea2f0") textSize(80) text(inputText, 220, 520) def drawGame(): #TODO: mainGame goes here global ballList, gameInProgress, frameSinceGame, gameStatus, catcher, playerLifes, normalBallRefreshInterval, slowBallRefreshInterval, fastBallRefreshInterval #print("Draw Game Running", gameInProgress) #DEBUG if gameInProgress == False: #Initializing game here gameInProgress = True #ballList.clear() # Clear function in python is not working in Processing's python D: #have to use some methods to find a workaround #Reseting Game emptyList = [] ballList = emptyList #add first ball to the game here newBallDict = copy.deepcopy(normalBallDict) ballList.append(newBallDict) playerLifes = playerLifesConst trueScore = 0 displayedScore = 0 #Init catcher's pos catcher['posY'] = screenResolutionHeight - catcher['btmDistance'] catcher['posX'] = screenResolutionWidth / 2 #ball's refresh interval reset normalBallRefreshInterval = normalBallDict['refreshInterval'] slowBallRefreshInterval = slowBallDict['refreshInterval'] fastBallRefreshInterval = fastBallDict['refreshInterval'] print(normalBallRefreshInterval) #CountFrames since this match start frameSinceGame = 0 else: frameSinceGame += 1 #Go scoreBoard if failed if playerLifes <= 0: gameInProgress = False gameStatus = 2 #gameStatus = 1 #test before code scoreboard #background(0) #nah, I'm not gonna use black background anymore drawColorfulBackground() fill(40 ,40 ,40 , 200) rect(screenResolutionWidth / 2, screenResolutionHeight / 2, screenResolutionWidth, screenResolutionHeight) ballCreator() #print("ballCreator Runs!") ballIterator() #print("ballIterator Runs!") updateCatcher() #print("updateCatcher Runs!") updateUI() #print("updateUI Runs!") def ballCreator(): global ballList, normalBallRefreshInterval, slowBallRefreshInterval, fastBallRefreshInterval #when frame reached normal ball refresh interval if (frameSinceGame % normalBallRefreshInterval) == 0: newBallDict = copy.deepcopy(normalBallDict) newBallDict['posX'] = random(20,580) ballList.append(newBallDict) #print("New normal ball added") normalBallRefreshInterval -= normalBallDict['intervalIncrement'] if normalBallRefreshInterval <= normalBallDict['minimumRefreshInterval']: normalBallRefreshInterval = normalBallDict['minimumRefreshInterval'] #when frame reached big ball refresh interval if (frameSinceGame % slowBallRefreshInterval) == 0: newBallDict = copy.deepcopy(slowBallDict) newBallDict['posX'] = random(30,570) ballList.append(newBallDict) slowBallRefreshInterval -= slowBallDict['intervalIncrement'] print("New slow ball added") if slowBallRefreshInterval <= slowBallDict['minimumRefreshInterval']: slowBallRefreshInterval = slowBallDict['minimumRefreshInterval'] #when frame reached fast ball refresh interval if (frameSinceGame % fastBallRefreshInterval) == 0: newBallDict = copy.deepcopy(fastBallDict) newBallDict['posX'] = random(30,570) ballList.append(newBallDict) fastBallRefreshInterval -= fastBallDict['intervalIncrement'] print("New fast ball added") if fastBallRefreshInterval <= fastBallDict['minimumRefreshInterval']: fastBallRefreshInterval = fastBallDict['minimumRefreshInterval'] def ballIterator(): global ballList, playerLifes, trueScore #Check collision, if not colliding, update position for ballElement in ballList: if checkBtmCollision(ballElement): playerLifes -= 1 ballList.remove(ballElement) elif checkCatcherCollision(ballElement): if ballElement['ballType'] == "fast": playerLifes += 1 trueScore += ballElement['score'] #print("score added") ballList.remove(ballElement) else: updateBalls(ballElement) #Include drawing part def checkBtmCollision(ballElement): #TODO: check is this ball colliding with Bottom or not, return boolean ballPosY = ballElement['posY'] ballRad = ballElement['rad'] if (ballPosY + ballRad) > screenResolutionHeight: #print("touch BTM") return True return False def checkCatcherCollision(ballElement): #TODO: check is this ball colliding with catcher or not, return boolean ballPosX = ballElement['posX'] ballPosY = ballElement['posY'] ballRad = ballElement['rad'] #calculate Y-axis collision first, should between a range of tolerance upperBound = (screenResolutionHeight - catcher['btmDistance']) - (catcher['height'] / 2.0) lowerBound = upperBound + catcher['yTolerance'] ballLowerBound = ballPosY + ballRad #then calculate X-axis collision leftBound = (catcher['posX'] - (catcher['width'] / 2.0)) ballLeftBound = ballPosX - (ballRad * (2.0 / 3.0)) rightBound = (catcher['posX'] + (catcher['width'] / 2.0)) ballRightBound = ballPosX + (ballRad * (2.0 / 3.0)) #print(ballRightBound, rightBound) if((ballRightBound < rightBound) and (ballLeftBound > leftBound)): #print("within x range") if ((ballLowerBound < lowerBound) and (ballLowerBound > upperBound)): #print("touched catcher") return True return False def updateBalls(ballElement): #TODO: update all balls pos and other attributes ballElement['posY'] += ballElement['speed'] ballElement['speed'] += ballElement['acceleration'] fill(ballElement['ballColor']) circle(ballElement['posX'], ballElement['posY'], ballElement['rad'] * 2) def detectInput(): global playerPressedKey if keyPressed: #if keyCode == LEFT and keyCode == RIGHT #Ummmm, Processing can't handle keys pressed at the same time properly if keyCode == LEFT: playerPressedKey = "leftPressed" elif keyCode == RIGHT: playerPressedKey = "rightPressed" else: playerPressedKey = "nothingPressed" def updateCatcher(): #TODO: update catcher's pos global catcher detectInput() #print("detectInput Runs!", playerPressedKey) if playerPressedKey == "leftPressed": catcher['curSpd'] -= catcher['acce'] #check if speed is higher than maxSpd if abs(catcher['curSpd']) > catcher['maxSpd']: catcher['curSpd'] = -1 * catcher['maxSpd'] elif playerPressedKey == "rightPressed": catcher['curSpd'] += catcher['acce'] #check if speed is higher than maxSpd if abs(catcher['curSpd']) > catcher['maxSpd']: catcher['curSpd'] = catcher['maxSpd'] elif playerPressedKey == "nothingPressed": if abs(catcher['curSpd']) > catcher['acce']: if catcher['curSpd'] < 0: catcher['curSpd'] += catcher['acce'] else: catcher['curSpd'] -= catcher['acce'] else: catcher['curSpd'] = 0 #Finally, update pos catcher['posX'] += catcher['curSpd'] if (catcher['posX'] + catcher['width'] / 2.0) > screenResolutionWidth: catcher['posX'] = screenResolutionWidth - (catcher['width'] / 2.0) catcher['curSpd'] = 0 elif (catcher['posX'] - catcher['width'] / 2.0) < 0: catcher['posX'] = catcher['width'] / 2.0 catcher['curSpd'] = 0 #print(catcher['curSpd']) #draw catcher here fill(catcher['color']) rect(catcher['posX'], catcher['posY'], catcher['width'], catcher['height'], 0, 0, catcher['cornerRounding'], catcher['cornerRounding']) def updateUI(): global displayedScore #update displayedScorefirst! if displayedScore < trueScore: displayedScore += 1 textSize(30) fill(122, 255, 211) scoreText = ("Score: %i" % (displayedScore)) text(scoreText, 0, 30) lifeRemainText = ("Life: %i" % (playerLifes)) fill(238, 255, 112) text(lifeRemainText, 0, 60) def drawScore(): #TODO: draw scoreboard here global trueScore, displayedScore, highestScore #re-initialize scores when game is over drawScoreBoard() if trueScore > highestScore: highestScore = trueScore gameInProgress = False def drawScoreBoard(): drawColorfulBackground() fill(10, 10, 10, 200) rect(screenResolutionWidth / 2, screenResolutionHeight / 2, screenResolutionWidth - 60, screenResolutionHeight - 60, 10, 10, 10, 10) highScoreText = ("Highest Score: %i" % (highestScore)) curScoreText = ("Your Score: %i" % (trueScore)) fill(255) textSize(45) text(highScoreText, 100, 300) text(curScoreText, 100, 380) drawInteractiveButton("Reset") def setup(): size(screenResolutionWidth, screenResolutionHeight) stroke(0) frameRate(60) #framebased physics, yay rectMode(CENTER) def draw(): interfaceSelector()
Screenshot
Status | Released |
Author | bohdns |
Genre | Platformer |
Tags | 2D, Retro |
Download
Download
application.windows64.zip 42 MB
Leave a comment
Log in with itch.io to leave a comment.