diff --git a/__init__.py b/__init__.py index 486e223..d7e4ad1 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,12 @@ from cmu_112_graphics import * from splashScreenMode import * from originalGameMode import * +from sidescrollGameMode import * + +# run this file! + +# animation framework attained from +# http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html # from http://www.cs.cmu.edu/~112/notes/notes-animations-part2.html # #subclassing ModalApp @@ -8,6 +14,7 @@ class MyModalApp(ModalApp): def appStarted(app): app.splashScreenMode=SplashScreenMode() app.gameMode=OriginalGameMode() + app.scrollMode=SideScrollGameMode() app.setActiveMode(app.splashScreenMode) app.timerDelay=50 diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..becf397 --- /dev/null +++ b/demo.py @@ -0,0 +1,322 @@ +from cmu_112_graphics import * +from tkinter import * +import random + +# TP1 edited, works without ghosts +# not TP2 submission, will not be part of final project + +# CITATION: http://www.cs.cmu.edu/~112/notes/notes-animations-part2.html +# #subclassingModalApp +class SplashScreenMode(Mode): + def redrawAll(mode,canvas): + canvas.create_rectangle(0,0,mode.width,mode.height,fill="black") + font = 'Arial 26 bold' + canvas.create_text(mode.width/2, mode.height/5, \ + text='Pac Man', font=font, fill="white") + canvas.create_text(mode.width/2, mode.height/3, \ + text='Press space to start!',font=font,fill="white") + + def keyPressed(mode,event): + if event.key=="Space": + mode.app.setActiveMode(mode.app.gameMode) + + #will add buttons to determine mode + def mousePressed(mode,event): + pass + +# Pac-Man class defines characteristics of Pac-Man and draws Pac-Man +class PacMan(Mode): + def __init__(self,x,y): + self.x=x + self.y=y + self.radius=10 + self.color="yellow" + self.url="http://labs.phaser.io/assets/games/pacman/sprites32.png" + def drawPacMan(self,canvas): + canvas.create_oval(self.x-self.radius,self.y-self.radius,\ + self.x+self.radius,self.y+self.radius,fill=self.color) + +# Ghost class defines characteristics of ghosts, draws ghosts, +# and defines movement +class Ghost(Mode): + def __init__(self,x,y): + self.x=x + self.y=y + self.color=None + self.radius=10 + self.url="http://labs.phaser.io/assets/games/pacman/sprites32.png" + def drawGhost(self,canvas): + canvas.create_oval(self.x-self.radius,self.y-self.radius,\ + self.x+self.radius,self.y+self.radius,fill=self.color) + def moveGhost(self): + # each ghost will have its own algorithm to determine its + # path around the maze, can be implemented in this method in each + # ghost subclass + pass + +class Blinky(Ghost): + def __init__(self,x,y): + super().__init__(x,y) + self.color="red" + def moveGhost(self): + pass + # follows the shortest path to get to Pac-Man + +class Pinky(Ghost): + def __init__(self,x,y): + super().__init__(x,y) + self.color="pink" + def moveGhost(self): + pass + # follows the path to get to four tiles to the right or left of Pac-Man + +class Inky(Ghost): + def __init__(self,x,y): + super().__init__(x,y) + self.color="aqua" + def moveGhost(self): + pass + # follows the shortest path from Blinky to two tiles next to Pac-Man and + # doubles length in that direction + +class Clyde(Ghost): + def __init__(self,x,y): + super().__init__(x,y) + self.color="orange" + def moveGhost(self): + pass + # if less than 8 tiles away from Pac-Man, random mode but if not, same algorithm as Blinky + +# Wall class defines characteristics of walls and draws walls +class Wall(Mode): + def __init__(self,x,y,width,height): + self.x=x + self.y=y + self.width=width + self.height=height + self.color="blue" + def drawWall(self,canvas): + canvas.create_rectangle(self.x,self.y,\ + self.x+self.width,self.y+self.height,fill=self.color,width=0) + +# OriginalBoard class draws walls based on given dimensions +# original board is static, and the dimensions and coordinates are predetermined +class OriginalBoard(Wall): + def __init__(self,mode,x,y,width,height): + super().__init__(x,y,width,height) + self.ratio1=50/mode.width + #right wall + rightWall=Wall(2*self.x,2*self.y,self.width,\ + mode.height-4*self.height) + #left wall + leftWall=Wall(mode.width-3*self.x,2*self.y,self.width,\ + mode.height-4*self.height) + #top wall + topWall=Wall(2*self.x,2*self.y,mode.width-4*self.width,\ + self.height) + #bottom wall + bottomWall=Wall(2*self.x,mode.height-3*self.y,mode.width-4*self.width,\ + self.height) + #1 + wall11=Wall(10*self.x,20*self.y,10*self.width,50*self.height) + #5 + wall51=Wall(10*self.x+2*self.ratio1*mode.width,20*self.y,20*self.width,\ + 10*self.height) + wall52=Wall(10*self.x+2*self.ratio1*mode.width,20*self.y+10*self.height,\ + 10*self.width,20*self.height) + wall53=Wall(20*self.x+2*self.ratio1*mode.width,20*self.y+20*self.height,10*self.width,\ + 20*self.height) + wall54=Wall(10*self.x+2*self.ratio1*mode.width,20*self.y+40*self.height,20*self.width,\ + 10*self.height) + #dash + wallDash=Wall(10*self.x+45*self.width,20*self.y+20*self.width,\ + 20*self.width,10*self.height) + #1 + wall12=Wall(80*self.x,20*self.y,10*self.width,50*self.height) + #1 + wall13=Wall(100*self.x,20*self.y,10*self.width,50*self.height) + #2 + wall21=Wall(100*self.x+2*self.ratio1*mode.width,20*self.y,20*self.width,\ + 10*self.height) + wall22=Wall(110*self.x+2*self.ratio1*mode.width,20*self.y+10*self.height,\ + 10*self.width,20*self.height) + wall23=Wall(100*self.x+2*self.ratio1*mode.width,20*self.y+20*self.height,10*self.width,\ + 20*self.height) + wall24=Wall(100*self.x+2*self.ratio1*mode.width,20*self.y+40*self.height,20*self.width,\ + 10*self.height) + self.board=[wall11,wall51,wall52,wall53,wall54,wallDash,wall12,wall13,\ + wall21,wall22,wall23,wall24,rightWall,leftWall,topWall,bottomWall] + self.dimensions=set() + for wall in self.board: + self.dimensions.add((wall.x,wall.y,wall.width,wall.height)) + def drawBoard(self,canvas): + for wall in self.board: + wall.drawWall(canvas) + +# Points class defines characteristics of points and draws points +class Points(object): + def __init__(self,x,y): + self.x=x + self.y=y + self.radius=5 + def drawPoints(self,canvas): + canvas.create_oval(self.x-self.radius,self.y-self.radius,\ + self.x+self.radius,self.y+self.radius,fill="orange") + +# OriginalGameMode establishes original game mode with static board +# if time permits, may add randomly generated board without side scroll +class OriginalGameMode(Mode): + def appStarted(mode): + mode.radius=10 + mode.pointRadius=5 + mode.pacmanXPos,mode.pacmanYPos=mode.width/2,4*mode.height/5 + mode.ghostXPos,mode.ghostYPos=325,225 + mode.wallX,mode.wallY=mode.width/150,mode.height/100 + mode.wallWidth,mode.wallHeight=mode.width/150,mode.height/100 + mode.speed=5 + mode.dxPos,mode.dyPos=-1*mode.speed,0 + mode.currDirection="left" + mode.direction=mode.currDirection + mode.legalDirections=["up","right","down","left"] + mode.gameBoard=OriginalBoard(mode,mode.wallX,mode.wallY,\ + mode.wallWidth,mode.wallHeight) + mode.points=[] + mode.drawCoins() + mode.score=0 + mode.gameOver=False + + def keyPressed(mode,event): + if mode.gameOver==False: + if event.key=="Right": + mode.direction="right" + elif event.key=="Left": + mode.direction="left" + elif event.key=="Up": + mode.direction="up" + elif event.key=="Down": + mode.direction="down" + if mode.direction in mode.legalDirections: + mode.currDirection=mode.direction + mode.movePacMan(mode.currDirection) + else: + mode.movePacMan(mode.currDirection) + else: + if event.key=="r": + mode.appStarted() + mode.gameOver=False + + def movePacMan(mode,direction): + if direction=="right": + mode.dirPacMan(mode.speed,0) + elif direction=="left": + mode.dirPacMan(-1*mode.speed,0) + elif direction=="up": + mode.dirPacMan(0,-1*mode.speed) + elif direction=="down": + mode.dirPacMan(0,mode.speed) + + def timerFired(mode): + if mode.gameOver==False: + mode.legalDirections=mode.legalPlaces() + if mode.currDirection in mode.legalDirections: + mode.pacmanXPos+=mode.dxPos + mode.pacmanYPos+=mode.dyPos + i=0 + while iwall[0] and \ + mode.pacmanXPos-mode.radiuswall[1]+wall[3] and mode.pacmanYPos-mode.radius<=wall[1]+wall[3]): + if "up" in mode.legalDirections: + mode.legalDirections.remove("up") + elif (mode.pacmanYPos=wall[1]): + if "down" in mode.legalDirections: + mode.legalDirections.remove("down") + if mode.pacmanYPos+mode.radius>wall[1] and \ + mode.pacmanYPos-mode.radiuswall[0]+wall[2] and mode.pacmanXPos-mode.radius<=wall[0]+wall[2]): + if "left" in mode.legalDirections: + mode.legalDirections.remove("left") + elif (mode.pacmanXPos=wall[0]): + if "right" in mode.legalDirections: + mode.legalDirections.remove("right") + return mode.legalDirections + + def drawCoins(mode): + for x in range(int(mode.wallX*10),int(mode.width-3*mode.wallWidth),int(mode.wallX*10)): + for y in range(int(mode.wallY*10),int(mode.height-3*mode.wallHeight),int(mode.wallY*10)): + mode.points.append(Points(x,y)) + i=0 + while i < len(mode.points): + for wall in mode.gameBoard.dimensions: + if (mode.points[i].x>wall[0] and \ + mode.points[i].xwall[1]): + mode.points.pop(i) + i+=1 + + def redrawAll(mode,canvas): + canvas.create_rectangle(0,0,mode.width,mode.height,fill="black") + if mode.gameOver==False: + mode.gameBoard.drawBoard(canvas) + for coin in mode.points: + coin.drawPoints(canvas) + Blinky(mode.ghostXPos-mode.width/25,mode.ghostYPos).drawGhost(canvas) + Pinky(mode.ghostXPos-mode.width/75,mode.ghostYPos).drawGhost(canvas) + Inky(mode.ghostXPos+mode.width/75,mode.ghostYPos).drawGhost(canvas) + Clyde(mode.ghostXPos+mode.width/25,mode.ghostYPos).drawGhost(canvas) + PacMan(mode.pacmanXPos,mode.pacmanYPos).drawPacMan(canvas) + canvas.create_text(mode.width//2,15,text=f'Score:{mode.score}',\ + fill="white") + else: + font = 'Arial 26 bold' + canvas.create_text(mode.width//2,mode.height//2, + text='Game Over!', font=font, fill="white") + canvas.create_text(mode.width//2,3*mode.height//4, + text=f'Your score: {mode.score}',font=font,fill="white") + canvas.create_text(mode.width//2,5*mode.height//6, + text='Press r to restart',font=font,fill="white") + +# SidescrollGameMode will establish a randomly generated board every single time +# a new game starts, will allow the user to travel off screen +class SidescrollGameMode(Mode): + pass + +# CreativeMode will allow the user to create their own map, will play like +# original mode +class CreativeMode(Mode): + pass + +# MultiplayerMode will allow two users to player, one as ghost +# can play in original mode +class MultiplayerMode(Mode): + pass + +# from http://www.cs.cmu.edu/~112/notes/notes-animations-part2.html +# #subclassingModalApp +class MyModalApp(ModalApp): + def appStarted(app): + app.splashScreenMode=SplashScreenMode() + app.gameMode=OriginalGameMode() + app.setActiveMode(app.splashScreenMode) + app.timerDelay=50 + +app = MyModalApp(width=750, height=500) diff --git a/ghost.py b/ghost.py index ef6c8c5..1454bf6 100644 --- a/ghost.py +++ b/ghost.py @@ -1,55 +1,191 @@ from cmu_112_graphics import * +from pacman import * +from originalBoard import * # animation framework attained from # http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html # Ghost class defines characteristics of ghosts, draws ghosts, # and defines movement -class Ghost(Mode): - def __init__(self,x,y): - self.x=x - self.y=y - self.color=None +class Ghost(object): + def __init__(self): + self.speed=5 + self.x,self.y=0,0 + self.dx,self.dy=0,-1*self.speed, self.radius=10 + self.color=None + self.currDirection="down" + self.direction=self.currDirection + self.legalDirections=["up","right","down","left"] self.url="http://labs.phaser.io/assets/games/pacman/sprites32.png" - def drawGhost(self,canvas): - canvas.create_oval(self.x-self.radius,self.y-self.radius,\ - self.x+self.radius,self.y+self.radius,fill=self.color) + def dirSetter(self): + if self.currDirection=="right": + self.speedSetter(self.speed,0) + elif self.currDirection=="left": + self.speedSetter(-1*self.speed,0) + elif self.currDirection=="up": + self.speedSetter(0,-1*self.speed) + elif self.currDirection=="down": + self.speedSetter(0,self.speed) + def speedSetter(self,dx,dy): + self.dx=dx + self.dy=dy def moveGhost(self): # each ghost will have its own algorithm to determine its # path around the maze, can be implemented in this method in each # ghost subclass pass + def drawGhost(self,canvas): + canvas.create_oval(self.x-self.radius,self.y-self.radius,\ + self.x+self.radius,self.y+self.radius,fill=self.color) + +# determines direction based on Pinky's relative position to Pac-Man +class Pinky(Ghost): + def __init__(self): + super().__init__() + self.color="pink" + def moveGhost(self,x,y): #x,y are Pac-Man's position + if self.currDirection in self.legalDirections: + if y 0: + # Get the current node + current_node = open_list[0] + current_index = 0 + for index, item in enumerate(open_list): + if item.f < current_node.f: + current_node = item + current_index = index + # Pop current off open list, add to closed list + open_list.pop(current_index) + closed_list.append(current_node) + # Found the goal + if current_node == end_node: + path = [] + current = current_node + while current is not None: + path.append(current.position) + current = current.parent + return path[::-1] # Return reversed path + # Generate children + children = [] + for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: # Adjacent squares + # Get node position + node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1]) + # Make sure within range + if node_position[0] > (len(self.screen) - 1) or node_position[0] < 0 or node_position[1] > (len(self.screen[len(self.screen)-1]) -1) or node_position[1] < 0: + continue + # Make sure walkable terrain + if self.screen[node_position[0]][node_position[1]] != 0: + continue + # Create new node + new_node = Node(current_node, node_position) + # Append + children.append(new_node) + # Loop through children + for child in children: + # Child is on the closed list + for closed_child in closed_list: + if child == closed_child: + continue + # Create the f, g, and h values + child.g = current_node.g + 1 + child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2) + child.f = child.g + child.h + # Child is already in the open list + for open_node in open_list: + if child == open_node and child.g > open_node.g: + continue + # Add the child to the open list + open_list.append(child) class Inky(Ghost): - def __init__(self,x,y): - super().__init__(x,y) + def __init__(self): + super().__init__() self.color="aqua" - def moveGhost(self): + def moveGhost(self,mode): pass # follows the shortest path from Blinky to two tiles next to Pac-Man and # doubles length in that direction class Clyde(Ghost): - def __init__(self,x,y): - super().__init__(x,y) + def __init__(self): + super().__init__() self.color="orange" - def moveGhost(self): + def moveGhost(self,mode): pass # if less than 8 tiles away from Pac-Man, random mode but if not, same algorithm as Blinky \ No newline at end of file diff --git a/originalBoard.py b/originalBoard.py index 5441748..00624ba 100644 --- a/originalBoard.py +++ b/originalBoard.py @@ -4,18 +4,6 @@ # animation framework attained from # http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html -# Wall class defines characteristics of walls and draws walls -class Wall(Mode): - def __init__(self,x,y,width,height): - self.x=x - self.y=y - self.width=width - self.height=height - self.color="blue" - def drawWall(self,canvas): - canvas.create_rectangle(self.x,self.y,\ - self.x+self.width,self.y+self.height,fill=self.color,width=0) - # OriginalBoard class draws walls based on given dimensions # original board is static, and the dimensions and coordinates are predetermined class OriginalBoard(Wall): @@ -69,3 +57,11 @@ def __init__(self,mode,x,y,width,height): def drawBoard(self,canvas): for wall in self.board: wall.drawWall(canvas) + def drawCells(self,mode): + self.rows=mode.height//5 + self.cols=mode.width//5 + self.table=[[0]*self.cols for row in range(self.rows)] + for wall in mode.gameBoard.dimensions: + for row in range(int(wall[1])//5,int(wall[1])//5+int(wall[3])//5): + for col in range(int(wall[0])//5,int(wall[0])//5+int(wall[2])//5): + pass \ No newline at end of file diff --git a/originalGameMode.py b/originalGameMode.py index 6664b9a..9ea583d 100644 --- a/originalGameMode.py +++ b/originalGameMode.py @@ -15,17 +15,19 @@ class OriginalGameMode(Mode): def appStarted(mode): mode.radius=10 mode.pointRadius=5 - mode.pacmanXPos,mode.pacmanYPos=mode.width/2,4*mode.height/5 - mode.ghostXPos,mode.ghostYPos=13*mode.width/30,9*mode.height/20 + mode.speed=5 + + mode.pacman=PacMan() + mode.blinky=Blinky() + mode.pinky=Pinky() + mode.pacman.x,mode.pacman.y=mode.width/2,4*mode.height/5 + mode.pinky.x,mode.pinky.y=13*mode.width/30,7*mode.height/20 + mode.wallX,mode.wallY=mode.width/150,mode.height/100 mode.wallWidth,mode.wallHeight=mode.width/150,mode.height/100 - mode.speed=5 - mode.dxPos,mode.dyPos=-1*mode.speed,0 - mode.currDirection="left" - mode.direction=mode.currDirection - mode.legalDirections=["up","right","down","left"] mode.gameBoard=OriginalBoard(mode,mode.wallX,mode.wallY,\ mode.wallWidth,mode.wallHeight) + mode.points=[] mode.drawCoins() mode.score=0 @@ -34,43 +36,30 @@ def appStarted(mode): def keyPressed(mode,event): if mode.gameOver==False: if event.key=="Right": - mode.direction="right" + mode.pacman.direction="right" elif event.key=="Left": - mode.direction="left" + mode.pacman.direction="left" elif event.key=="Up": - mode.direction="up" + mode.pacman.direction="up" elif event.key=="Down": - mode.direction="down" - if mode.direction in mode.legalDirections: - mode.currDirection=mode.direction - mode.movePacMan(mode.currDirection) - else: - mode.movePacMan(mode.currDirection) + mode.pacman.direction="down" else: if event.key=="r": mode.appStarted() mode.gameOver=False - def movePacMan(mode,direction): - if direction=="right": - mode.dirPacMan(mode.speed,0) - elif direction=="left": - mode.dirPacMan(-1*mode.speed,0) - elif direction=="up": - mode.dirPacMan(0,-1*mode.speed) - elif direction=="down": - mode.dirPacMan(0,mode.speed) - def timerFired(mode): if mode.gameOver==False: - mode.legalDirections=mode.legalPlaces() - if mode.currDirection in mode.legalDirections: - mode.pacmanXPos+=mode.dxPos - mode.pacmanYPos+=mode.dyPos + mode.pacman.legalDirections=mode.legalPlaces(mode.pacman.x,mode.pacman.y) + mode.pacman.movePacMan() + mode.pinky.legalDirections=mode.legalPlaces(mode.pinky.x,mode.pinky.y) + mode.pinky.moveGhost(mode.pacman.x,mode.pacman.y) + if mode.pinky.x==mode.pacman.x and mode.pinky.y==mode.pacman.y: + mode.gameOver=True i=0 while iwall[0] and \ - mode.pacmanXPos-mode.radiuswall[1]+wall[3] and mode.pacmanYPos-mode.radius<=wall[1]+wall[3]): - if "up" in mode.legalDirections: - mode.legalDirections.remove("up") - elif (mode.pacmanYPos=wall[1]): - if "down" in mode.legalDirections: - mode.legalDirections.remove("down") - if mode.pacmanYPos+mode.radius>wall[1] and \ - mode.pacmanYPos-mode.radiuswall[0]+wall[2] and mode.pacmanXPos-mode.radius<=wall[0]+wall[2]): - if "left" in mode.legalDirections: - mode.legalDirections.remove("left") - elif (mode.pacmanXPos=wall[0]): - if "right" in mode.legalDirections: - mode.legalDirections.remove("right") - return mode.legalDirections + if x+mode.radius>wall[0] and \ + x-mode.radiuswall[1]+wall[3] and y-mode.radius<=wall[1]+wall[3]): + if "up" in legalDirections: + legalDirections.remove("up") + elif (y=wall[1]): + if "down" in legalDirections: + legalDirections.remove("down") + if y+mode.radius>wall[1] and \ + y-mode.radiuswall[0]+wall[2] and x-mode.radius<=wall[0]+wall[2]): + if "left" in legalDirections: + legalDirections.remove("left") + elif (x=wall[0]): + if "right" in legalDirections: + legalDirections.remove("right") + return legalDirections def drawCoins(mode): for x in range(int(mode.wallX*10),int(mode.width-3*mode.wallWidth),int(mode.wallX*10)): - for y in range(int(mode.wallY*10),int(mode.height-3*mode.wallHeight),int(mode.wallY *10)): + for y in range(int(mode.wallY*10),int(mode.height-3*mode.wallHeight),int(mode.wallY*10)): mode.points.append(Points(x,y)) for wall in mode.gameBoard.dimensions: for point in mode.points: @@ -123,11 +108,8 @@ def redrawAll(mode,canvas): mode.gameBoard.drawBoard(canvas) for coin in mode.points: coin.drawPoints(canvas) - Blinky(mode.ghostXPos-mode.width/25,mode.ghostYPos).drawGhost(canvas) - Pinky(mode.ghostXPos-mode.width/75,mode.ghostYPos).drawGhost(canvas) - Inky(mode.ghostXPos+mode.width/75,mode.ghostYPos).drawGhost(canvas) - Clyde(mode.ghostXPos+mode.width/25,mode.ghostYPos).drawGhost(canvas) - PacMan(mode.pacmanXPos,mode.pacmanYPos).drawPacMan(canvas) + mode.pacman.drawPacMan(canvas) + mode.pinky.drawGhost(canvas) canvas.create_text(mode.width//2,15,text=f'Score:{mode.score}',\ fill="white") else: diff --git a/pacman.py b/pacman.py index 59865ab..a5bf6b7 100644 --- a/pacman.py +++ b/pacman.py @@ -4,13 +4,36 @@ # http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html # Pac-Man class defines characteristics of Pac-Man and draws Pac-Man -class PacMan(Mode): - def __init__(self,x,y): - self.x=x - self.y=y +class PacMan(object): + def __init__(self): + self.speed=5 + self.x,self.y=0,0 + self.dx,self.dy=-1*self.speed,0 self.radius=10 self.color="yellow" + self.currDirection="left" + self.direction=self.currDirection + self.legalDirections=["up","right","down","left"] self.url="http://labs.phaser.io/assets/games/pacman/sprites32.png" + def dirSetter(self): + if self.currDirection=="right": + self.speedSetter(self.speed,0) + elif self.currDirection=="left": + self.speedSetter(-1*self.speed,0) + elif self.currDirection=="up": + self.speedSetter(0,-1*self.speed) + elif self.currDirection=="down": + self.speedSetter(0,self.speed) + def speedSetter(self,dx,dy): + self.dx=dx + self.dy=dy + def movePacMan(self): + if self.direction in self.legalDirections: + self.currDirection=self.direction + self.dirSetter() + if self.currDirection in self.legalDirections: + self.x+=self.dx + self.y+=self.dy def drawPacMan(self,canvas): canvas.create_oval(self.x-self.radius,self.y-self.radius,\ - self.x+self.radius,self.y+self.radius,fill=self.color) + self.x+self.radius,self.y+self.radius,fill=self.color) \ No newline at end of file diff --git a/path algo.py b/path algo.py new file mode 100644 index 0000000..dcbe274 --- /dev/null +++ b/path algo.py @@ -0,0 +1,177 @@ +from cmu_112_graphics import * +# animation framework attained from +# http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html + +# this file is a test file for the algorithm, currently not running in the game + +# node class for a* path-finding for Blinky +# program attained from +# https://medium.com/@nicholas.w.swift/easy-a-star-pathfinding-7e6689c7f7b2 + +class Node(object): + def __init__(self, parent=None, position=None): + self.parent = parent + self.position = position + self.g = 0 + self.h = 0 + self.f = 0 + def __eq__(self, other): + return (self.position == other.position) + +# Returns a list of tuples as a path from the given start to the given end in the given maze +def astar(maze, start, end): + #start=(int(start[0])//5,int(start[1])//5) + #end=(int(end[0])//5,int(end[1])//5) + # Create start and end node + start_node = Node(None, start) + start_node.g = start_node.h = start_node.f = 0 + end_node = Node(None, end) + end_node.g = end_node.h = end_node.f = 0 + # Initialize both open and closed list + open_list = [] + closed_list = [] + # Add the start node + open_list.append(start_node) + # Loop until you find the end + while len(open_list) > 0: + # Get the current node + current_node = open_list[0] + current_index = 0 + for index, item in enumerate(open_list): + if item.f < current_node.f: + current_node = item + current_index = index + # Pop current off open list, add to closed list + open_list.pop(current_index) + closed_list.append(current_node) + # Found the goal + if current_node == end_node: + path = [] + current = current_node + while current is not None: + path.append(current.position) + current = current.parent + return path[::-1] # Return reversed path + # Generate children + children = [] + for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: # Adjacent squares + # Get node position + node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1]) + # Make sure within range + if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0: + continue + # Make sure walkable terrain + if maze[node_position[0]][node_position[1]] != 0: + continue + # Create new node + new_node = Node(current_node, node_position) + # Append + children.append(new_node) + # Loop through children + for child in children: + # Child is on the closed list + for closed_child in closed_list: + if child == closed_child: + continue + # Create the f, g, and h values + child.g = current_node.g + 1 + child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2) + child.f = child.g + child.h + # Child is already in the open list + for open_node in open_list: + if child == open_node and child.g > open_node.g: + continue + # Add the child to the open list + open_list.append(child) + +#test cases +board=[[0,0,0,0,0], + [0,0,0,0,0], + [0,0,1,0,0], + [0,0,1,0,0], + [0,0,0,0,0]] + +start=(0,0) +end=(4,4) + +print(astar(board,start,end)) + +# Wall class defines characteristics of walls and draws walls +class Wall(object): + def __init__(self,x,y,width,height): + self.x=x + self.y=y + self.width=width + self.height=height + self.color="blue" + def drawWall(self,canvas): + canvas.create_rectangle(self.x,self.y,\ + self.x+self.width,self.y+self.height,fill=self.color,width=0) + +class OriginalBoard(Wall): + def __init__(self,x,y,width,height): + super().__init__(x,y,width,height) + self.ratio1=50/750 + #right wall + rightWall=Wall(2*self.x,2*self.y,self.width,\ + 500-4*self.height) + #left wall + leftWall=Wall(750-3*self.x,2*self.y,self.width,\ + 500-4*self.height) + #top wall + topWall=Wall(2*self.x,2*self.y,500-4*self.width,\ + self.height) + #bottom wall + bottomWall=Wall(2*self.x,500-3*self.y,750-4*self.width,\ + self.height) + #1 + wall11=Wall(10*self.x,20*self.y,10*self.width,50*self.height) + #5 + wall51=Wall(10*self.x+2*self.ratio1*750,20*self.y,20*self.width,\ + 10*self.height) + wall52=Wall(10*self.x+2*self.ratio1*750,20*self.y+10*self.height,\ + 10*self.width,20*self.height) + wall53=Wall(20*self.x+2*self.ratio1*750,20*self.y+20*self.height,10*self.width,\ + 20*self.height) + wall54=Wall(10*self.x+2*self.ratio1*750,20*self.y+40*self.height,20*self.width,\ + 10*self.height) + #dash + wallDash=Wall(10*self.x+45*self.width,20*self.y+20*self.width,\ + 20*self.width,10*self.height) + #1 + wall12=Wall(80*self.x,20*self.y,10*self.width,50*self.height) + #1 + wall13=Wall(100*self.x,20*self.y,10*self.width,50*self.height) + #2 + wall21=Wall(100*self.x+2*self.ratio1*750,20*self.y,20*self.width,\ + 10*self.height) + wall22=Wall(110*self.x+2*self.ratio1*750,20*self.y+10*self.height,\ + 10*self.width,20*self.height) + wall23=Wall(100*self.x+2*self.ratio1*750,20*self.y+20*self.height,10*self.width,\ + 20*self.height) + wall24=Wall(100*self.x+2*self.ratio1*750,20*self.y+40*self.height,20*self.width,\ + 10*self.height) + self.board=[wall11,wall51,wall52,wall53,wall54,wallDash,wall12,wall13,\ + wall21,wall22,wall23,wall24,rightWall,leftWall,topWall,bottomWall] + self.dimensions=set() + for wall in self.board: + self.dimensions.add((wall.x,wall.y,wall.width,wall.height)) + def drawBoard(self,canvas): + for wall in self.board: + wall.drawWall(canvas) + def drawCells(self): + self.rows=500//5 + self.cols=750//5 + self.table=[[0]*self.cols for row in range(self.rows)] + for wall in self.dimensions: + for row in range(int(wall[1]),int(wall[1])+int(wall[3]),5): + for col in range(int(wall[0]),int(wall[0])+int(wall[2]),5): + self.table[row//5][col//5]=1 + return self.table + +#board=OriginalBoard(5,5,5,5) + +#print(board.drawCells()) + +#runs extremely slow, no efficiency +#print(astar(board.drawCells(),(0,0),(250,375))) \ No newline at end of file diff --git a/points.py b/points.py index 6bab62e..908b620 100644 --- a/points.py +++ b/points.py @@ -4,7 +4,7 @@ # http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html # Points class defines characteristics of points and draws points -class Points(object): +class Points(Mode): def __init__(self,x,y): self.x=x self.y=y diff --git a/sidescrollBoard.py b/sidescrollBoard.py new file mode 100644 index 0000000..c9f75f2 --- /dev/null +++ b/sidescrollBoard.py @@ -0,0 +1,51 @@ +from cmu_112_graphics import * +from wall import * +import random + +# animation framework attained from +# http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html + +#creates a randomly generated board + +class SideScrollBoard(Wall): + def __init__(self,mode,x,y,width,height): + super().__init__(x,y,width,height) + self.ratio1=50/mode.width + #right wall + rightWall=Wall(2*self.x,2*self.y,self.width,\ + 1.5*(mode.height-4*self.height)) + #left wall + leftWall=Wall(2*(mode.width-3*self.x),2*self.y,self.width,\ + 1.5*(mode.height-4*self.height)) + #top wall + topWall=Wall(2*self.x,2*self.y,2*(mode.width-4*self.width),\ + self.height) + #bottom wall + bottomWall=Wall(2*self.x,1.5*(mode.height-3*self.y),2*(mode.width-4*self.width),\ + self.height) + self.board=[rightWall,leftWall,topWall,bottomWall] + i=0 + while i < 10: + x=random.randint(10,2*(mode.width-30)) + y=random.randint(10,2*(mode.width-20)) + wall=random.choice(["horizontal","vertical"]) + if wall=="horizontal": + newWall=Wall(x,y,50,100) + elif wall=="vertical": + newWall=Wall(x,y,100,50) + self.board.append(newWall) + i+=1 + self.dimensions=set() + for wall in self.board: + self.dimensions.add((wall.x,wall.y,wall.width,wall.height)) + def drawBoard(self,canvas): + for wall in self.board: + wall.drawWall(canvas) + def drawCells(self,mode): + self.rows=mode.height//5 + self.cols=mode.width//5 + self.table=[[0]*self.cols for row in range(self.rows)] + for wall in mode.gameBoard.dimensions: + for row in range(int(wall[1])//5,int(wall[1])//5+int(wall[3])//5): + for col in range(int(wall[0])//5,int(wall[0])//5+int(wall[2])//5): + pass #change when algorithm is complete \ No newline at end of file diff --git a/sidescrollGameMode.py b/sidescrollGameMode.py new file mode 100644 index 0000000..de5be59 --- /dev/null +++ b/sidescrollGameMode.py @@ -0,0 +1,206 @@ +from cmu_112_graphics import * +from pacman import * +from ghost import * +from points import * +from sidescrollBoard import * +from tkinter import * +import random + +# animation framework attained from +# http://www.cs.cmu.edu/~112/notes/notes-animations-part1.html + +# SidescrollGameMode will establish a randomly generated board every single time +# a new game starts, will allow the user to travel off screen +class SideScrollGameMode(Mode): + def appStarted(mode): + mode.radius=10 + mode.pointRadius=5 + mode.margin=50 + mode.scrollX=0 + mode.scrollY=0 + mode.pacmanXPos,mode.pacmanYPos=mode.width/2,4*mode.height/5 + mode.pinkyGhostXPos,mode.pinkyGhostYPos=13*mode.width/30,7*mode.height/20 + mode.blinkyGhostXPos,mode.blinkyGhostYPos=13*mode.width/30,9*mode.height/20 + mode.inkyGhostXPos,mode.inkyGhostYPos=13*mode.width/30+30,9*mode.height/20 + mode.clydeGhostXPos,mode.clydeGhostYPos=13*mode.width/30-30,9*mode.height/20 + mode.wallX,mode.wallY=mode.width/150,mode.height/100 + mode.wallWidth,mode.wallHeight=mode.width/150,mode.height/100 + mode.speed=5 + mode.dxPacPos,mode.dyPacPos=-1*mode.speed,0 + mode.dxPinkyPos,mode.dyPinkyPos=1*mode.speed,0 + mode.pacCurrDirection="left" + mode.pinkyCurrDirection="up" + mode.pacDirection=mode.pacCurrDirection + mode.pinkDirection=mode.pinkyCurrDirection + mode.legalPacDirections=["up","right","down","left"] + mode.legalPinkyDirections=["up","right","down","left"] + mode.gameBoard=SideScrollBoard(mode,mode.wallX,mode.wallY,\ + mode.wallWidth,mode.wallHeight) + mode.points=[] + mode.drawCoins() + mode.score=0 + mode.gameOver=False + + # from + # http://www.cs.cmu.edu/~112/notes/notes-animations-part2.html#sidescrollerExamples + def makePlayerVisible(mode): + if (mode.pacmanXPos < mode.scrollX + mode.margin): + mode.scrollX = mode.pacmanXPos - mode.margin + if (mode.pacmanXPos > mode.scrollX + mode.width - mode.margin): + mode.scrollX = mode.pacmanXPos - mode.width + mode.margin + if (mode.pacmanYPos < mode.scrollY + mode.margin): + mode.scrollY = mode.pacmanYPos - mode.margin + if (mode.pacmanXPos > mode.scrollY + mode.height - mode.margin): + mode.scrollY = mode.pacmanYPos - mode.height + mode.margin + + def keyPressed(mode,event): + if mode.gameOver==False: + if event.key=="Right": + mode.pacDirection="right" + elif event.key=="Left": + mode.pacDirection="left" + elif event.key=="Up": + mode.pacDirection="up" + elif event.key=="Down": + mode.pacDirection="down" + mode.setPinkyDir() + if mode.pacDirection in mode.legalPacDirections: + mode.pacCurrDirection=mode.pacDirection + mode.movePlayer(mode.pacCurrDirection,"pac") + else: + mode.movePlayer(mode.pacCurrDirection,"pac") + else: + if event.key=="r": + mode.appStarted() + mode.gameOver=False + + # will move to moveGhost method in Pinky class after bugs are removed + # and tested + def setPinkyDir(mode): + if mode.pacCurrDirection=="right": + mode.pinkyCurrDirection="left" + elif mode.pacCurrDirection=="left": + mode.pinkyCurrDirection=="right" + elif mode.pacCurrDirection=="up": + mode.pinkyCurrDirection=="down" + elif mode.pacCurrDirection=="down": + mode.pinkyCurrDirection=="up" + + def movePlayer(mode,direction,name): + if direction=="right": + mode.dirSetter(name,mode.speed,0) + elif direction=="left": + mode.dirSetter(name,-1*mode.speed,0) + elif direction=="up": + mode.dirSetter(name,0,-1*mode.speed) + elif direction=="down": + mode.dirSetter(name,0,mode.speed) + + def timerFired(mode): + if mode.gameOver==False: + mode.legalPacDirections=mode.legalPlaces(mode.pacmanXPos,mode.pacmanYPos) + if mode.pacCurrDirection in mode.legalPacDirections: + mode.pacmanXPos+=mode.dxPacPos + mode.pacmanYPos+=mode.dyPacPos + mode.makePlayerVisible() + mode.setPinkyDir() + mode.legalPinkyDirections=mode.legalPlaces(mode.pinkyGhostXPos,mode.pinkyGhostYPos) + if mode.pinkyCurrDirection in mode.legalPinkyDirections: + mode.movePlayer(mode.pinkyCurrDirection,"pinky") + else: + mode.pinkyCurrDirection=random.choice(mode.legalPinkyDirections) + mode.movePlayer(mode.pinkyCurrDirection,"pinky") + mode.pinkyGhostXPos+=mode.dxPinkyPos + mode.pinkyGhostYPos+=mode.dyPinkyPos + if mode.pinkyGhostXPos==mode.pacmanXPos and mode.pinkyGhostYPos==mode.pacmanYPos: + mode.gameOver=True + i=0 + while iwall[0] and \ + x-mode.radiuswall[1]+wall[3] and y-mode.radius<=wall[1]+wall[3]): + if "up" in legalDirections: + legalDirections.remove("up") + elif (y=wall[1]): + if "down" in legalDirections: + legalDirections.remove("down") + if y+mode.radius>wall[1] and \ + y-mode.radiuswall[0]+wall[2] and x-mode.radius<=wall[0]+wall[2]): + if "left" in legalDirections: + legalDirections.remove("left") + elif (x=wall[0]): + if "right" in legalDirections: + legalDirections.remove("right") + return legalDirections + + def drawCoins(mode): + for x in range(int(mode.wallX*10),int(2*(mode.width-3*mode.wallWidth)),int(mode.wallX*10)): + for y in range(int(mode.wallY*10),int(1.5*(mode.height-3*mode.wallHeight)),int(mode.wallY*10)): + mode.points.append(Points(x,y)) + for wall in mode.gameBoard.dimensions: + for point in mode.points: + if (point.x+mode.pointRadius>=wall[0] and \ + point.x-mode.pointRadius<=wall[0]+wall[2] and \ + point.y-mode.pointRadius<=wall[1]+wall[3] and \ + point.y+mode.pointRadius>=wall[1]): + mode.points.remove(point) + + def redrawAll(mode,canvas): + canvas.create_rectangle(0,0,mode.width,mode.height,fill="black") + if mode.gameOver==False: + for wall in mode.gameBoard.board: + wall.x-=mode.scrollX + wall.y-=mode.scrollY + mode.gameBoard.drawBoard(canvas) + for coin in mode.points: + coin.x-=mode.scrollX + coin.y-=mode.scrollY + coin.drawPoints(canvas) + mode.pacmanXPos-=mode.scrollX + mode.pacmanYPos-=mode.scrollY + PacMan(mode.pacmanXPos,mode.pacmanYPos).drawPacMan(canvas) + mode.blinkyGhostXPos-=mode.scrollX + mode.blinkyGhostYPos-=mode.scrollY + Blinky(mode,mode.blinkyGhostXPos,mode.blinkyGhostYPos).drawGhost(canvas) + mode.pinkyGhostXPos-=mode.scrollX + mode.pinkyGhostYPos-=mode.scrollY + Pinky(mode,mode.pinkyGhostXPos,mode.pinkyGhostYPos).drawGhost(canvas) + mode.inkyGhostXPos-=mode.scrollX + mode.inkyGhostYPos-=mode.scrollY + Inky(mode,mode.inkyGhostXPos,mode.inkyGhostYPos).drawGhost(canvas) + mode.clydeGhostXPos-=mode.scrollX + mode.clydeGhostYPos-=mode.scrollY + Clyde(mode,mode.clydeGhostXPos,mode.clydeGhostYPos).drawGhost(canvas) + canvas.create_text(mode.width//2,15,text=f'Score:{mode.score}',\ + fill="white") + else: + font = 'Arial 26 bold' + canvas.create_text(mode.width//2,mode.height//2, + text='Game Over!', font=font, fill="white") + canvas.create_text(mode.width//2,3*mode.height//4, + text=f'Your score: {mode.score}',font=font,fill="white") + canvas.create_text(mode.width//2,5*mode.height//6, + text='Press r to restart',font=font,fill="white") \ No newline at end of file diff --git a/splashScreenMode.py b/splashScreenMode.py index 08bf8b5..7c6c5ff 100644 --- a/splashScreenMode.py +++ b/splashScreenMode.py @@ -12,11 +12,13 @@ def redrawAll(mode,canvas): canvas.create_text(mode.width/2, mode.height/5, \ text='Pac Man', font=font, fill="white") canvas.create_text(mode.width/2, mode.height/3, \ - text='Press o to start!',font=font,fill="white") + text='Press o for original mode, s for sidescroll mode!',font=font,fill="white") def keyPressed(mode,event): if event.key=="o": mode.app.setActiveMode(mode.app.gameMode) + elif event.key=="s": + mode.app.setActiveMode(mode.app.scrollMode) #will add buttons to determine mode def mousePressed(mode,event):