from scene import *
from sound import *
from copy import copy
from math import modf, floor
import time
screen_size = Size()
class Player (object): # Player object...
def __init__(self, name, color): # define the player color
self.color = color # set color as the color of player
self.score = 0 # set score as zero
self.name = name # set name as the name as the player
def __str__(self):
return self.name
class Puck (object): # Puck object
def __init__(self, pos, scene): # define the puck
self.vector = Vector3(0, 0, 0) # set the puck as a vector
self.pos = pos # set the puck position
def reverse_vector(self):
v = self.vector
self.vector = Vector3(-v.x, -v.y, 0)
class Game (Scene):
def setup(self):
self.left_player = Player("Green Player", Color(0.50, 1.00, 0.00)) # sets green player color
self.right_player = Player("Gold Player", Color(1.00, 0.80, 0.40)) # sets gold player color
self.players = (self.left_player, self.right_player) # sets players in left corner and right corner
self.start_time = 0.0
self.stop_time = 0.0
self.last_seconds = 0
self.running = False
self.start_time = time.time()
self.running = True
for s in ('Drums_06', 'Woosh_1', 'Powerup_2'): # for these sound effects...
load_effect(s) # load the sound effects in
center = self.size.w / 2 # sets center as center of the screen
middle = self.size.h / 2 # sets middle as middle of the screen
gh = self.size.h / 4 # sets goal height
self.puck_radius = gh / 2.5 # sets puck size/radius
self.puck = self.centered_puck() # makes puck start out centered
# the last time the puck was hit; Used to animate its slow down
self.puck_start_t = 0 # sets puck start to the dead center of the screen
pr = self.puck_radius # set pr to puck radius
self.line_width = self.puck_radius / 6 # sets puck radius inside the center line
lw = self.line_width # sets lw to line width
self.red_line = Rect(center - lw / 2, 0, lw, self.size.h) # sets red center line
self.red_circle = Rect(w=gh, h=gh) # sets circle in the red center line
self.red_circle.center(self.bounds.center()) # set the size of the circle in the center line
self.left_goal = Rect(w=gh, h=gh) # sets left goal as a rectangle
self.right_goal = Rect(w=gh, h=gh) # sets right goal as a rectangle
self.left_goal.center(0, middle) # sets the left goal to be centered
self.right_goal.center(self.size.w, middle) # sets the right goal to be centered
self.winner = None # when someone reaches seven goals, save them to show a message
def score_goal(self, player):
player.score += 1 # sets player score to plus one for backend purposes
self.puck = self.centered_puck() # sets up variable for the puck being centered
# following block of code sets the score so when a player reaches 7 they win
for p in self.players:
if p.score > 6:
self.winner = p
break
overlay = Layer(self.bounds) # sets the cover as an overlay, so its not behind the ice
def hide_overlay():
overlay.animate('alpha', 0.0, 1, completion=lambda: overlay.remove_layer())
if self.winner:
message = "%s Wins" % (self.winner) # shows a message for whatever player wins
on_completion = None
self.hide_overlay = hide_overlay
else:
message = "Goal!" # shows a message for when a player scores a goal
on_completion = hide_overlay
self.stop_time = time.time()
self.running = True
# restart the puck on the other player's side
if player == self.left_player:
self.puck.pos.x += self.size.w / 4 + self.puck_radius
else:
self.puck.pos.x -= self.size.w / 4 + self.puck_radius
size = self.puck_radius * 1.0 # sets puck radius
text_layer = TextLayer(message, 'AvenirNext-Heavy', size) # sets text font to Futura
text_layer.frame.center(self.bounds.center()) # sets the text to display from the center
text_layer.frame.y += self.size.h / 4 # sets the text to autosize itself
text_layer.animate('scale_x', 1.3, 0.3, autoreverse=True) # sets the x animation display time/size
text_layer.animate('scale_y', 1.3, 0.3, autoreverse=True) # sets the y animation display time/size
overlay.add_layer(text_layer) # sets the text layer to overlay
#following code sets color, etc. for when a player scores a goal
start_color, end_color = copy(player.color), copy(player.color)
start_color.a = 0
end_color.a = .5
overlay.background = start_color
overlay.animate('background', end_color, .10, completion=on_completion)
self.add_layer(overlay)
play_effect('Woosh_1') # sets effect of puck scoring to Woosh
def centered_puck(self): # set center
pos = Rect(w=self.puck_radius, h=self.puck_radius)
pos.center(self.bounds.center())
return Puck(pos, self)
def move_puck(self): # this lets the puck move by touching it once, like a real air hockey game
puck = self.puck
ease_x = (self.t - self.puck_start_t) / 4.0
ease = max(0, 1 - curve_ease_out(ease_x))
puck.pos.x += puck.vector.x * ease
puck.pos.y += puck.vector.y * ease
if puck.pos.right() > self.size.w and not puck.pos.intersects(self.right_goal): # if puck hits the side, play the drum sound effect
puck.vector.x *= -1
play_effect('Drums_06')
puck.pos.x = min(self.size.w - puck.pos.w, puck.pos.x)
if puck.pos.left() > self.size.w: # sets the left goal
self.score_goal(self.left_player)
return
if puck.pos.left() < 0 and not puck.pos.intersects(self.left_goal):
puck.vector.x *= -1
play_effect('Drums_06')
puck.pos.x = max(0, puck.pos.x)
if puck.pos.right() < 0: # sets the right goal
self.score_goal(self.right_player)
return
if puck.pos.top() > self.size.h or puck.pos.bottom() < 0: # if puck hits the side, play the drum sound effect
puck.vector.y *= -1
play_effect('Drums_06')
puck.pos.y = max(0, puck.pos.y)
puck.pos.y = min(self.size.h - puck.pos.h, puck.pos.y)
def draw(self):
stroke_weight(self.line_width)
background(1, 1, 1)
# red lines on ice in middle
stroke(1.00, 0.40, 0.40)
fill(1.00, 0.40, 0.40)
rect(*self.red_line.as_tuple())
fill(1, 1, 1)
ellipse(*self.red_circle.as_tuple())
# red goal markers
for goal in (self.left_goal, self.right_goal):
rect(*goal.as_tuple())
for touch in self.touches.values():
self.handle_touch(touch)
# black puck
no_stroke()
fill(0, 0, 0)
ellipse(*self.puck.pos.as_tuple())
self.draw_scores()
self.move_puck()
if self.root_layer:
self.root_layer.update(self.dt)
self.root_layer.draw()
if self.winner is not None: # shows message/allows player to tap to play again
c = Rect()
c.center(self.bounds.center())
tint(1, 1, 1)
message = "Tap to Play Again"
y_offset = self.size.h / 4
size = self.puck_radius
text(message, x=c.x, y=c.y-y_offset, font_size=size, font_name='AvenirNext-Heavy')
def draw_scores(self): # sets score font/size
for p, x in zip(self.players, (50, self.size.w - 50)):
tint(*p.color.as_tuple())
text(str(p.score), x=x, y=self.size.h- 50, font_size=32, font_name='AvenirNext-Heavy')
tint(0.00, 0.50, 1.00)
#Format the elapsed time (dt):
dt = 0.0
if self.running:
dt = (time.time() - self.start_time)
else:
dt = (self.stop_time - self.start_time)
minutes = abs(dt) / 60 # absolute value of dt divided by 60
seconds = abs(dt) % 60 # absolute value times percentage of 60
centiseconds = modf(abs(dt))[0] * 100
s = '%02d:%02d.%02d' % (minutes, seconds, centiseconds)
text(s, x=510, y=700, font_size=34, font_name='AvenirNext-Heavy')
def handle_touch(self, touch):
if self.winner:
# check for winner overlay and clear.
# Overlays to restart game to play again
self.winner = None
self.hide_overlay()
del self.hide_overlay
self.left_player.score = 0
self.right_player.score = 0
# stops the clock
self.stop_time = time.time()
self.running = False
# resets the clock
self.start_time = 0.0
self.last_seconds = 0
self.stop_time = 0.0
# starts the clock
self.start_time = time.time()
self.running = True
return
tx = touch.location.x # sets x touch location...
ty = touch.location.y # sets y touch location...
finger = Rect(tx - 20, ty - 20, 40, 40) # sets touch location for finger size
if finger.intersects(self.puck.pos):
dx = tx - touch.prev_location.x
dy = ty - touch.prev_location.y
# Richochet for unmoving finger, to make it like a real air hockey game
if abs(dx) < 5 and abs(dy) < 5:
self.puck.reverse_vector()
# Slide puck out from the finger. No puck holding.
if dx == 0: dx = self.puck.vector.x
if dy == 0: dy = self.puck.vector.y
if not any([dx, dy]): return
while finger.intersects(self.puck.pos):
self.puck.pos.x += dx
self.puck.pos.y += dy
else:
self.step = 0
self.puck_start_t = self.t
self.puck.vector = Vector3(dx * .8, dy * .8, 0)
self.puck.pos.x += dx
self.puck.pos.y += dy
class Start (Scene):
def draw(self):
background(0.40, 0.80, 1.00) # light blue background color
fill(0.50, 1.00, 0.00) # play button fill color
rect(320, 350, 358, 100) # play button rectangle
tint(1.00, 1.00, 1.00) # white text color
text('Play Game', font_name='AvenirNext-Heavy', font_size=60.0, x=500.0, y=400.0)
def touch_ended(self, touch):
main_scene.switch_scene(Game)
class GameOver (Scene):
def setup(self):
self.button = Button(Rect((screen_size.w/2)-100, (screen_size.h/2)-50, 200, 100), 'RESTART')
self.button.action = self.restart
self.add_layer(self.button)
def restart(self):
main_scene.switch_scene(Game)
def draw(self):
background(0,0,0)
self.button.draw()
no_tint()
text('Your score was: {0}'.format(score), x=screen_size.w/2, y=screen_size.h-50, font_size=24)
class MultiScene (Scene):
def __init__(self, start_scene):
self.active_scene = start_scene()
def switch_scene(self, new_scene):
self.active_scene = new_scene()
self.setup()
def setup(self):
global screen_size
screen_size = self.size
self.active_scene.add_layer = self.add_layer
self.active_scene.size = self.size
self.active_scene.setup()
def draw(self):
self.active_scene.touches = self.touches
self.active_scene.draw()
def touch_began(self, touch):
self.active_scene.touch_began(touch)
def touch_moved(self, touch):
self.active_scene.touch_moved(touch)
def touch_ended(self, touch):
self.active_scene.touch_ended(touch)
main_scene = MultiScene(Start)
run(main_scene)