Advertisement
4karsh

Pong! for Codeskulptor

May 5th, 2013
1,844
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 25.60 KB | None | 0 0
  1. """
  2. Simplified Pong!
  3.  
  4. Attributions under CC:
  5. http://creativecommons.org/licenses/by/3.0/
  6.  
  7. Sounds:
  8. PongBlipF4.wav
  9. http://www.freesound.org/people/NoiseCollector/sounds/4359/
  10.  
  11. Error.wav
  12. http://www.freesound.org/people/Autistic%20Lucario/sounds/142608/
  13. """
  14.  
  15. import math
  16. import simplegui
  17. import random
  18.  
  19. #Globals
  20.  
  21. # Room dimensions
  22. room_width = 600
  23. room_height = 400
  24. top_margin = 80
  25. room_center = ( room_width/2, (room_height + top_margin)/2 )
  26.  
  27. # Ball parameters
  28. ball_radius = 8
  29.  
  30. # Paddle parameters
  31. player1_speed = 8
  32. player2_speed = player1_speed
  33. paddle_length = 80
  34. paddle_width = 8
  35.  
  36. # Paddle Movement sensitivity
  37. UP = (0, -1) # move paddle in up/negative Y direction
  38. DOWN = (0, 1) # move paddle in down/positive Y direction
  39.  
  40. # Single or Two Player
  41. player2_auto = False
  42.  
  43. """
  44. Classes
  45. """
  46. ## Geometric Primitives
  47. # Rectangle
  48. class Rect(object):
  49.     def __init__(self, center, width, height, color="White"):
  50.         self.width = width
  51.         self.height = height
  52.         self.center = center
  53.         self.color = color
  54.  
  55.     def getWidth(self):
  56.         return self.width
  57.  
  58.     def getHeight(self):
  59.         return self.height
  60.  
  61.     def getCenter(self):
  62.         return self.center
  63.  
  64.     def getTopLeft(self):
  65.         """
  66.         Calculate topLeft based on center coordinates.
  67.         Useful when moving the rect by changing center coordinates
  68.        """
  69.         center = self.center
  70.         width = self.width
  71.         height = self.height
  72.         return ((center[0] - width/2), (center[1] - height/2))
  73.  
  74.     def pointList(self):
  75.         topLeft = self.getTopLeft()
  76.         return ([topLeft, \
  77.                  (topLeft[0] + self.width, topLeft[1]), \
  78.                  (topLeft[0] + self.width, topLeft[1] + self.height), \
  79.                  (topLeft[0], topLeft[1] + self.height)])
  80.  
  81.     def intersection(self, point):
  82.         """
  83.        Determine if a given point is inside or outside the rectangle
  84.  
  85.        point: tuple
  86.        returns True if point is ON the edges or INSIDE the shape
  87.        else False
  88.        """
  89.         topLeft = self.getTopLeft()
  90.         xIntersect = point[0] >= topLeft[0] \
  91.             and point[0] <= topLeft[0] + self.width
  92.  
  93.         yIntersect = point[1] >= topLeft[1] \
  94.             and point[1] <= topLeft[1] + self.height
  95.  
  96.         return xIntersect and yIntersect
  97.  
  98.     def draw(self, canvas):
  99.         canvas.draw_polygon(self.pointList(), 1, self.color, self.color)
  100.  
  101. # Circle
  102. class Circle(object):
  103.     def __init__(self, center, radius, color="White"):
  104.         self.center = center
  105.         self.radius = radius
  106.         self.color = color
  107.  
  108.     def getCenter(self):
  109.         return self.center
  110.  
  111.     def getRadius(self):
  112.         return self.radius
  113.  
  114.     def distanceToCenter(self, point):
  115.         """ Distance between a point somewhere in space, and the center of this circle """
  116.         return math.sqrt( (point[0] - self.center[0])**2  + (point[1] - self.center[1])**2 )
  117.  
  118.     def getBoundingBox(self):
  119.         return Rect(self.getCenter(), self.getRadius()*2, self.getRadius()*2)
  120.  
  121.     def intersection(self, point):
  122.         """
  123.        Determine if a given point is inside or outside the circle
  124.  
  125.        point: tuple
  126.        returns True if point is ON the edges or INSIDE the shape
  127.        else False
  128.        """
  129.         distance = self.distanceToCenter(point)
  130.         return self.radius >= distance
  131.  
  132.     def draw(self, canvas):
  133.         canvas.draw_circle(self.center, self.radius, 1, self.color, self.color)
  134.  
  135. # Classes: Vectors (cartesian)
  136. class Vector(object):
  137.     def __init__(self, coordinates):
  138.         self.coordinates = coordinates
  139.  
  140.     def getCoordinates(self):
  141.         # Returns Cartesian coordinates of this vector
  142.         return self.coordinates
  143.  
  144.     def getMagnitude(self):
  145.         # Returns magnitude of this vector
  146.         x = self.coordinates[0]
  147.         y = self.coordinates[1]
  148.         return math.sqrt(x**2 + y**2)
  149.  
  150.     def dot(self, v2):
  151.         """
  152.        Dot product of this and v2
  153.        Returns a scalar value
  154.        """
  155.         x = self.coordinates[0]
  156.         y = self.coordinates[1]
  157.         v2_coord = v2.getCoordinates()
  158.         result = (x * v2_coord[0]) + (y * v2_coord[1])
  159.         return result
  160.  
  161.     def __add__(self, v2):
  162.         """
  163.        Add this vector to another vector v2
  164.        Returns tuple of resultant vector
  165.        """
  166.         x = self.coordinates[0]
  167.         y = self.coordinates[1]
  168.         v2_coord = v2.getCoordinates()
  169.         result = (x + v2_coord[0], y + v2_coord[1])
  170.         return Vector(result)
  171.  
  172.     def __sub__(self, v2):
  173.         """
  174.        Subtract v2 from this vector
  175.        Returns tuple of resultant vector
  176.        """
  177.         x = self.coordinates[0]
  178.         y = self.coordinates[1]
  179.         v2_coord = v2.getCoordinates()
  180.         result = (x - v2_coord[0], y - v2_coord[1])
  181.         return Vector(result)
  182.  
  183.     def normalize(self):
  184.         """
  185.        Returns the normalized coordinates of this vector
  186.        """
  187.         magnitude = self.getMagnitude()
  188.         x = self.coordinates[0]
  189.         y = self.coordinates[1]
  190.         result = (x/magnitude, y/magnitude)
  191.         return Vector(result)
  192.  
  193.     def scalarMul(self, C):
  194.         """
  195.        Scalar multiplication of a vector
  196.        Returns tuple containing coordinates multiplied by the scalar
  197.        """
  198.         x = self.coordinates[0]
  199.         y = self.coordinates[1]
  200.         result = (C*x, C*y)
  201.         return Vector(result)
  202.  
  203.     def proj(self, v2):
  204.         """
  205.        Project this onto v2. v2 should be the surface normal of a wall or other object
  206.        """
  207.         n = v2.normalize()
  208.         return n.scalarMul(self.dot(n))
  209.  
  210.     def reflectionVector(self, v2):
  211.         """
  212.        http://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector
  213.        Coupe de grace; Reflects this according to the law of reflection
  214.        v2 is the surface normal of reflecting surface
  215.  
  216.        Returns a tuple containing coordinates of reflected vector
  217.        """
  218.         v1_projected_v2 = (self.proj(v2)).scalarMul(2).getCoordinates()
  219.         x = self.coordinates[0] - v1_projected_v2[0]
  220.         y = self.coordinates[1] - v1_projected_v2[1]
  221.         return Vector((x, y))
  222.  
  223. ## Classes: Game Elements
  224. # Ball
  225. class Ball(Circle):
  226.     """
  227.    Define a ball object which is a circle with additional properties
  228.  
  229.    speed: position increment in pixels. Position will change with every
  230.    call to move()
  231.    direction: angle measured from positive x axis
  232.    """
  233.     def __init__(self, center, radius, velocity):
  234.         Circle.__init__(self, center, radius, "Yellow")
  235.         self.velocity = velocity
  236.  
  237.     def getSpeed(self):
  238.         return self.velocity.getMagnitude()
  239.  
  240.     def getDirection(self):
  241.         return self.velocity.normalize().getCoordinates()
  242.  
  243.     def setPosition(self, center):
  244.         self.center = center
  245.  
  246.     def getVelocity(self):
  247.         return self.velocity
  248.  
  249.     def setVelocity(self,  direction):
  250.         self.velocity = Vector(direction)
  251.  
  252.     def move(self):
  253.         c = self.getCenter()
  254.         speed = self.getSpeed()
  255.         d = self.getDirection()
  256.         new_pos = [(c[0] + speed * d[0]), (c[1] + speed * d[1])]
  257.         if new_pos[0] < 0:
  258.             new_pos[0] = 0
  259.         elif new_pos[0] > room_width - paddle_width - 1:
  260.             new_pos[0] = room_width - paddle_width - 1
  261.         if new_pos[1] < (top_margin + paddle_width)/2:
  262.             new_pos[1] = (top_margin + paddle_width)/2
  263.         elif new_pos[1] > (top_margin + paddle_width)/2 + room_height:
  264.             new_pos[1] = room_height
  265.         self.setPosition( tuple(new_pos) )
  266.        
  267.  
  268.     def reflect(self, normal):
  269.         """
  270.            The velocity vector is reflected according to the law of reflection,
  271.            upon collision with a surface
  272.        """
  273.         self.velocity = self.velocity.reflectionVector(normal)
  274.  
  275. # Paddle
  276. class Paddle(Rect):
  277.     """
  278.    Define a paddle object which is a Rect with additional properties
  279.  
  280.    speed: position increment in pixels. Position will change with every
  281.    call to move()
  282.    direction: either down or up
  283.    """
  284.     def __init__(self, center, width, height, color, velocity, surfaceNormal):
  285.         Rect.__init__(self, center, width, height, color)
  286.         self.normal = surfaceNormal
  287.         self.velocity = velocity
  288.  
  289.     def getSpeed(self):
  290.         return self.velocity.getMagnitude()
  291.  
  292.     def getDirection(self):
  293.         return self.velocity.normalize().getCoordinates()
  294.  
  295.     def getSurfaceNormal(self):
  296.         return self.normal
  297.  
  298.     def setPosition(self, center):
  299.         self.center = center
  300.  
  301.     def setVelocity(self, vel):
  302.         self.velocity = Vector(vel)
  303.  
  304.     def move(self):
  305.         speed = self.getSpeed()
  306.         d = self.getDirection()
  307.         newy = self.center[1] + speed * d[1]
  308.         self.center = (self.center[0], newy)
  309.  
  310. # Wall/Boundaries
  311. class Wall(Rect):
  312.     """
  313.    Define a paddle object which is a Rect with additional properties
  314.  
  315.    speed: position increment in pixels. Position will change with every
  316.    call to move()
  317.    direction: either down or up
  318.    """
  319.     def __init__(self, center, width, height, surfaceNormal):
  320.         Rect.__init__(self, center, width, height)
  321.         self.surfaceNormal = surfaceNormal
  322.  
  323.     def getSurfaceNormal(self):
  324.         # Return the Surface Normal Vector
  325.         return self.surfaceNormal
  326.  
  327. """
  328.    Helper functions
  329. """
  330.  
  331. # Random Velocity
  332. def genRandomVelocity(sgn=0):
  333.     if sgn != 0:
  334.         # If sign is specified, only generate Y randomly
  335.         x = sgn * random.randrange(120, 240)
  336.         y = random.randrange(-1,2,2) * random.randrange(60, 180)
  337.         return ((x/60, y/60))
  338.     else:
  339.         # Sign is not specified, both components are random
  340.         x = random.randrange(-1,2,2) * random.randrange(120, 240)
  341.         y = random.randrange(-1,2,2) * random.randrange(60, 180)
  342.         return ((x/60, y/60))
  343.  
  344. # Determine collisions
  345. def intersectingShapes(shape1, shape2):
  346.     """
  347.    Takes 2 shapes and determines if there is any overlap
  348.  
  349.    returns: True if shape1, and shape2 overlap
  350.    """
  351.     # Rect and Rect
  352.     def overlappingRectangles(shape1, shape2):
  353.         """
  354.        If rectangles are of different sizes, need to check if vertices
  355.        of smaller rectangle are inside the larger one.
  356.        """
  357.         vertices_shape1 = shape1.pointList()
  358.         vertices_shape2 = shape2.pointList()
  359.         for v1 in vertices_shape1:
  360.             if shape2.intersection(v1):
  361.                 return True
  362.         else:
  363.             for v2 in vertices_shape2:
  364.                 if shape1.intersection(v2):
  365.                     return True
  366.             else:
  367.                 return False
  368.  
  369.     # Circle and Rectangle
  370.     def overlappingCircleandRect(shape1, shape2):
  371.         if isinstance(shape1, Circle):
  372.             c = shape1
  373.             r = shape2
  374.         else:
  375.             c = shape2
  376.             r = shape1
  377.  
  378.         boundingBox = c.getBoundingBox()
  379.         vertices = r.pointList()
  380.         for vertex in vertices:
  381.             if c.intersection(vertex):
  382.                 return True
  383.         else:
  384.             return overlappingRectangles(r, boundingBox)
  385.  
  386.     if isinstance(shape1, Rect) and isinstance(shape2, Rect):
  387.         return overlappingRectangles(shape1, shape2)
  388.  
  389.     elif    isinstance(shape1, Circle) and isinstance(shape2, Rect) \
  390.         or  isinstance(shape2, Circle) and isinstance(shape1, Rect):
  391.         return overlappingCircleandRect(shape1, shape2)
  392.  
  393. """
  394.    Initialize and Load Game
  395. """
  396. def game_init():
  397.     """ Loads the game environment """
  398.     # Game elements
  399.     global pong_ball, top_wall, bottom_wall, player1_paddle, player2_paddle, roomRect
  400.     # Controls, scoring
  401.     global keyboard, player1_score, player2_score, match_point
  402.     # Flags
  403.     global start_game, player1_out, player2_out
  404.     # Game Assets
  405.     global ball_hit_sound, ball_out_sound
  406.  
  407.     # Game Elements
  408.     # Ball
  409.     pong_ball = Ball( room_center, ball_radius, Vector(genRandomVelocity()) )
  410.  
  411.     # Walls
  412.     top_wall_y = top_margin/2
  413.     bottom_wall_y = top_wall_y + room_height + paddle_width
  414.  
  415.     top_wall = Wall( (room_width/2, top_wall_y), room_width, paddle_width, Vector((0, 1)) )
  416.     bottom_wall = Wall( (room_width/2, bottom_wall_y), room_width, paddle_width, Vector((0, -1)) )
  417.     # print (bottom_wall.getCenter()[1] - paddle_width/2) - (top_wall.getCenter()[1] + paddle_width/2)  # should be == room_width
  418.  
  419.     # Paddles
  420.     paddles_y = room_center[1]
  421.     player1_vel = Vector(DOWN).scalarMul(player1_speed)
  422.     player2_vel = Vector(DOWN).scalarMul(player2_speed)
  423.  
  424.     player1_paddle = Paddle( (paddle_width/2, paddles_y), paddle_width, paddle_length, "Red", player1_vel, Vector((1, 0)) )
  425.     player2_paddle = Paddle( (room_width - paddle_width/2 - 1, paddles_y), paddle_width, paddle_length, "Blue", player2_vel, Vector((-1, 0)) )
  426.  
  427.     # Canvas (Game map/area)
  428.     roomRect = Rect(room_center, room_width, room_height + top_margin)
  429.  
  430.     # User Control
  431.     keyboard = {'up' : False,
  432.                 'down' : False,
  433.                 'w' : False,
  434.                 's' : False,
  435.                 }
  436.  
  437.     # Scoring
  438.     player1_score = 0
  439.     player2_score = 0
  440.     match_point = 7
  441.  
  442.     # Flags
  443.     start_game = False
  444.     player1_out = False
  445.     player2_out = False
  446.  
  447.     # Game Assets
  448.     # Sounds
  449.     ball_hit_sound = simplegui.load_sound("http://www.freesound.org/people/NoiseCollector/sounds/4359/download/4359__noisecollector__pongblipf4.wav")
  450.     ball_out_sound = simplegui.load_sound("http://www.freesound.org/people/Autistic%20Lucario/sounds/142608/download/142608__autistic-lucario__error.wav")
  451.  
  452. game_init()
  453.  
  454. """
  455.    Movement and animation functions
  456. """
  457.  
  458. """
  459.    Ball Movements
  460. """
  461.  
  462. # Ball out of bounds
  463. def ball_outOfBounds(ball):
  464.     global player1_out, player2_out
  465.     c = ball.getCenter()
  466.     r = ball.getRadius()
  467.     d = ball.getDirection()
  468.     p1 = player1_paddle.getCenter()
  469.     p2 = player2_paddle.getCenter()
  470.     if d[0] < 0:
  471.         # Ball out of bounds on left side of screen
  472.         if (c[1] + r <= p1[1] - player1_paddle.getHeight()/2)\
  473.         or (c[1] - r >= p1[1] + player1_paddle.getHeight()/2):
  474.             ball_out = (c[0] - r <= paddle_width)\
  475.                     or (c[0] + r >= room_width - paddle_width)
  476.             if ball_out:
  477.                 player1_out = True
  478.             return ball_out
  479.     elif d[0] > 0:
  480.         # Ball out of bounds on right side of screen
  481.         if (c[1] + r <= p2[1] - player1_paddle.getHeight()/2)\
  482.         or (c[1] - r >= p2[1] + player1_paddle.getHeight()/2):
  483.             ball_out = (c[0] - r <= paddle_width)\
  484.                     or (c[0] + r >= room_width - paddle_width)
  485.             if ball_out:
  486.                 player2_out = True
  487.             return ball_out
  488.        
  489. # Reset Ball Position
  490. def ball_reset():
  491.     """ Reset the ball, when it goes out of bounds """
  492.     global start_game, player1_out, player2_out
  493.     start_game = player1_out = player2_out = False  
  494.     ball_out_sound.play()
  495.     reset_timer.start()
  496.  
  497. # Ball Reset timer
  498. def reset_pause():
  499.     global start_game
  500.     start_game = True
  501.     pong_ball.setPosition(room_center)
  502.     reset_timer.stop()
  503.  
  504. # Buffer zone around surfaces before smartly testing for collisions
  505. def ball_buffer():
  506.     """ Returns the distance between center of ball and center of paddle
  507.        one timestep before imminent collision.
  508.    """
  509.     return (paddle_width/2 + pong_ball.getSpeed() + ball_radius)
  510.  
  511. # Smartly determine if ball is in dangerzone (dz) and
  512. # collision is imminent (after one additional timestep)
  513. dz_left = player1_paddle.getCenter()[0] + ball_buffer()
  514. dz_right = player2_paddle.getCenter()[0] - ball_buffer()
  515. dz_top = top_wall.getCenter()[1] + ball_buffer()
  516. dz_bottom = bottom_wall.getCenter()[1] - ball_buffer()
  517.  
  518. def ball_collisions():
  519.     """
  520.    Since the game has only one moving object, with 4 fixed surfaces, and a room of known size
  521.    significant efficiency gains can be achieved by not checking for collisions
  522.    on every single draw callback.
  523.  
  524.    This function will smartly check for collisions based on distance between surfaces and ball
  525.    """
  526.     pong_ball_center = pong_ball.getCenter()
  527.     pong_ball_dir = pong_ball.getDirection()
  528.  
  529.     # Left paddle (player 1)
  530.     if pong_ball_center[0] <= dz_left and pong_ball_dir[0] < 0:
  531.         if intersectingShapes(player1_paddle, pong_ball):
  532.             ball_hit_sound.play()
  533.             pong_ball.reflect(player1_paddle.getSurfaceNormal())
  534.             pong_ball.setVelocity(pong_ball.getVelocity().scalarMul(1.1).getCoordinates())
  535.  
  536.     # Right paddle (player 2)
  537.     elif pong_ball_center[0] >= dz_right and pong_ball_dir[0] > 0:
  538.         if intersectingShapes(player2_paddle, pong_ball):
  539.             ball_hit_sound.play()
  540.             pong_ball.reflect(player2_paddle.getSurfaceNormal())
  541.             pong_ball.setVelocity(pong_ball.getVelocity().scalarMul(1.1).getCoordinates())
  542.  
  543.     # Top wall
  544.     if pong_ball_center[1] <= dz_top and pong_ball_dir[1] < 0:
  545.         if intersectingShapes(top_wall, pong_ball):
  546.             ball_hit_sound.play()
  547.             pong_ball.reflect(top_wall.getSurfaceNormal())
  548.  
  549.     # Bottom wall
  550.     elif pong_ball_center[1] >= dz_bottom and pong_ball_dir[1] > 0:
  551.         if intersectingShapes(bottom_wall, pong_ball):
  552.             ball_hit_sound.play()
  553.             pong_ball.reflect(bottom_wall.getSurfaceNormal())
  554.  
  555. """
  556.    Scoring
  557. """
  558. def calculateScores():
  559.     global player1_score, player2_score
  560.     # Updates scores.
  561.     if player2_out:
  562.         player1_score += 1
  563.     elif player1_out:
  564.         player2_score += 1
  565.  
  566. def isGameOver():
  567.     return player1_score == match_point\
  568.         or player2_score == match_point
  569.  
  570. """
  571.    User Controls: Paddle Movements
  572. """
  573. # Determine if paddle is able to move
  574. def paddle_validMove(paddle):
  575.     """ Move the paddle if it won't collide with the walls """
  576.     speed = paddle.getSpeed()
  577.     d = paddle.getDirection()
  578.     newy = paddle.getCenter()[1] + speed * d[1]  # predicted position of paddle center after one tick
  579.  
  580.     # Paddle moving UP
  581.     if d[1] < 0 :
  582.        newy -= paddle_length/2
  583.        boundary = top_wall.getCenter()[1] + paddle_width/2
  584.        if newy <= boundary:
  585.             paddle.setPosition( (paddle.getCenter()[0], boundary + paddle_length/2) )
  586.        else:
  587.             paddle.move()
  588.     # Paddle moving DOWN
  589.     elif d[1] > 0 :
  590.        newy += paddle_length/2
  591.        boundary = bottom_wall.getCenter()[1] - paddle_width/2
  592.        if newy >= boundary:
  593.             paddle.setPosition( (paddle.getCenter()[0], boundary - paddle_length/2) )
  594.        else:
  595.             paddle.move()
  596.  
  597. # Player1 movement
  598. def player1_move(paddle):
  599.     if keyboard['s']:
  600.         paddle.setVelocity(Vector(DOWN).scalarMul(player1_speed).getCoordinates())
  601.         paddle_validMove(paddle)
  602.     elif keyboard['w']:
  603.         paddle.setVelocity(Vector(UP).scalarMul(player1_speed).getCoordinates())
  604.         paddle_validMove(paddle)
  605.  
  606. # Player2 Movement
  607. def player2_move(paddle):
  608.     if player2_auto:
  609.         # Computer controlled second paddle
  610.         target = pong_ball.getCenter()
  611.         current = paddle.getCenter()      
  612.  
  613.         # move computer paddle only after player has struck the ball and pong_ball.getCenter()[0] > room_width/2
  614.         if pong_ball.getDirection()[0] > 0:
  615.             if target[1] < current[1]:
  616.                 paddle.setVelocity(Vector(UP).scalarMul(player2_speed).getCoordinates())
  617.             if target[1] > current[1]:
  618.                 paddle.setVelocity(Vector(DOWN).scalarMul(player2_speed).getCoordinates())
  619.             paddle_validMove(paddle)
  620.     else:
  621.         # User controlled second paddle
  622.         if keyboard['down']:
  623.             paddle.setVelocity(Vector(DOWN).scalarMul(player2_speed).getCoordinates())
  624.             paddle_validMove(paddle)
  625.         elif keyboard['up']:
  626.             paddle.setVelocity(Vector(UP).scalarMul(player2_speed).getCoordinates())
  627.             paddle_validMove(paddle)
  628.  
  629.  
  630. """
  631.    Game Animations
  632. """
  633. # Movement of all objects in game
  634. def game_movement():
  635.     """ Movement and collision detection for all game objects """
  636.     # Paddles should move regardless of what the ball is doing
  637.     player1_move(player1_paddle)
  638.     player2_move(player2_paddle)
  639.  
  640.     # Ball: Check for boundary violations/collisions
  641.     if not ball_outOfBounds(pong_ball):
  642.         ball_collisions()
  643.         pong_ball.move()
  644.  
  645.     elif ball_outOfBounds(pong_ball) and not reset_timer.is_running():
  646.         p1Score = player1_score
  647.         p2Score = player2_score
  648.         calculateScores()
  649.         ball_reset() # start reset timer
  650.         if player1_score > p1Score:
  651.             pong_ball.setVelocity(genRandomVelocity(-1))
  652.         elif player2_score > p2Score:
  653.             pong_ball.setVelocity(genRandomVelocity(1))
  654.  
  655.            
  656. """
  657.    Game Draw functions
  658. """
  659.  
  660. def draw_scores(canvas):
  661.     canvas.draw_text(str(player1_score), (room_width/4, (top_margin - paddle_width)/3), 24, "White")
  662.     canvas.draw_text(str(player2_score), (room_width/4 + room_width/2, (top_margin - paddle_width)/3), 24, "White")
  663.  
  664. def game_over(canvas):
  665.     def gameover_msg_coordinates(message, text_size):
  666.         message_width = pong_frame.get_canvas_textwidth(message, text_size)
  667.         x = (room_center[0] - message_width)/2
  668.         y = room_center[1]
  669.         return (x, y)
  670.  
  671.     if player1_score > player2_score:
  672.         message = "P1 WIN!"
  673.         coord = gameover_msg_coordinates(message, 24)
  674.         canvas.draw_text(message, coord, 24, "Red")
  675.     else:
  676.         message = "P2 WIN!"
  677.         coord = gameover_msg_coordinates(message, 24)
  678.         canvas.draw_text(message, coord, 24, "Blue")
  679.  
  680. def draw_game_static_env(canvas):
  681.     """ Draw all the static objects in the game environment """
  682.     # centerline
  683.     canvas.draw_line( (room_width/2, top_wall.getCenter()[1]), (room_width/2, bottom_wall.getCenter()[1]), 2, "White")
  684.     canvas.draw_line([paddle_width, top_wall.getCenter()[1]],[paddle_width, bottom_wall.getCenter()[1]], 1, "White")
  685.     canvas.draw_line([room_width - paddle_width - 1, top_wall.getCenter()[1]],[room_width - paddle_width, bottom_wall.getCenter()[1]], 1, "White")
  686.  
  687.     # walls
  688.     top_wall.draw(canvas)
  689.     bottom_wall.draw(canvas)
  690.  
  691.     # scores
  692.     draw_scores(canvas)
  693.  
  694. def draw_ball_paddles(canvas):
  695.     # Draw Ball
  696.     pong_ball.draw(canvas)
  697.     # Draw Paddles
  698.     player1_paddle.draw(canvas)
  699.     player2_paddle.draw(canvas)
  700.    
  701. # Main game callback (auto-loop)
  702. def draw(canvas):
  703.     global start_game
  704.  
  705.     # draw static elements
  706.     draw_game_static_env(canvas)    
  707.  
  708.     # Check if current game is over
  709.     if not isGameOver():
  710.         draw_ball_paddles(canvas)
  711.         # Check that the game is not blocked,
  712.         # or new game has not yet been started
  713.         if start_game:
  714.             game_movement()
  715.     else:
  716.         """ Game has ended, print game results, and freeze canvas
  717.            until user creates a new game
  718.        """
  719.         draw_ball_paddles(canvas)
  720.         start_game = False
  721.         game_over(canvas)
  722.  
  723. """
  724.    Event Handlers and Game Loop
  725. """
  726. # New Game Button Handler
  727.  
  728. # Mouseclick- Game start
  729. def mouseclick_startGame(position):
  730.     global start_game
  731.     if not start_game:
  732.         start_game = True
  733.  
  734. # Enable single player mode, player2 paddle will be controlled by computer
  735. def singlePlayer():
  736.     global player2_auto
  737.     game_init()
  738.     player2_auto = True
  739.  
  740. # 2Player Button Handler
  741. def twoPlayer():
  742.     global player2_auto
  743.     game_init()
  744.     player2_auto = False
  745.  
  746. # Key is pushed and held down
  747. def keydown(key):
  748.     if key == simplegui.KEY_MAP['s']:
  749.         keyboard['s'] = True
  750.     elif key == simplegui.KEY_MAP['w']:
  751.         keyboard['w'] = True
  752.     if key == simplegui.KEY_MAP['down']:
  753.         keyboard['down'] = True
  754.     elif key == simplegui.KEY_MAP['up']:
  755.         keyboard['up'] = True
  756.  
  757. # Key is released
  758. def keyup(key):
  759.     if key == simplegui.KEY_MAP['s']:
  760.         keyboard['s'] = False
  761.     elif key == simplegui.KEY_MAP['w']:
  762.         keyboard['w'] = False
  763.     if key == simplegui.KEY_MAP['down']:
  764.         keyboard['down'] = False
  765.     elif key == simplegui.KEY_MAP['up']:
  766.         keyboard['up'] = False
  767.  
  768.  
  769. """
  770. Game Window Settings
  771. """
  772. def gameWindow_init():
  773.     global pong_frame, reset_timer
  774.  
  775.     # Create Game Window
  776.     pong_frame = simplegui.create_frame("Pong", roomRect.getWidth(), roomRect.getHeight(), 300)
  777.     game_instructions = []
  778.     game_instructions.append(pong_frame.add_label("Welcome to Pong!"))
  779.     game_instructions.append(pong_frame.add_label(""))
  780.     game_instructions.append(pong_frame.add_label("Up and Down arrow keys control the Blue paddle"))
  781.     game_instructions.append(pong_frame.add_label(""))
  782.     game_instructions.append(pong_frame.add_label("W and S keys control the Red paddle"))
  783.     game_instructions.append(pong_frame.add_label(""))
  784.     game_instructions.append(pong_frame.add_label("Click anywhere in the game window to start"))
  785.     game_instructions.append(pong_frame.add_label(""))
  786.     game_instructions.append(pong_frame.add_label("May the force be with you."))
  787.     game_instructions.append(pong_frame.add_label(""))
  788.  
  789.     # Game Window Buttons and Controls
  790.     # resetButton = pong_frame.add_button("New Game", new_game, 150)
  791.     pong_frame.add_button("Single Player (vs Computer)", singlePlayer, 250)
  792.     pong_frame.add_button("2 Player (Restart)", twoPlayer, 250)
  793.  
  794.     # Timers
  795.     reset_timer = simplegui.create_timer(1000, reset_pause)
  796.  
  797.     # Register event handlers
  798.     pong_frame.set_keydown_handler(keydown)
  799.     pong_frame.set_keyup_handler(keyup)
  800.     pong_frame.set_draw_handler(draw)
  801.     pong_frame.set_mouseclick_handler(mouseclick_startGame)
  802.  
  803. # Start the frame animation
  804. gameWindow_init()
  805. pong_frame.start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement