Created
March 1, 2013 03:29
-
-
Save jsecretan/5062279 to your computer and use it in GitHub Desktop.
Some python code that I stole, I mean put together, from a couple of different sources, including:
http://www.linuxuser.co.uk/tutorials/make-a-game-on-raspberry-pi
and
http://ideamonk.blogspot.com/2010/03/fun-with-pygames-camera-module.html
This will let you play pong with a raspberry pi / camera setup which will track your white socks on the fl…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# PiPong - A remake of the classic Pong game using PyGame. Written by | |
# Liam Fraser - 28/07/2012 for the Linux User & Developer magazine. | |
# Modified by Jimmy Secretan in 12/2012 to use the pygame camera module to track white socks | |
import pygame # Provides what we need to make a game | |
import sys # Gives us the sys.exit function to close our program | |
import random # Can generate random positions for the pong ball | |
import pygame.camera | |
from pygame.locals import * | |
from pygame import * | |
# Camera capture stuff, copied from | |
# http://ideamonk.blogspot.com/2010/03/fun-with-pygames-camera-module.html | |
class Capture(object): | |
def __init__(self, ccolor=(255, 255, 255), threshold=(60, 10, 10)): | |
# Size of the camera capture | |
self.size = (320,240) | |
# initialize camera module | |
pygame.camera.init() | |
# this is the same as what we saw before | |
self.clist = pygame.camera.list_cameras() | |
if not self.clist: | |
raise ValueError("Sorry, no cameras detected.") | |
self.cam = pygame.camera.Camera(self.clist[0], self.size) | |
self.cam.start() | |
# create a surface to capture to. for performance purposes | |
# bit depth is the same as that of the display surface. | |
# TODO, See if we could use lower bit depth for increased speed | |
self.snapshot = pygame.surface.Surface(self.size, 0, 24) | |
self.ccolor = ccolor | |
# by default we give more priority to shades of red | |
self.threshold = threshold | |
self.location = 0.0 | |
# Returns a floating point number from 0 to 1, with 0 being all the way to the left side, and 1 being all the way to the right | |
def get_player_foot_location(self): | |
# If we have an image ready, get and process it, if not, return the last known location | |
if self.cam.query_image(): | |
self.snapshot = self.cam.get_image(self.snapshot) | |
# threshold against the color we got before | |
mask = pygame.mask.from_threshold(self.snapshot, self.ccolor, self.threshold) | |
# keep only the largest blob of that color | |
connected = mask.connected_component() | |
# these numbers are purely experimental and specific to your room and object | |
# print mask.count() # use this to estimate | |
# make sure the blob is big enough that it isn't just noise | |
if mask.count() > 7: | |
# find the center of the blob | |
self.location = float(mask.centroid()[0])/float(self.size[0]) | |
return self.location | |
# Our main game class | |
class PiPong: | |
def __init__(self): | |
# Make the display size a member of the class | |
self.displaySize = (640, 480) | |
# Initialize pygame | |
pygame.init() | |
# Create a clock to manage time | |
self.clock = pygame.time.Clock() | |
# Set the window title | |
display.set_caption("Pi Pong") | |
# Create the window | |
self.display = display.set_mode(self.displaySize) | |
# Create the background, passing through the display size | |
self.background = Background(self.displaySize) | |
# Create two bats, a ball and add them to a sprite group | |
self.player1Bat = Bat(self.displaySize, "player1") | |
self.player2Bat = Bat(self.displaySize, "player2") | |
self.ball = Ball(self.displaySize) | |
self.sprites = sprite.Group(self.player1Bat, self.player2Bat, | |
self.ball) | |
def run(self): | |
# Runs the game loop | |
while True: | |
# The code here runs when every frame is drawn | |
# Handle Events | |
self.handleEvents() | |
# Draw the background | |
self.background.draw(self.display) | |
# Update and draw the sprites | |
self.sprites.update() | |
self.sprites.draw(self.display) | |
# Check for bat collisions | |
self.ball.batCollisionTest(self.player1Bat) | |
self.ball.batCollisionTest(self.player2Bat) | |
# Update the full display surface to the screen | |
display.update() | |
# Limit the game to 30 frames per second | |
self.clock.tick(30) | |
def handleEvents(self): | |
# Handle events, starting with the quit event | |
for event in pygame.event.get(): | |
if event.type == QUIT: | |
pygame.quit() | |
sys.exit() | |
if event.type == KEYDOWN: | |
# Find which key was pressed and start moving appropriate bat | |
if event.key == K_s: | |
# Start moving bat | |
self.player1Bat.startMove("down") | |
elif event.key == K_w: | |
self.player1Bat.startMove("up") | |
if event.key == K_DOWN: | |
self.player2Bat.startMove("down") | |
elif event.key == K_UP: | |
self.player2Bat.startMove("up") | |
if event.type == KEYUP: | |
if event.key == K_s or event.key == K_w: | |
self.player1Bat.stopMove() | |
elif event.key == K_DOWN or event.key == K_UP: | |
self.player2Bat.stopMove() | |
# The class for the background | |
class Background: | |
def __init__(self, displaySize): | |
# Set our image to a new surface, the size of the screen rectangle | |
self.image = Surface(displaySize) | |
# Fill the image with a green colour (specified as R,G,B) | |
self.image.fill((27, 210, 57)) | |
# Get width proportionate to display size | |
lineWidth = displaySize[0] / 80 | |
# Create a rectangle to make the white line | |
lineRect = Rect(0, 0, lineWidth, displaySize[1]) | |
lineRect.centerx = displaySize[0] / 2 | |
draw.rect(self.image, (255, 255, 255), lineRect) | |
def draw(self, display): | |
# Draw the background to the display that has been passed in | |
display.blit(self.image, (0,0)) | |
# The class for the bats on either side | |
class Bat(sprite.Sprite): | |
def __init__(self, displaySize, player): | |
# Initialize the sprite base class | |
super(Bat, self).__init__() | |
# Make player a member variable | |
self.player = player | |
# Get a width and height values proportionate to the display size | |
width = displaySize[0] / 80 | |
height = displaySize[1] / 6 | |
# Create an image for the sprite using the width and height | |
# we just worked out | |
self.image = Surface((width, height)) | |
# Fill the image white | |
self.image.fill((255, 255, 255)) | |
# Create the sprites rectangle from the image | |
self.rect = self.image.get_rect() | |
self.displaySize = displaySize | |
# Set the rectangle's location depending on the player | |
if player == "player1": | |
# Left side | |
self.rect.centerx = displaySize[0] / 20 | |
# Also make a capture object | |
self.capture = Capture() | |
self.camera_controlled = True | |
elif player == "player2": | |
# Right side | |
self.rect.centerx = displaySize[0] - displaySize[0] / 20 | |
self.camera_controlled = False | |
# Center the rectangle vertically | |
self.rect.centery = displaySize[1] / 2 | |
# Set a bunch of direction and moving variables | |
self.moving = False | |
self.direction = "none" | |
self.speed = 13 | |
def startMove(self, direction): | |
# Set the moving flag to true | |
self.direction = direction | |
self.moving = True | |
def update(self): | |
# If we are player 1, move with the camera | |
if self.camera_controlled: | |
self.rect.centery = self.displaySize[1] * self.capture.get_player_foot_location() | |
elif self.moving: | |
# Move the bat up or down if moving | |
if self.direction == "up": | |
self.rect.centery -= self.speed | |
elif self.direction == "down": | |
self.rect.centery += self.speed | |
def stopMove(self): | |
self.moving = False | |
# The class for the ball | |
class Ball(sprite.Sprite): | |
def __init__(self, displaySize): | |
# Initialize the sprite base class | |
super(Ball, self).__init__() | |
# Get the display size for working out collisions later | |
self.displaySize = displaySize | |
# Get a width and height values proportionate to the display size | |
width = displaySize[0] / 30 | |
height = displaySize[1] / 30 | |
# Create an image for the sprite | |
self.image = Surface((width, height)) | |
# Fill the image blue | |
self.image.fill((27, 224, 198)) | |
# Create the sprites rectangle from the image | |
self.rect = self.image.get_rect() | |
# Work out a speed | |
self.speed = displaySize[0] / 110 | |
# Reset the ball | |
self.reset() | |
def reset(self): | |
# Start the ball directly in the centre of the screen | |
self.rect.centerx = self.displaySize[0] / 2 | |
self.rect.centery = self.displaySize[1] / 2 | |
# Start the ball moving to the left or right (pick randomly) | |
# Vector(x, y) | |
if random.randrange(1, 3) == 1: | |
# move to left | |
self.vector = (-1, 0) | |
else: | |
# move to right | |
self.vector = (1, 0) | |
def update(self): | |
# Check if the ball has hit a wall | |
if self.rect.midtop[1] <= 0: | |
# Hit top side | |
self.reflectVector() | |
elif self.rect.midleft[0] <= 0: | |
# Hit left side | |
self.reset() | |
elif self.rect.midright[0] >= self.displaySize[0]: | |
self.reset() | |
elif self.rect.midbottom[1] >= self.displaySize[1]: | |
# Hit bottom side | |
self.reflectVector() | |
# Move in the direction of the vector | |
self.rect.centerx += (self.vector[0] * self.speed) | |
self.rect.centery += (self.vector[1] * self.speed) | |
def reflectVector(self): | |
# Gets the current angle of the ball and reflects it, for bouncing | |
# off walls | |
deltaX = self.vector[0] | |
deltaY = - self.vector[1] | |
self.vector = (deltaX, deltaY) | |
def batCollisionTest(self, bat): | |
# Check if the ball has had a collision with the bat | |
if Rect.colliderect(bat.rect, self.rect): | |
# Work out the difference between the start and end points | |
deltaX = self.rect.centerx - bat.rect.centerx | |
deltaY = self.rect.centery - bat.rect.centery | |
# Make the values smaller so it's not too fast | |
deltaX = deltaX / 12 | |
deltaY = deltaY / 12 | |
# Set the balls new direction | |
self.vector = (deltaX, deltaY) | |
if __name__ == '__main__': | |
game = PiPong() | |
game.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment