# ASKBliG
# ~~~~~~~
#
# Aka, "Breakout." Kind-of.
# Input arguments:
# ~~~~~~~~~~~~~~~
#
# Width -- (standard) width of board
# Height -- (standard) height of board
# Rows -- number of rows of bricks
# Game play
# ~~~~~~~~~
# The user may move the mouse to move the paddle. Pressing any mouse
# button will create a new ball; up to four balls may be active at
# one time. Press 'n' to start a new game.
# Game scoring
# ~~~~~~~~~~~~
#
# Good things--
#
# Hit wall: +10 pts
# Hit paddle: +20 pts
# Hit brick: +100 pts
# Hit ball: +200 pts
#
# Bad things--
#
# Loose ball: -400 pts
# Being alive: -1 pt/frame
#
# The player starts a game with 1000 points; the game is over when
# the score reaches zero.
# Known bugs:
# ~~~~~~~~~~
#
# - Balls will sometimes go through a wall and get lost.
# - When the system slows down too much, mouse movement events are
# seen sporadically; it should really be using MousePosition() to
# place the paddle, put for some reason this routine it tremendously
# slow when the paddle moves. Strange.
import ihEvent # For interpreting event messages
import ihApp # Very basic application framework on top of
# the iHTML core. Veeerry basic.
# Class: HitMask
# Superclass: none
#
# This class is used to make checking for object collisions more efficient.
# It divides the play area into horizontal strips, and keeps track of which
# objects are in each strip. This way an object only needs to check those
# in its own strip, rather than the entire playfield.
#
# The class current divides the playfield into strips of 20 pixels; it
# should be more intelligent about this, as the overall efficiency of the
# system is extremely dependent on this constant. Too large, and objects
# have to check more hits than necessary; too large, and they have to check
# many individual strips to find all the collisions.
#
# This class can also probably stand to be improved a bit -- it might
# be more effecient to have the strips contain dictionaries rather than
# arrays.
class HitMask:
# Create class. 'height' is the total height, in pixels, of the
# playfield.
def __init__(self,height):
self.height = height
self.last = (height-1)/20
if( self.last < 1 ): self.last = 1
#self.masks = [[]] * (self.last+1)
self.masks = []
for i in range(0,self.last+1):
self.masks.append([])
# Add a new piece to the HitMask, who's top is located at 'y' and
# which is 'height' pixels tall.
def AddPiece(self,piece,y,height):
#print 'Add range for %s, y=%s, height=%s' % (piece,y,height)
#print self.make_range(y,height)
for i in self.make_range(y,height):
self.masks[i].append(piece)
# Remove a piece from the HitMask, who's top is located at 'y' and
# which is 'height' pixels tall.
def RemPiece(self,piece,y,height):
#print 'Rem range for %s, y=%s, height=%s' % (piece,y,height)
#print self.make_range(y,height)
try:
for i in self.make_range(y,height):
self.masks[i].remove(piece)
except ValueError:
pass
# Update the position of a piece -- it was located at 'oldy' and
# was 'oldheight' pixels tall; it is now located at 'newy' and is
# 'newheight' pixels tall.
def MovePiece(self,piece,oldy,oldheight,newy,newheight):
oldy1, oldy2 = self.get_range(oldy,oldheight)
newy1, newy2 = self.get_range(newy,newheight)
if( oldy1 != newy1 or oldy2 != newy2 ):
#print 'Moving:',piece
if( oldy1 < newy1 ):
for i in range(oldy1,newy1+1):
try:
self.masks[i].remove(piece)
except:
pass
if( newy1 < oldy1 ):
for i in range(oldy1,newy1+1):
self.masks[i].append(piece)
if( oldy2 > newy2 ):
for i in range(newy2-1,oldy2):
try:
self.masks[i].remove(piece)
except:
pass
if( newy2 > oldy2 ):
for i in range(oldy2-1,newy2):
self.masks[i].append(piece)
# Return an array of the strips which an object with the given
# position and height will need to check for hits.
def PieceMask(self,y,height):
y1,y2 = self.get_range(y,height)
#print 'Get range: from %s to %s' % (y1,y2)
return self.masks[y1:y2]
# **
# ** Private functions
# **
# Return the range of strips covered by the given dimensions.
def get_range(self,y,height):
y1 = y/20
if( y1 < 0 ): y1 = 0
elif( y1 > self.last ): y1 = self.last
y2 = ((y+height-1)/20)+1
if( y2 < 1 ): y2 = 1
elif( y2 > (self.last+1) ): y2 = (self.last+1)
return y1,y2
# Create an array range for the given dimensions.
def make_range(self,y,height):
y1 = y/20
if( y1 < 0 ): y1 = 0
elif( y1 > self.last ): y1 = self.last
y2 = ((y+height-1)/20)+1
if( y2 < 1 ): y2 = 1
elif( y2 > (self.last+1) ): y2 = (self.last+1)
#print 'y1=%s, y2=%s, last=%s' % (y1,y2,self.last)
return range(y1,y2)
# Class: GamePiece
# Superclass: none
#
# This class defines the components common to all pieces used by the
# game. This includes the bricks, balls, paddle, etc. It also may
# optionally make use of a HitMask object which the piece is to be
# put in.
# Universal game piece -- defines all common functionality and structure.
class GamePiece:
# Class initialization. Arguments are:
#
# app: (required positional) the main application class. Must be
# a subclass of a widget, and define the functions LogScore(),
# RemoveBrick(), RemoveBall(), and have member variables
# background, foreground, shine_color, shadow_color.
# [Yes, this isn't the best. :p]
# hit_mask: (required positional) a HitMask object in which to place
# this piece. If 'None', it is not used.
# x: (optional keyword) the initial x position
# y: (optional keyword) the initial y position
# width: (optional keyword) the initial width in pixels
# height: (optional keyword) the initial height in pixels
# xvel: (optional keyword) the initial x velocity
# yvel: (optional keyword) the initial y velocity
# movable: (optional keyword) boolean -- can this piece be moved?
# hitable: (optional keyword) hitable -- can this piece be touched?
# color: (optional keyword) color to draw piece in
# pixmap: (optional keyword) pixmap to draw piece with; overrides color
def __init__(self,app,hit_mask,x=0,y=0,width=0,height=0,xvel=0,yvel=0,
movable=0,hitable=1,color=None,pixmap=None,**leftovers):
self.app = app
self.hit_mask = hit_mask
self.x = x
self.y = y
self.width = width
self.height = height
self.xvel = xvel
self.yvel = yvel
if hit_mask: hit_mask.AddPiece(self,y,height)
self.movable = movable
self.hitable = hitable
self.color = color or self.app.foreground
self.pixmap = pixmap
if pixmap:
self.width = pixmap.Dimensions()[2]
self.height = pixmap.Dimensions()[3]
# Change the position of the piece. Keeps the HitMask up-to-date.
def SetPosition(self,x,y):
if( self.hit_mask ): self.hit_mask.MovePiece(self,self.y,self.height,
y,self.height)
self.x = x
self.y = y
# Change the size of the piece. Keeps the HitMask up-to-date.
def SetSize(self,width,height):
if( self.hit_mask ): self.hit_mask.RemPiece(self,self.y,self.height)
self.width = width
self.height = height
if( self.hit_mask ): self.hit_mask.AddPiece(self,self.y,self.height)
# Check for collisions. 'pieces' is an array of pieces which should
# be checked; for any collision found between this piece and one in
# in the array, both piece's 'do_hit()' method is called.
# This should probably be changed to take better advantage of the
# HitMask.
def Hit(self,pieces):
for other in pieces:
if not self is other:
# print 'Did %s hit %s?' % (self.__class__,other.__class__)
# print '(%s,%s)/(%sx%s) to (%s,%s)/(%sx%s)' \
# % ( self.x,self.y,self.width,self.height,
# other.x,other.y,other.width,other.height )
if ( self.x < (other.x+other.width)
and (self.x+self.width) > other.x
and self.y < (other.y+other.height)
and (self.y+self.height) > other.y
and self.hitable and other.hitable ):
# print 'HIT: (%s,%s)/(%sx%s) to (%s,%s)/(%sx%s)' \
# % ( self.x,self.y,self.width,self.height,
# other.x,other.y,other.width,other.height )
self.do_hit(other)
other.do_hit(self)
# Draw the piece's graphic in the drawable 'where'. If a pixmap is
# available, that is used; otherwise, it is by default drawn as a
# rectangle in the piece's color.
def Draw(self,where):
if self.pixmap:
where.Paste(self.x,self.y,self.pixmap)
else:
where.ForePen(self.color)
where.FillRectangle(self.x,self.y,self.width,self.height)
# Erase the piece's graphic in the drawable 'where'. Draws a
# rectangle in the background color.
def Erase(self,where):
if self.pixmap:
where.ForePen(self.app.background)
where.FillRectangle(self.x,self.y,self.width,self.height)
else:
where.ForePen(self.app.background)
where.FillRectangle(self.x,self.y,self.width,self.height)
# Change state for next frame. By default does no action.
def Step(self):
pass # nothing
# **
# ** The rest are private method.
# **
# Do action when hit by another object. Must be defined by sub-class.
def do_hit(self,other):
raise AccessError, 'undefined method do_hit() called.'
# Class: Wall
# Superclass: GamePiece
#
# Implements the functionality for a wall piece. This basically involves
# incrementing the player's score by 10 when hit by a ball.
class Wall(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
def do_hit(self,other):
if other.__class__ == Ball:
self.app.LogScore(10)
# Class: Brick
# Superclass: GamePiece
#
# Implements the functionality for a wall piece. This involves
# incrementing the player's score by 100 when hit by a ball, and asking
# the main class to remove this brick.
class Brick(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
def do_hit(self,other):
if other.__class__ == Ball:
self.app.LogScore(100)
self.app.RemoveBrick(self)
# Class: InvisibleDeath
# Superclass: GamePiece
#
# Creates a piece which removes a ball whenever it is touched, and
# decrements the player's score by 400. It does not draw on to the
# playfield. This class is used to bound the bottom of the screen,
# below the paddle.
class InvisibleDeath(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
def Draw(self,where):
pass
def Erase(self,where):
pass
def do_hit(self,other):
if other.__class__ == Ball:
self.app.LogScore(-400)
self.app.RemoveBall(other)
# Class: InvisibleCleaner
# Superclass: GamePiece
#
# Creates a piece which removes a ball whenever it is touched, but
# does not decrement the player's score. It does not draw on to the
# playfield. This class is used behind the walls, to catch any
# balls which somehow [through a bug in the program :p] make it through
# them.
class InvisibleCleaner(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
def Draw(self,where):
pass
def Erase(self,where):
pass
def do_hit(self,other):
if other.__class__ == Ball:
self.app.RemoveBall(other)
# Class: Paddle
# Superclass: GamePiece
#
# Implement the game paddle. This piece positions itself so that
# it is centered on its current (x,y) location, and adds 20 to the
# player's score when hit by a ball. It also doesn't allow itself
# to be moved through walls.
class Paddle(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
self.xvel = 0
self.yvel = 0
def do_mouse(self,ev,x,y):
oldx = self.x
oldy = self.y
self.SetPosition(x - (self.width/2),y - (self.height/2))
if( self.x != oldx):
self.xvel = self.x - oldx
if( self.y != oldy):
self.yvel = self.y - oldy
def do_hit(self,other):
if other.__class__ == Ball:
self.app.LogScore(20)
elif other.__class__ == Wall:
# print 'myx=%s, myw=%s; othx=%s, othw=%s' % (self.x,self.width,
# other.x,other.width)
if( other.width < other.height ):
if( (other.x+(other.width/2)) < (self.x+(self.width/2)) ):
self.x = other.x+other.width
if( (other.x+(other.width/2)) > (self.x+(self.width/2)) ):
self.x = other.x-self.width
else:
if( (other.y+(other.height/2)) < (self.y+(self.height/2)) ):
self.y = other.y+other.height
if( (other.y+(other.height/2)) > (self.y+(self.height/2)) ):
self.y = other.y-self.height
# Class: Ball
# Superclass: GamePiece
#
# Implement the game ball. This piece's default draw style is a
# filled circle; it automatically moves itself when stepped, increments
# the player's score by 100 when hit by another ball [giving a total
# score of 200], and tries to bounce itself off other objects. The
# latter is sometimes not too successful, however.
# The class changes its default xvel and yvel to 1.
class Ball(GamePiece):
def __init__(self,app,hit_mask,**keys):
# Change default velocities.
if not keys.has_key('xvel'):
keys['xvel'] = 1
if not keys.has_key('yvel'):
keys['yvel'] = 1
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
def Draw(self,where):
if self.pixmap:
where.Paste(self.x,self.y,self.pixmap)
else:
where.ForePen(self.color)
where.FillArc(self.x,self.y,self.width,self.height)
def Step(self):
if( self.xvel < -7 ): self.xvel = -7
if( self.xvel > 7 ): self.xvel = 7
if( self.yvel < -7 ): self.yvel = -7
if( self.yvel > 7 ): self.yvel = 7
self.SetPosition(self.x + self.xvel,self.y + self.yvel)
def do_hit(self,other):
if other.__class__ == Ball:
self.app.LogScore(100) # Note this is called once for each ball.
if( other.width < other.height ):
self.xvel = -self.xvel
if other.__class__ != Wall:
if( self.y < other.y ):
self.yvel = -abs(self.yvel)
elif( (self.y+self.height) > (other.y+other.height) ):
self.yvel = abs(self.yvel)
self.yvel = self.yvel + other.yvel
else:
self.yvel = -self.yvel
if other.__class__ != Wall:
if( self.x < other.x ):
self.xvel = -abs(self.xvel)
elif( (self.x+self.width) > (other.x+other.width) ):
self.xvel = abs(self.xvel)
self.xvel = self.xvel + other.xvel
self.Step()
# Class: Points
# Superclass: GamePiece
#
# A game piece which keeps track of and displays the player's score.
# Defaults to 'hitable' being 0 and a width which will theoretically
# hold a "large" score. Also supports a new argument 'points' which
# defines the initial score.
class Points(GamePiece):
def __init__(self,app,hit_mask,**keys):
if not keys.has_key('hitable'):
keys['hitable'] = 0
if( not keys.has_key('width') ):
tw,th,asc,desc = app.TextExtent(' High: 88888 / Current: 88888 ')
print 'text width',tw
keys['width'] = tw
# Do superclass initialization.
apply(GamePiece.__init__,(self,app,hit_mask),keys)
if( keys.has_key('points') ):
self.points = keys['points']
else:
self.points = 1000
self.high = self.points
# Add a point of the given 'amount' [may be negative] to the running
# total. If this is a new maximum score, take it.
def AddPoints(self,amount):
self.points = self.points + amount
if( self.points > self.high ):
self.high = self.points
# Is the game over?
def IsOver(self):
return self.points < 0
def Draw(self,where):
view = 'High: %5d / Current: %5d' % (self.high,self.points)
w,h,a,d = where.TextExtent(view)
where.ForePen(self.app.shadow_color)
where.DrawText(self.x+self.width-w+1,
self.y+(self.height/2)-(h/2)+a+1,
view, -1)
where.ForePen(self.app.shine_color)
where.DrawText(self.x+self.width-w-1,
self.y+(self.height/2)-(h/2)+a-1,
view, -1)
where.ForePen(self.color)
where.DrawText(self.x+self.width-w,
self.y+(self.height/2)-(h/2)+a,
view, -1)
def do_hit(self,other):
pass
# Class: ihEmbed
# Superclass: iHTML Application
#
# Our top-level class.
class ihEmbed(ihApp.Application):
# Log a change in the user's scored -- called by the pieces.
def LogScore(self,points):
if( not self.is_demo ):
self.points.AddPoints(points)
# Remove the given 'ball' from the playfield. Also removes it
# from the HitMask, which isn't good; the ball should be doing this
# itself, nie?
def RemoveBall(self,ball):
self.ball_count = self.ball_count - 1
try:
self.move_pieces.remove(ball)
except ValueError:
pass
self.hit_mask.RemPiece(ball,ball.y,ball.height)
# Remove the given 'brick' from the playfield. Also removes it
# from the HitMask, which isn't good; the brick should be doing this
# itself, nie?
def RemoveBrick(self,brick):
self.brick_count = self.brick_count - 1
brick.Erase(self.buffer)
try:
self.fixed_pieces.remove(brick)
except ValueError:
pass
self.hit_mask.RemPiece(brick,brick.y,brick.height)
if( self.brick_count == 0 ):
self.build_bricks()
self.draw_all()
# Main application entry.
def __init__(self,rows=6,**args):
# Send all arguments up to parent initialization.
apply(ihApp.Application.__init__,(self,),args)
# Retrieve arguments
self.rows = rows
# Retrieve basic app colors
self.foreground = self.ForePen()
self.background = self.BackPen()
self.wall_color = self.foreground
self.shine_color = self.MakeColor(1,1,1)
self.shadow_color = self.MakeColor(0,0,0)
self.ball_color = self.MakeColor(1,1,0)
self.brick_color = self.MakeColor(.9,.3,.2)
self.paddle_color = self.MakeColor(0,0,.4)
# Create buffer to draw in.
self.buffer = self.MakePixmap(self.Dimensions()[2],
self.Dimensions()[3])
# Initialize mouse coordinates
self.mouse_x = 0
self.mouse_y = 0
self.is_demo = 0
# Find dimensions for playfield
self.find_dimens()
# Create initial game pieces.
self.start_game()
# Draw initial image into buffer and start game.
self.draw_all()
self.update()
# **
# ** All other methods are private
# **
# Find dimensions for screen. This sets a ton of member variable
# which I am not going to document, so there. [Hey! It's a
# dynamically interpreted language! You're -supposed- to be quick
# and loose with your variables. ;)]
def find_dimens(self):
x, y, w, h = self.Dimensions()
tw,th,asc,desc = self.TextExtent('88888888888')
bor = 10
self.width = w
self.height = h
self.inner_width = w-(bor*2)
self.inner_height = h-(bor*2)
self.text_height = th
self.border_width = bor
self.brick_top = bor*3 + th
self.border_width = 10
self.brick_width = (self.inner_width/10)-4
self.paddle_width = w/15
self.paddle_height = bor
self.ball_width = 8
# Create pictures for some game pieces
self.brick_pic = self.MakePixmap(self.brick_width,bor)
self.brick_pic.ForePen(self.brick_color)
self.brick_pic.FillRectangle(0,0,self.brick_width,bor)
self.brick_pic.ForePen(self.shadow_color)
self.brick_pic.DrawLine(0,bor-1,self.brick_width-1,bor-1)
self.brick_pic.DrawLine(self.brick_width-1,0,self.brick_width-1,bor-1)
self.brick_pic.ForePen(self.shine_color)
self.brick_pic.DrawLine(0,0,self.brick_width-1,0)
self.brick_pic.DrawLine(0,0,0,bor-2)
bw = self.ball_width
self.ball_pic = self.MakePixmap(bw,bw)
self.ball_pic.ForePen(self.background)
self.ball_pic.FillRectangle(0,0,bw,bw)
self.ball_pic.ForePen(self.ball_color)
self.ball_pic.FillArc(0,0,bw,bw)
self.ball_pic.ForePen(self.shine_color)
self.ball_pic.DrawArc(0,0,bw,bw,90,270)
self.ball_pic.ForePen(self.shadow_color)
self.ball_pic.DrawArc(0,0,bw,bw,270,90)
self.paddle_pic = self.MakePixmap(self.paddle_width,bor)
self.paddle_pic.ForePen(self.paddle_color)
self.paddle_pic.FillRectangle(0,0,self.paddle_width,bor)
self.paddle_pic.ForePen(self.shadow_color)
self.paddle_pic.DrawLine(0,bor-1,self.paddle_width-1,bor-1)
self.paddle_pic.DrawLine(self.paddle_width-1,0,
self.paddle_width-1,bor-1)
self.paddle_pic.ForePen(self.shine_color)
self.paddle_pic.DrawLine(0,0,self.paddle_width-1,0)
self.paddle_pic.DrawLine(0,0,0,bor-2)
# Start a new game. Initializes the arrays holding pieces, creates
# a HitMask for the game, creates the pieces.
def start_game(self):
self.move_pieces = [] # All pieces which can move
self.fixed_pieces = [] # All pieces which are fixed in place
self.ball_count = 0
self.brick_count = 0
w, h = self.width, self.height
th = self.text_height
bor = self.border_width
inw, inh = self.inner_width, self.inner_height
self.hit_mask = HitMask(h)
self.ball_count = 0
self.brick_count = 0
self.paddle = Paddle(self, self.hit_mask,
x=w/2, y=self.height-self.paddle_height,
width=w/15, height=bor,
color=self.paddle_color,
pixmap=self.paddle_pic)
self.points = Points(self, None,
x=bor*2, y=bor*2,
width = w-(bor*4), height=th+(th/2),
color = self.foreground, points=1000)
self.fixed_pieces.append(Wall(self, self.hit_mask,
x=0, y=0,
width=bor, height=h,
color=self.wall_color))
self.fixed_pieces.append(InvisibleCleaner(self, self.hit_mask,
x=-(bor*2), y=-(bor*2),
width=(bor*2), height=h+(bor*2),
color=self.wall_color))
self.fixed_pieces.append(Wall(self, self.hit_mask,
x=w-bor, y=0,
width=bor, height=h,
color=self.wall_color))
self.fixed_pieces.append(InvisibleCleaner(self, self.hit_mask,
x=w, y=-(bor*2),
width=(bor*2), height=h+(bor*2),
color=self.wall_color))
self.fixed_pieces.append(Wall(self, self.hit_mask,
x=bor, y=0,
width=w-(bor*2), height=bor,
color=self.wall_color))
self.fixed_pieces.append(InvisibleCleaner(self, self.hit_mask,
x=0, y=-(bor*2),
width=w, height=(bor*2),
color=self.wall_color))
self.fixed_pieces.append(InvisibleDeath(self, self.hit_mask,
x=0, y=h+bor,
width=w, height=(bor*2),
color=self.wall_color))
self.move_pieces.append(self.paddle)
self.build_bricks()
# Build the columns of bricks. Builds 'self.cols' number of columns.
def build_bricks(self):
top = self.brick_top
for i in range(self.rows):
for j in range(10):
self.brick_count = self.brick_count + 1
self.fixed_pieces.append(Brick(self, self.hit_mask,
x = ((self.inner_width*j)
/10)+2+self.border_width,
y = top,
width = (self.inner_width/10)-4,
height = self.border_width,
color = self.brick_color,
pixmap = self.brick_pic))
top = top + self.border_width*2
#self.move_pieces.append(Ball(self,x=w/2,y=h/2,width=8,height=8,
# xvel=2,yvel=2,color=self.ball_color))
#print 'Mask array='
#print self.hit_mask.masks
# Draw the entire playfield in the buffer. This is only done when
# something drastically changes.
def draw_all(self):
self.buffer.ForePen(self.background)
self.buffer.FillRectangle(0,0,self._Widget_.Dimensions()[2],
self._Widget_.Dimensions()[3])
for i in self.move_pieces:
i.Draw(self.buffer)
for i in self.fixed_pieces:
i.Draw(self.buffer)
self.points.Draw(self.buffer)
self.redraw()
# Redraw the main window. This just involves copying the buffer in
# to it.
def redraw(self):
self.Paste(0,0,self.buffer)
self.Flush()
pass
# Erase all of the dynamic pieces.
def erase_pieces(self):
for i in self.move_pieces:
i.Erase(self.buffer)
self.points.Erase(self.buffer)
# Draw all of the dynamic pieces.
def draw_pieces(self):
for i in self.move_pieces:
i.Draw(self.buffer)
self.points.Draw(self.buffer)
# Update the game. Erase all pieces, step all pieces, get mouse
# position and move paddle, check for collisions, redraw display.
def update(self):
#print self.MouseState()
self.FutureCall(.05,self.update)
self.erase_pieces()
self.LogScore(-(self.ball_count)/2 - 1)
for i in self.move_pieces:
i.Step()
# For some reason, MousePosition() seems to be deadly slow
# when the mouse is moving in the window... HUH?
#self.mouse_x, self.mouse_y = self.MousePosition()
#print self.MousePosition()
if( self.is_demo ):
lowest = None
follow = None
for i in self.move_pieces:
if( i.__class__ == Ball ):
if( not lowest or i.y > lowest.y ):
lowest = i
if( i.yvel >= 0 and (not follow or i.y > follow.y) ):
follow = i
if( not follow ):
follow = lowest
if( follow ):
if( follow.x > (self.mouse_x+10) ):
self.mouse_x = self.mouse_x+10
elif( follow.x < (self.mouse_x-10) ):
self.mouse_x = self.mouse_x-10
else:
self.mouse_x = follow.x
if( (not lowest) or lowest.y < (self.height/2) ):
self.add_ball(self.mouse_x,self.mouse_y)
if( self.mouse_x < self.border_width ):
self.mouse_x = self.border_width
if( self.mouse_x > (self.width-self.border_width) ):
self.mouse_x = self.width-self.border_width
if( self.mouse_y < self.border_width ):
self.mouse_y = self.border_width
if( self.mouse_y > (self.height-self.border_width) ):
self.mouse_y = self.height-self.border_width
self.paddle.do_mouse(None,self.mouse_x,self.height-self.paddle_height)
for i in self.move_pieces:
#print 'PieceMask:'
#print self.hit_mask.PieceMask(i.y,i.height)
for j in self.hit_mask.PieceMask(i.y,i.height):
#print j
# Problem -- if a piece occurs in more than one slice, we
# may hit it twice.
i.Hit(j)
self.draw_pieces()
if( self.points.IsOver() ):
self.start_game()
self.draw_all()
else:
self.redraw()
# Handle redraw events.
def OnRedraw(self,ev,x,y,w,h):
self.redraw()
# Handle keypress events.
def OnKeyPress(self,ev,key,state):
keystr = chr(key)
if( keystr == 'n' ):
self.is_demo = 0
self.points.AddPoints(-100000)
if( keystr == 'd' ):
self.is_demo = 1
# Handle mouse events.
def add_ball(self,x,y):
if( self.ball_count < 4 ):
self.ball_count = self.ball_count + 1
self.move_pieces.append(Ball(self, self.hit_mask,
x=self.paddle.x
+(self.paddle.width/2)-4,
y=self.paddle.y-8,
width=self.ball_width,
height=self.ball_width,
xvel=self.paddle.xvel,
yvel=-5,
color=self.ball_color,
pixmap=self.ball_pic))
def OnMouse(self,ev,x,y,state,hit):
if( ev.Code == ihEvent.CodeNames['MousePress'] ):
self.add_ball(x,y)
if( not self.is_demo ):
self.mouse_x = x
self.mouse_y = y
__export__ = ['ihEmbed']
![]()
| Dianne Kyra Hackborn <hackbod@angryredplanet.com> | Last modified: Wed Aug 14 14:33:18 PDT 1996 |