Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Avacado-Sliced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Guac.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added GuacSong.mp3
Binary file not shown.
Binary file added ProjectWrite-UpInteractiveGame.pdf
Binary file not shown.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# InteractiveProgramming
This is the base repo for the interactive programming project for Software Design, Spring 2016 at Olin College.
This is the base repo for our interactive programming project for Software Design, Spring 2016 at Olin College.

There are three main python files in this project; two in PyGame and one in OpenCV. The PyGame file titled "whack_a_mole_no_cv.py" is the code for our mvp that runs the Whack-a-Mole game with a mouse controller. The PyGame file titled "whack_a_mole.py" is the code for the PyGame portion of the final Gual-a_Mole game that is paired with the OpenCV file "WhackAMoleOpenCV.py". Also in the folder are the image files necessary to display the visuals correctly and the sound files necessary to play the sound effects correctly.

Open the whack_a_mole.py and WhackAMoleOpenCV.py files in Sublime Text and run from the whack_a_mole.py file to play Guac-a-Mole! Make sure you have something blue in your hand for the OpenCV to detect and no other blue in the space around you!

Open the whack_a_mole_no_cv.py file and run in Sublime Text to play the mouse controlled version of Whack-a-Mole!

https://www.youtube.com/watch?v=JNsKvZo6MDs Thank you for the inspiration, Dr. Jean!
113 changes: 113 additions & 0 deletions WhackAMole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import pygame
from pygame.locals import QUIT, KEYDOWN, MOUSEMOTION
import time
from random import choice


class MoleView(object):
""" Visualizes a brick breaker game in a pygame window """
def __init__(self, model, screen):
""" Initialize the view with the specified model
and screen. """
self.model = model
self.screen = screen


def draw(self):
""" Draw the game state to the screen """
self.screen.fill(pygame.Color('black'))
# draw the bricks to the screen
for brick in self.model.bricks:
r = pygame.Rect(brick.left, brick.top, brick.width, brick.height)
pygame.draw.rect(self.screen, pygame.Color(brick.color), r)
pygame.display.update()

class MoleHole(object):
""" Represents a brick in our brick breaker game """
def __init__(self, left, top, width, height):
self.left = left
self.top = top
self.width = width
self.height = height
self.color = "red" # choice(["red", "green", "orange", "blue", "purple"])

class MoleModel(object):
""" Stores the game state for our brick breaker game """
def __init__(self):
self.bricks = []
self.MARGIN = 5
self.BRICK_WIDTH = 40
self.BRICK_HEIGHT = 40


new_hole = MoleHole(5, 5, 40, 20)
self.bricks.append(new_hole)
for left in range(self.MARGIN,
640 - self.BRICK_WIDTH - self.MARGIN,
self.BRICK_WIDTH + self.MARGIN):
for top in range(self.MARGIN,
980/2,
self.BRICK_HEIGHT + self.MARGIN):
mole_hole = MoleHole(left, top, self.BRICK_WIDTH, self.BRICK_HEIGHT)
self.bricks.append(mole_hole)

self.last_modified = choice(self.bricks)
self.last_modified.color = "blue"

def update(self):
print "updating"
change_color = choice(self.bricks)
change_color.color = "blue"
if self.last_modified:
self.last_modified.color = "red"
self.last_modified = change_color
# print self.last_modified.top
print self.last_modified.left

class MoleMouseController(object):
def __init__(self, model):
self.model = model

def get_cursor(self):
get_pressed = pygame.mouse.get_pressed()
print self.model.last_modified.left
if get_pressed[0] == 1 or get_pressed[1] == 1 or get_pressed[2] == 1:
mouse_position = pygame.mouse.get_pos()
print mouse_position
if mouse_position[0] > self.model.last_modified.left and mouse_position[0] < (self.model.last_modified.left+40):
if mouse_position[1] > self.model.last_modified.top and mouse_position[1] < (self.model.last_modified.top+40):
print "IN BOUNDS"
# self.model.update()
self.model.last_modified.color = 'red'


# def handle_event(self, event):
# """ Look for mouse movements and respond appropriately """
# if event.type != MOUSEMOTION:
# return
# self.model.paddle.left = event.pos[0]

if __name__ == '__main__':
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)

model = MoleModel()
view = MoleView(model, screen)
# controller = PyGameKeyboardController(model)
controller = MoleMouseController(model)

running = True
while running:
ticks = pygame.time.get_ticks()
if ticks%1000 == 0:
model.update()
for event in pygame.event.get():
if event.type == QUIT:
running = False
# controller.handle_event(event)
controller.get_cursor()
view.draw()
# time.sleep(1)
# pygame.time.wait(1000)
# print pygame.time.get_ticks()
Binary file added WhackAMole1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions WhackAMoleOpenCV.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#Import OpenCV
import cv2
#Import Numpy
import numpy as np

"""OpenCV portion of Gual-a-Mole! code"""

camera_feed = cv2.VideoCapture(0)

def color_tracking(child):
while(1):
_,frame = camera_feed.read()
#Convert the current frame to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

#Define the threshold for finding a blue object with hsv
lower_blue = np.array([100,100,100])
upper_blue = np.array([140,255,255])

#Create a binary image, where anything blue appears white and everything else is black
mask = cv2.inRange(hsv, lower_blue, upper_blue)

#Get rid of background noise using erosion and fill in the holes using dilation and erode the final image on last time
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
mask = cv2.erode(mask,element, iterations=2)
mask = cv2.dilate(mask,element,iterations=2)
mask = cv2.erode(mask,element)

#Create Contours for all blue objects
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
maximumArea = 0
bestContour = None
for contour in contours:
currentArea = cv2.contourArea(contour)
if currentArea > maximumArea:
bestContour = contour
maximumArea = currentArea
#Create a bounding box around the biggest blue object
if bestContour is not None:
x,y,w,h = cv2.boundingRect(bestContour)
cv2.rectangle(frame, (x,y),(x+w,y+h), (0,0,255), 3)
# sends the center of the rectangle to the parent
child.send([x+w/2,y+h/2])

#Show the original camera feed with a bounding box overlayed
cv2.imshow('frame',frame)
#Show the contours in a seperate window
cv2.imshow('mask',mask)
#Use this command to prevent freezes in the feed
k = cv2.waitKey(5) & 0xFF
#If escape is pressed close all windows
if k == 27:
break
Binary file added avocado.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added knife.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added punch.wav
Binary file not shown.
187 changes: 187 additions & 0 deletions whack_a_mole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import pygame
from pygame.locals import QUIT, KEYDOWN, MOUSEMOTION
from pygame.transform import scale
import time
from random import choice
from multiprocessing import Process, Pipe
from WhackAMoleOpenCV import color_tracking
"""Guac-a-Mole code that connects with WhackAMoleOpenCV"""
class MoleView(object):
""" Visualizes a guac_a_mole game in a pygame window """
def __init__(self, model, screen):
""" Initialize the view with the specified model
and screen. """
self.model = model
self.screen = screen

def draw(self):
""" Draw the game state to the screen """
# draw the black screen
self.screen.fill(pygame.Color('black'))
# load images
img = pygame.image.load('Avacado-Sliced.png')
img_whacked = pygame.image.load('Guac.png')
img_knife = pygame.image.load('knife.png')
# make and display title
white = (250, 250, 250)
message = 'GUAC-A-MOLE!'
font = pygame.font.Font(None, 40)
text = font.render(message, 1, white)
screen.blit(text, (202,40))
# make and display a countdown timer
white = (250, 250, 250)
message = str(model.time_left)
font = pygame.font.Font(None, 40)
text = font.render(message, 1, white)
screen.blit(text, (600,10))
# make and display scoreboard
white = (250, 250, 250)
message = 'Bowls of Guac: ' + str(model.score)
font = pygame.font.Font(None, 40)
text = font.render(message, 1, white)
screen.blit(text, (400,450))
# draw the knife cursor
r = pygame.Rect(self.model.hand[0], self.model.hand[1], 10, 10)
pygame.draw.rect(self.screen, pygame.Color('black'), r)
self.screen.blit(pygame.transform.scale(img_knife, (40,40)), (self.model.hand[0],self.model.hand[1]))
# if avocado is sliced, display guacamole image
if self.model.last_modified.whacked:
self.screen.blit(pygame.transform.scale(img_whacked, (40,40)), (self.model.last_modified.left,self.model.last_modified.top))
# display moving avocado
else:
self.screen.blit(pygame.transform.scale(img, (40,40)), (self.model.last_modified.left,self.model.last_modified.top))
pygame.display.update()

class MoleHole(object):
""" Represents a mole hole in our whack-a-mole game """
def __init__(self, left, top, width, height):
self.left = left
self.top = top
self.width = width
self.height = height
self.color = "green"
self.draw = True
self.whacked = False

class MoleModel(object):
""" Stores the game state for our whack-a-mole game """
def __init__(self):
self.holes = []
self.MARGIN = 5
self.BRICK_WIDTH = 40
self.BRICK_HEIGHT = 40
self.score = 0
self.missed = 0
self.click = False
self.hand = [0,0]
self.time_left = 60

# instantiates a new_hole and appends it to the self.holes list
new_hole = MoleHole(5, 5, 40, 20)
self.holes.append(new_hole)
for left in range(self.MARGIN,
640 - self.BRICK_WIDTH - self.MARGIN,
self.BRICK_WIDTH + self.MARGIN):
for top in range(self.MARGIN,
980/2,
self.BRICK_HEIGHT + self.MARGIN):
mole_hole = MoleHole(left, top, self.BRICK_WIDTH, self.BRICK_HEIGHT)
self.holes.append(mole_hole)
# randomly chooses a new hole and sets it equal to self_last_modified
self.last_modified = choice(self.holes)

def update(self):
"""Updates the status of the chosen mole hole and the timer, and ends the game if the countdown
has run out of time"""
change_color = choice(self.holes)
change_color.draw = False
if self.last_modified:
self.last_modified.draw = True
self.last_modified = change_color
self.last_modified.whacked = False
self.time_left -= 1
if self.time_left == -1:
font = pygame.font.Font(None, 40)
white = (250, 250, 250)
text2 = font.render("Game Over! Enjoy the guac!",1, white)
screen.blit(text2, (140,200))
pygame.display.update()
pygame.time.wait(2000)
pygame.quit()
sys.exit()

def whack(self):
"""If the click attribute is true, sets the click attribute to false and
sets last_modified.whacked to true to indicate that the avocado has been
sliced and the guacamole image should appear.
"""
if self.click:
self.click = False
self.last_modified.whacked = True

class MoleMouseController(object):
"""Represents the controller of the mouse position"""
def __init__(self, model):
self.model = model

def get_cursor(self):
"""Sets model.hand (the output of WhackAMoleOpenCV) equal to mouse_position,
horizontally flips the mouse_position, and checks if the mouse_position is
in the location of the avocado."""
mouse_position = self.model.hand
mouse_position[0] = 640 - self.model.hand[0]
if mouse_position[0] > self.model.last_modified.left and mouse_position[0] < (self.model.last_modified.left+40):
if mouse_position[1] > self.model.last_modified.top and mouse_position[1] < (self.model.last_modified.top+40):
self.model.click = True
self.model.last_modified.color = 'red'
self.model.score += 5

def whack_mole(parent):
"""The function that contains the while loop of the parent"""
running = True
# default value of 0 for time of the last update
previous_update = 0
# while True statement
while running:
# sets ticks equal to current timing
ticks = pygame.time.get_ticks()
model.whack()
# sets model.hand equal to the output of WhackAMoleOpenCV.py
model.hand = parent.recv()
# calls the method get_cursor of the object controller
controller.get_cursor()
# checks if the difference between the past update and current time is
# greater than 1 second and updates if it is
if ticks - previous_update > 1000:
previous_update = ticks
model.update()
# calls the method draw of the object view
view.draw()

if __name__ == '__main__':
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)

# instantiates an object of MoleModel
model = MoleModel()
# instantiates an object MoleView
view = MoleView(model, screen)
# instantiates an object of MoleMouseController
controller = MoleMouseController(model)

# plays the background music
pygame.mixer.music.load ("GuacSong.mp3")
pygame.mixer.music.play(-1,0.0)

# creates a connection between the parent and child
parent, child = Pipe()

# allows for multiprocessing of both the while loops of whack_mole
# and color_tracking from WhackAMoleOpenCV
p1 = Process(target=whack_mole, args=(parent,))
p2 = Process(target=color_tracking, args=(child,))
p1.start()
p2.start()
p1.join()
p2.join()
Loading