What if you put extra efforts on video game assignments----8
A downloadable game
Pongtato
Project Description
A simple breakout game with rouge-lite elements. Use mouse to control the paddle.
Assignment Rubrics
- 5 points - code is free of bugs and runs as designed
- 2 points - at least one class is used
- 3 points - code is commented, well formatted, and readable (no excessive whitespace, consistent variable, class, and function names, etc.)
- 5 points - postmortem that details the initial design, how it changed over the course of the development process, the things that went well, the problems you faced (programming or design), how you approached them, what you learned from the process of making this project, and what the future of this project might be
- Extra Credit (1 point) - the code/project is publicly available/playable on Github, your portfolio website, or itch.io.
My Code (Partially)
Cooperate with Davide
# Pongtato, imge credits goes to LORA model! # Global Variables gameState=0 TITLE_STATE=0 PLAY_STATE=1 GAME_OVER_STATE=2 STORE_PAGE = 3 enemyBallList=[] INITIAL_BALL_SIZE = 60 BALL_IMPACT_DECAY = 0.95 BALL_SIZE_DECAY = -0.02 # Variables here would need to reset after a match playerExp = 0 playerLevel = 1 expToNextLevel = 2 expIncrement = 3 enemyHP = 1 SpawnedEnemies = 0 playerBallSize = 60 playerBallPenPower = 1 playerBallStock = 5 enemyRespawnInterval = 30 ballReplenishInterval = 360 remainReplenishInterval = 360 currentScore = 0 playerBallList=[] paddlePosX=0 paddlePosY=0 paddleWidth=120 paddleHeight=40 # Possible Upgrade List upgradeList = ["Ball Size increase", "Paddle Width increase", "Ball Penetration Power + 1", "Ball Stock + 3", "Enemies Refresh Frequency Decrease"] currentStoreList = [] titleImg = None #____________Main Functions___________# def setup(): global paddlePosX,paddlePosY,paddleWidth,paddleHeight, titleImg size(960,480) background(0) textSize(32) titleImg = loadImage("title.png") def draw(): background(0) if gameState==TITLE_STATE: drawTitleScreen() elif gameState==PLAY_STATE: drawPlayScreen() elif gameState==GAME_OVER_STATE: drawGameOverScreen() elif gameState == STORE_PAGE: drawStorePage() #__________Sub Draw Functions___________# def drawTitleScreen(): # textSize(64) # textAlign(CENTER) # text("Pongtato",width/2,height/2) # textSize(32) # textAlign(LEFT) # text("Today's Date:"+str(month())+"-"+str(day())+"-"+str(year()),20,40) # textAlign(RIGHT) # text(str(hour())+":"+nf(minute(),2)+":"+nf(second(),2),width-20,40) # textAlign(CENTER) # Load title Image imageMode(CENTER) image(titleImg, width / 2, height / 2 - 50, 400, 400) textSize(30) textAlign(RIGHT, BOTTOM) text("Press P to Start",width - 20,height - 30) textSize(20) textAlign(LEFT) tempY = 30 tempX = 40 text("Tutorial:", 100 - tempX, 350 + tempY) text("1. Press SpaceBar to fire the ball.", 120 - tempX, 375 + tempY) text("2. Avoid incoming empty balls, Catch soild ball.", 120 - tempX, 400 + tempY) text("3. Make sure to pick up the right upgrade!", 120 - tempX, 425 + tempY) def drawPlayScreen(): updatePaddle() enemySpawnController() resetBallCollision() UpdatePlayerBalls() UpdateEnemyBalls() updatePlayerExp() updateAutoReplenish() drawUI() def drawGameOverScreen(): global objects fill(255) textAlign(CENTER, CENTER) textSize(60) text("GAME OVER",width/2,height/2) textSize(30) text("Your Score is: " + str(currentScore), width/2, height/2 - 100) text("Press P to go Main Menu", width/2, height/2 + 100) objects=[] def drawStorePage(): global upgradeList, currentStoreList, gameState tempY = 30 tempYInc = 160 for i in range(3): if buttonCreation(100, tempY + tempYInc * i, 760, 100, upgradeList[currentStoreList[i]]): applyUpgrade(currentStoreList[i]) gameState = PLAY_STATE else: pass #______________Helper Functions____________# def updatePaddle(): global paddlePosY,paddlePosX paddlePosX=mouseX paddlePosY=height rectMode(CENTER) fill(255) rect(paddlePosX,paddlePosY,paddleWidth,paddleHeight) def enemySpawnController(): global enemyHP, SpawnedEnemies if SpawnedEnemies / 10 > enemyHP: enemyHP += 1 if frameCount % enemyRespawnInterval == 0: startPos=PVector(random(0,width), 30) tempVel=PVector(random(0,1), random(0,2)) tempColor=color(random(120, 255), random(120, 255), random(120, 255)) newEnemyBall=EnemyBall(startPos,tempVel,INITIAL_BALL_SIZE,tempColor,enemyHP) enemyBallList.append(newEnemyBall) SpawnedEnemies += 1 # Apply upgrade to current game def applyUpgrade(upgradeNum): global playerBallSize, paddleWidth, playerBallPenPower, enemyRespawnInterval, playerBallStock # Number corrdinate to "upgradeList" order if upgradeNum == 0: playerBallSize += 20 elif upgradeNum == 1: paddleWidth += 40 elif upgradeNum == 2: playerBallPenPower += 1 elif upgradeNum == 3: playerBallStock += 3 elif upgradeNum == 4: enemyRespawnInterval += 5 else: pass def keyPressed(): global gameState,startTime # gameState change if key =="p" or key=="P": if gameState==TITLE_STATE: gameState=PLAY_STATE startTime=millis() # elif gameState==PLAY_STATE: # gameState=GAME_OVER_STATE elif gameState==GAME_OVER_STATE: gameState=TITLE_STATE resetGameConst() # Fire the ball if key==" ": global playerBallStock if playerBallStock >= 1: startPos=PVector(mouseX, height - playerBallSize / 2 - paddleHeight) tempVel=PVector(random(0,4), random(0,10)) tempColor=color(random(120, 255), random(120, 255), random(120, 255)) tempVel.normalize().mult(11) # tempVel2=PVector(random(10,10), random(4,4)) newPlayerBall=PlayerBall(startPos,tempVel, playerBallSize, tempColor,1) playerBallList.append(newPlayerBall) playerBallStock -= 1 # Update EnemyBall Behavior and attributes def UpdateEnemyBalls(): global gameState,enemyBallList,playerBallList for ball in enemyBallList: ball.update() ball.render() if ball.rad<0: enemyBallList.remove(ball) if ball.collision(paddlePosX,paddlePosY,paddleWidth,paddleHeight): enemyBallList=[] playerBallList=[] gameState=GAME_OVER_STATE # Update Player ball behavior and attributes def UpdatePlayerBalls(): for playerBall in playerBallList: playerBall.EnemyCollision() playerBall.update() playerBall.render() playerBall.collision(paddlePosX,paddlePosY,paddleWidth,paddleHeight) # Update Player Exp, also some of the caculation happened in Player class (Though it is not great to do that there) def updatePlayerExp(): global playerExp, playerLevel, expToNextLevel, expIncrement, gameState, playerBallStock if playerExp >= expToNextLevel: playerExp = 0 playerLevel += 1 expToNextLevel += expIncrement expIncrement += 1 gameState = STORE_PAGE playerBallStock += 1 storeSetup() # Ball Auto-replenish Function def updateAutoReplenish(): global ballReplenishInterval, playerBallStock, remainReplenishInterval if remainReplenishInterval <= 0: playerBallStock += 1 remainReplenishInterval = ballReplenishInterval else: remainReplenishInterval -= 1 # Only call once before everytime player open store def storeSetup(): global currentStoreList, mouseClickPasser mouseClickPasser = False currentStoreList = [] for i in range(3): # TODO: check repetition of elements tempInt = int(random(0, len(upgradeList))) currentStoreList.append(tempInt) # Reset game's constants def resetGameConst(): global currentScore, remainReplenishInterval, ballReplenishInterval, playerExp, playerLevel, expToNextLevel, enemyHP, SpawnedEnemies, playerBallSize, playerBallPenPower, playerBallStock, enemyRespawnInterval, paddleWidth playerExp = 0 playerLevel = 1 expToNextLevel = 2 enemyHP = 1 SpawnedEnemies = 0 playerBallSize = 60 playerBallPenPower = 1 playerBallStock = 5 enemyRespawnInterval = 30 ballReplenishInterval = 360 remainReplenishInterval = 360 paddleWidth=120 currentScore = 0 # Collision detect def offScreen(vector, rad): rad /= 2 if vector.x - rad < 0: return 1 # N elif vector.y + rad > height: return 2 # E elif vector.x + rad > width: return 3 # S elif vector.y - rad < 0: return 4 # W return 0 # reflect 2 balls while collide def reflect(ball1, ball2): normal = PVector.sub(ball1.pos, ball2.pos) normal.normalize() dot = 2 * ball1.vel.dot(normal) ball1.vel.sub(PVector.mult(normal, dot)) normal = PVector.mult(normal, -1) dot2 = 2 * ball2.vel.dot(normal) ball2.vel.sub(PVector.mult(normal, dot2)) # Reset Collision def resetBallCollision(): for enemyBall in enemyBallList: enemyBall.collidedThisFrame = False for playerBall in playerBallList: playerBall.collidedThisFrame = False # Reuse previous buttonCreation function for store page def buttonCreation(posX, posY, sizeX, sizeY, tempText): global mouseClickPasser rectMode(CORNER) textAlign(CENTER,CENTER) if (mouseX < posX + sizeX) and (mouseX > posX) and (mouseY < posY + sizeY) and (mouseY > posY): fill(200, 200, 250) rect(posX, posY, sizeX, sizeY) fill(40) textSize(30) text(tempText, posX + 0.5 * sizeX, posY + 0.5 * sizeY) if mouseClickPasser: mouseClickPasser = False return True else: fill(100, 100, 130) rect(posX, posY, sizeX, sizeY) fill(250) textSize(20) text(tempText, posX + 0.5 * sizeX, posY + 0.5 * sizeY) return False # ButtonCreation helper function def mouseClicked(): global mouseClickPasser mouseClickPasser = True #______________Render UIs_____________# def drawUI(): drawExpBar() drawRemainingBalls() drawReplenishBar() drawScore() # drawTime() def drawExpBar(): fill(100, 100, 255, 80) expPercentage = float(playerExp) / expToNextLevel rectMode(CORNER) rect(0, 0, expPercentage * width, 30) fill(255) textAlign(LEFT) textSize(30) text("level: " + str(playerLevel), 80, 30) def drawRemainingBalls(): textAlign(LEFT) textSize(30) text("Remaining Balls: " + str(playerBallStock), 380, 30) def drawTime(): offsetTime=millis()-startTime seondsString=str(offsetTime/1000) middleString=str((offsetTime%1000-(offsetTime%100))/100) millisecondsString=nf(offsetTime%100,2) offsetString=seondsString+":"+middleString+":"+millisecondsString textAlign(CENTER) fill(255) text(offsetString+"\n"+str(offsetTime),width/2,height/2) def drawReplenishBar(): fill(100, 255, 100, 80) rectMode(CORNER) tempBar = float(remainReplenishInterval) / ballReplenishInterval rect(0, 30, tempBar * width, 10) def drawScore(): textAlign(RIGHT) textSize(30) fill(255) text("Score: " + str(currentScore), width - 100, 30) #__________EnemyBall Class_________# class EnemyBall: def __init__(self,tempPos,tempVel,tempSize,tempColor,enemyHP): self.pos=tempPos self.vel=tempVel self.rad=tempSize self.col=tempColor self.enemyHP=enemyHP self.colliedThisFrame=False def update(self): global playerExp, currentScore self.pos+= self.vel # Collision whichWall = offScreen(self.pos, self.rad) if whichWall > 0: self.rad *= BALL_IMPACT_DECAY if whichWall == 1 or whichWall == 3: self.vel.rotate(PI - 2*self.vel.heading()) else: self.vel.rotate(-2 * self.vel.heading()) # Self Decay if self.rad > 0: if self.rad > INITIAL_BALL_SIZE/4: self.rad += BALL_SIZE_DECAY else: self.rad += BALL_SIZE_DECAY * 10 # HP control if self.colliedThisFrame==True: self.enemyHP-=1 self.colliedThisFrame=False # Remove if self.enemyHP <= 0: enemyBallList.remove(self) playerExp += 1 currentScore += enemyHP * 1000 def render(self): pushStyle() fill(0,0,0,0) stroke(self.col, 255 * self.rad/float(INITIAL_BALL_SIZE)) ellipse(self.pos.x, self.pos.y, self.rad, self.rad) fill(self.col) text(self.enemyHP,self.pos.x,self.pos.y) popStyle() # Collide with 4 walls def collision(self,paddlePosX,paddlePosY,paddleWidth,paddleHeight): if self.pos.x> paddlePosX-paddleWidth/2 and self.pos.x<paddlePosX+paddleWidth/2: if self.pos.y + self.rad / 2 >paddlePosY - paddleHeight / 2 and self.pos.y + self.rad / 2< paddlePosY + paddleHeight / 2: return True return False #_________PlayerBall Class__________# class PlayerBall(EnemyBall): def update(self): # Collision, but only collide with up, left, right walls self.pos += self.vel #/10.0 whichWall = offScreen(self.pos, self.rad) if whichWall > 0: if whichWall == 1: # Ensure ball won't struck on the left edge if self.vel.x < 0: self.vel.rotate(PI - 2*self.vel.heading()) else: pass elif whichWall == 3: # Ensure ball won't struck on the right edge if self.vel.x > 0: self.vel.rotate(PI - 2*self.vel.heading()) else: pass elif whichWall == 4: # Ensure ball won't struck on the top edge if self.vel.y < 0: self.vel.rotate(-2*self.vel.heading()) else: pass else: playerBallList.remove(self) def render(self): pushStyle() fill(255) circle(self.pos.x, self.pos.y, self.rad) fill(self.col) #text(self.enemyHP,self.pos.x,self.pos.y) popStyle() # Very simple window border collision def collision(self,paddlePosX,paddlePosY,paddleWidth,paddleHeight): if self.pos.x>paddlePosX-paddleWidth/2 - self.rad / 3 and self.pos.x<paddlePosX+paddleWidth/2 + self.rad / 3: if self.pos.y + self.rad / 2 >paddlePosY - paddleHeight / 2 and self.pos.y + self.rad / 2< paddlePosY + paddleHeight / 2: self.vel.rotate(-2 * self.vel.heading()) # Enemyball collision detection (This won't function correctly if playerball is tangent to enemyball, it will lock to the edge of enemyball) def EnemyCollision(self): for enemyball in enemyBallList: for playerball in playerBallList: if not playerball.collidedThisFrame and not enemyball.collidedThisFrame: if dist(playerball.pos.x, playerball.pos.y, enemyball.pos.x, enemyball.pos.y) < (playerball.rad/2 + enemyball.rad/2): reflect(playerball, enemyball) playerball.collidedThisFrame = True enemyball.collidedThisFrame = True enemyball.enemyHP -= playerBallPenPower
Screenshot
Download
Download
application.windows64.zip 44 MB
Install instructions
Java 8 required
Leave a comment
Log in with itch.io to leave a comment.