"""
A clone of the game of pong or tele-tennis.
Requires Python and PyGame:
http://www.python.org/ and http://pygame.seul.org/
Try 'python pypong.py --help' for instructions.
This code is in the public domain.
[Tested on Win98 / Win2K / XP / Gentoo]
Version: 0.0.3
Author : John Popplewell
Email : john@johnnypops.demon.co.uk
Web : http://www.johnnypops.demon.co.uk/
Changes:
avoid TypeError in make_tone()
got rid of clicks by:
- removing [loops, [maxtime]] from channel.play()
- adding a linear fade-out at the sample end
- changing the individual sample volume settings
added sound effects test mode
"""
import os, sys, getopt, math, random
try:
import Numeric as N
except:
print "This game requires the Numeric module."
sys.exit()
try:
import pygame
except:
print "This game requires the PyGame module."
sys.exit()
from pygame.locals import *
file_name = "pypong"
demo_name = "pyPong"
if not pygame.font:
print 'Warning, fonts disabled'
if not pygame.mixer:
print 'Warning, sound disabled'
LEFT_PLAYER_UP = K_q
LEFT_PLAYER_DOWN = K_a
LEFT_PLAYER_SERVE = K_s
RIGHT_PLAYER_UP = K_p
RIGHT_PLAYER_DOWN = K_l
RIGHT_PLAYER_SERVE = K_k
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
BAT_WIDTH = 12
BAT_HEIGHT = 80
BAT_INDENT = 10
BAT_VELOCITY = 256.0
BAT_ACCELERATION = 300.0
BAT_SPIN_FACTOR = -0.333
BAT_CURVATURE = -8.0
BORDER_THICKNESS = 2
BALL_SIZE = 12
BALL_VELOCITY = 360.0
MAX_BALL_VELOCITY= 460.0
BALL_WOBBLE = BALL_VELOCITY/10.0
SCORE_INDENT = 10
SCORE_POINT_SIZE = 36
TICK_PER_SECOND = 40
SND_STEREO = 0
SND_BITS_PER_SAMPLE = 16
SND_SAMPLES_PER_SEC = 22050
game_font = None
all_sprites = None
visible_sprites = None
def make_tone(frequency, duration, samples_per_sec, bits_per_sample, fade_cycles=30):
samples_per_cycle = int(math.ceil(samples_per_sec/frequency))
total_samples = samples_per_cycle*int(frequency*duration)
samples = N.zeros(total_samples, N.Int16)
amplitude = ((2**bits_per_sample)/2)-1
k = 2.0*math.pi/samples_per_cycle
for i in range(total_samples):
samples[i] = int(amplitude*math.sin(k*(i%samples_per_cycle)))
fade_samples = samples_per_cycle*fade_cycles
start_fade = total_samples-fade_samples
for i in range(fade_samples):
samples[start_fade+i] = int(samples[start_fade+i]*float(fade_samples-i)/fade_samples)
res = pygame.sndarray.make_sound(samples)
res.set_volume(1.0)
return res
def sign(i):
if i < 0: return -1
if i > 0: return 1
return 0
class ScoreBoard(pygame.sprite.Sprite):
LEFT, CENTER, RIGHT = range(3)
def __init__(self, x, y, align, colour ):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.align = align
self.colour = colour
self.score = 0
self.update_score(0)
visible_sprites.add(self)
def update_score(self, delta):
self.score += delta
if not game_font:
return
self.image = game_font.render("%d"%self.score, 1, self.colour)
self.rect = self.image.get_rect()
self.rect.top = self.y
if self.align == ScoreBoard.LEFT:
self.rect.left = self.x
elif self.align == ScoreBoard.CENTER:
self.rect.centerx = self.x
elif self.align == ScoreBoard.RIGHT:
self.rect.right = self.x
class Bat(pygame.sprite.Sprite):
def __init__(self, x, height_range, colour):
pygame.sprite.Sprite.__init__(self)
self.height_range = height_range
self.rect = pygame.Rect((0,0,BAT_WIDTH,BAT_HEIGHT))
self.image = pygame.Surface((BAT_WIDTH,BAT_HEIGHT))
self.image.fill(colour)
self.p_x = float(x)
self.p_y = float((self.height_range-self.rect.height)/2)
self.dir = 0
self.v_y = 0.0
self.rect.move_ip(round(self.p_x),round(self.p_y))
def update(self,dT):
self.v_y += sign(self.v_y)*BAT_ACCELERATION*dT
self.p_y += self.v_y*dT
if self.p_y <= 0.0:
self.p_y = 0.0
self.v_y = 0.0
if self.p_y+BAT_HEIGHT >= SCREEN_HEIGHT:
self.p_y = SCREEN_HEIGHT-BAT_HEIGHT
self.v_y = 0.0
self.rect.top = round(self.p_y)
def move(self,dir):
self.dir = dir
self.v_y = self.dir*BAT_VELOCITY
def stop(self,dir):
if dir == self.dir:
self.move(0)
class Player:
properties = (
(BAT_INDENT , 0.25),
(SCREEN_WIDTH-BAT_INDENT-BAT_WIDTH, 0.75),
)
controls = (
(LEFT_PLAYER_UP, LEFT_PLAYER_DOWN),
(RIGHT_PLAYER_UP, RIGHT_PLAYER_DOWN),
)