Advertisement
Guest User

Gameobjects

a guest
Dec 10th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.53 KB | None | 0 0
  1. import images
  2. import pygame
  3. import pymunk
  4. import math
  5.  
  6.  
  7. '''Contains classes to create game objects, such as tanks and boxes.'''
  8.  
  9.  
  10. DEBUG = False # Change this to set it in debug mode
  11.  
  12.  
  13. def physics_to_display(x):
  14.     """ This function is used to convert coordinates in the physic engine into the display coordinates """
  15.     return x * images.TILE_SIZE
  16.  
  17.  
  18. class GameObject:
  19.     """ Mostly handles visual aspects (pygame) of an object.
  20.       Subclasses need to implement two functions:
  21.       - screen_position    that will return the position of the object on the screen
  22.       - screen_orientation that will return how much the object is rotated on the screen (in degrees). """
  23.  
  24.     def __init__(self, sprite):
  25.         self.sprite         = sprite
  26.  
  27.  
  28.     def update(self):
  29.         """ Placeholder, supposed to be implemented in a subclass.
  30.           Should update the current state (after a tick) of the object."""
  31.         return
  32.  
  33.     def post_update(self):
  34.         """ Should be implemented in a subclass. Make updates that depend on
  35.           other objects than itself."""
  36.         return
  37.  
  38.  
  39.     def update_screen(self, screen):
  40.         """ Updates the visual part of the game. Should NOT need to be changed
  41.           by a subclass."""
  42.         sprite = self.sprite
  43.  
  44.         p = self.screen_position() # Get the position of the object (pygame coordinates)
  45.         sprite = pygame.transform.rotate(sprite, self.screen_orientation()) # Rotate the sprite using the rotation of the object
  46.  
  47.         # The position of the screen correspond to the center of the object,
  48.         # but the function screen.blit expect to receive the top left corner
  49.         # as argument, so we need to adjust the position p with an offset
  50.         # which is the vector between the center of the sprite and the top left
  51.         # corner of the sprite
  52.         offset = pymunk.Vec2d(sprite.get_size()) / 2.
  53.         p = p - offset
  54.         screen.blit(sprite, p) # Copy the sprite on the screen
  55.  
  56.  
  57.  
  58. class GamePhysicsObject(GameObject):
  59.     """ This class extends GameObject and it is used for objects which have a
  60.       physical shape (such as tanks and boxes). This class handle the physical
  61.       interaction of the objects.
  62.   """
  63.  
  64.     def __init__(self, x, y, orientation, sprite, space, movable):
  65.         """ Takes as parameters the starting coordinate (x,y), the orientation, the sprite (aka the image
  66.           representing the object), the physic engine object (space) and whether the object can be
  67.           moved (movable).
  68.       """
  69.  
  70.         super().__init__(sprite)
  71.  
  72.         # Half dimensions of the object converted from screen coordinates to physic coordinates
  73.         half_width          = 0.5 * self.sprite.get_width() / images.TILE_SIZE
  74.         half_height         = 0.5 * self.sprite.get_height() / images.TILE_SIZE
  75.  
  76.         # Physical objects have a rectangular shape, the points correspond to the corners of that shape.
  77.         points              = [[-half_width, -half_height],
  78.                             [-half_width, half_height],
  79.                             [half_width, half_height],
  80.                             [half_width, -half_height]]
  81.         self.points = points
  82.         # Create a body (which is the physical representation of this game object in the physic engine)
  83.         if(movable):
  84.             # Create a movable object with some mass and moments
  85.             # (considering the game is a top view game, with no gravity,
  86.             # the mass is set to the same value for all objects)."""
  87.             mass = 10
  88.             moment = pymunk.moment_for_poly(mass, points)
  89.             self.body         = pymunk.Body(mass, moment)
  90.         else:
  91.             self.body         = pymunk.Body(body_type=pymunk.Body.STATIC) # Create a non movable (static) object
  92.  
  93.         self.body.position  = x, y
  94.         self.body.angle     = math.radians(orientation)       # orientation is provided in degress, but pymunk expects radians.
  95.         self.shape          = pymunk.Poly(self.body, points)
  96.         self.shape.parent = self  # Create a polygon shape using the corner of the rectangle
  97.  
  98.         # Set some value for friction and elasticity, which defines interraction in case of a colision
  99.         self.shape.friction = 0.5
  100.         self.shape.elasticity = 0.1
  101.  
  102.         # Add the object to the physic engine
  103.         if(movable):
  104.             space.add(self.body, self.shape)
  105.         else:
  106.             space.add(self.shape)
  107.  
  108.  
  109.     def screen_position(self):
  110.         """ Converts the body's position in the physics engine to screen coordinates. """
  111.         return physics_to_display(self.body.position)
  112.  
  113.     def screen_orientation(self):
  114.         """ Angles are reversed from the engine to the display. """
  115.         return -math.degrees(self.body.angle)
  116.  
  117.     def update_screen(self, screen):
  118.         super().update_screen(screen)
  119.         # debug draw
  120.         if DEBUG:
  121.             ps = [self.body.position+p for p in self.points]
  122.  
  123.             ps = [physics_to_display(p) for p in ps]
  124.             ps += [ps[0]]
  125.             pygame.draw.lines(screen, pygame.color.THECOLORS["red"], False, ps, 1)
  126.  
  127. def clamp (minval, val, maxval):
  128.     """ Convenient helper function to bound a value to a specific interval. """
  129.     if val < minval: return minval
  130.     if val > maxval: return maxval
  131.     return val
  132.  
  133.  
  134. class Tank(GamePhysicsObject):
  135.     """ Extends GamePhysicsObject and handles aspects which are specific to our tanks. """
  136.  
  137.     # Constant values for the tank, acessed like: Tank.ACCELERATION
  138.     ACCELERATION = 0.4
  139.     NORMAL_MAX_SPEED = 1.0
  140.     FLAG_MAX_SPEED = NORMAL_MAX_SPEED * 0.5
  141.  
  142.     def __init__(self, x, y, orientation, sprite, space):
  143.         super().__init__(x, y, orientation, sprite, space, True)
  144.         # Define variable used to apply motion to the tanks
  145.         self.acceleration         = 0.0
  146.         self.velocity             = 0.0
  147.         self.angular_acceleration = 0.0
  148.         self.angular_velocity     = 0.0
  149.  
  150.         self.flag                 = None                      # This variable is used to access the flag object, if the current tank is carrying the flag
  151.         self.maximum_speed        = Tank.NORMAL_MAX_SPEED     # Impose a maximum speed to the tank
  152.         self.start_position       = pymunk.Vec2d(x, y)        # Define the start position, which is also the position where the tank has to return with the flag
  153.         self.shape.collision_type = 2
  154.  
  155.         self.last_bullet          = 0
  156.         self.playernbr            = 0
  157.         self.score                = 0
  158.         self.starting_position    = None
  159.  
  160.     def accelerate(self):
  161.         """ Call this function to make the tank move forward. """
  162.         self.acceleration = Tank.ACCELERATION
  163.  
  164.  
  165.     def decelerate(self):
  166.         """ Call this function to make the tank move backward. """
  167.         self.acceleration = -Tank.ACCELERATION
  168.  
  169.     #
  170.     def turn_left(self):
  171.         """ Makes the tank turn left (counter clock-wise). """
  172.         self.angular_acceleration = -Tank.ACCELERATION
  173.  
  174.  
  175.     def turn_right(self):
  176.         """ Makes the tank turn right (clock-wise). """
  177.         self.angular_acceleration = Tank.ACCELERATION
  178.  
  179.     def update(self):
  180.         """ A function to update the objects coordinates. Gets called at every tick of the game. """
  181.  
  182.         # Update the velocity of the tank in function of the physic simulation (in case of colision, the physic simulation will change the speed of the tank)
  183.         #if self.last_bullet >= 1:
  184.         #    self.last_bullet -= 1
  185.         if self.last_bullet > 300:
  186.             self.last_bullet = 0
  187.         if self.last_bullet < 300:
  188.             self.last_bullet += 5
  189.  
  190.  
  191.         if(math.fabs(self.velocity) > 0 ):
  192.             self.velocity         *= self.body.velocity.length  / math.fabs(self.velocity)
  193.         if(math.fabs(self.angular_velocity) > 0 ):
  194.             self.angular_velocity *= math.fabs(self.body.angular_velocity / self.angular_velocity)
  195.  
  196.         # Update the velocity in function of the acceleration
  197.         self.velocity         += self.acceleration
  198.         self.angular_velocity += self.angular_acceleration
  199.  
  200.         # Make sure the velocity is not larger than a maximum speed
  201.         self.velocity         = clamp(-self.maximum_speed, self.velocity,         self.maximum_speed)
  202.         self.angular_velocity = clamp(-self.maximum_speed, self.angular_velocity, self.maximum_speed)
  203.  
  204.         # Update the physic velocity
  205.         self.body.velocity = pymunk.Vec2d((0, self.velocity)).rotated(self.body.angle)
  206.         self.body.angular_velocity = self.angular_velocity
  207.  
  208.  
  209.     def stop_moving(self):
  210.         """ Call this function to make the tank stop moving. """
  211.         self.velocity     = 0
  212.         self.acceleration = 0
  213.  
  214.     def stop_turning(self):
  215.         """ Call this function to make the tank stop turning. """
  216.         self.angular_velocity     = 0
  217.         self.angular_acceleration = 0
  218.  
  219.     def post_update(self):
  220.         # If the tank carries the flag, then update the positon of the flag
  221.         if(self.flag != None):
  222.             self.flag.x           = self.body.position[0]
  223.             self.flag.y           = self.body.position[1]
  224.             self.flag.orientation = -math.degrees(self.body.angle)
  225.         # Else ensure that the tank has its normal max speed
  226.         else:
  227.             self.maximum_speed = Tank.NORMAL_MAX_SPEED
  228.  
  229.  
  230.     def try_grab_flag(self, flag):
  231.         """ Call this function to try to grab the flag, if the flag is not on other tank
  232.           and it is close to the current tank, then the current tank will grab the flag.
  233.       """
  234.         # Check that the flag is not on other tank
  235.         if(not flag.is_on_tank):
  236.             # Check if the tank is close to the flag
  237.             flag_pos = pymunk.Vec2d(flag.x, flag.y)
  238.             if((flag_pos - self.body.position).length < 0.5):
  239.                 # Grab the flag !
  240.                 self.flag           = flag
  241.                 self.is_on_tank     = True
  242.                 self.maximum_speed  = Tank.FLAG_MAX_SPEED
  243.  
  244.     def has_won(self):
  245.         """ Check if the current tank has won (if it is has the flag and it is close to its start position). """
  246.         return self.flag != None and (self.start_position - self.body.position).length < 0.2
  247.  
  248.  
  249.     def shoot(self, space):
  250.         """ Call this function to shoot a missile (current implementation does nothing ! you need to implement it yourself) """
  251.         if self.last_bullet >= 300:
  252.             bullet = Bullet(self.body.position[0] - (math.sin(self.body.angle)) * 0.6, self.body.position[1] + (math.cos(self.body.angle)) * 0.6, self.body.angle, images.bullet, space)
  253.             self.last_bullet += 1
  254.             return bullet
  255.         else:
  256.             return None
  257.  
  258.  
  259. class Box(GamePhysicsObject):
  260.     """ This class extends the GamePhysicsObject to handle box objects. """
  261.  
  262.     def __init__(self, x, y, boxmodel, space):
  263.         """ It takes as arguments the coordinate of the starting position of the box (x,y) and the box model (boxmodel). """
  264.         super().__init__(x, y, 0, boxmodel.sprite, space, boxmodel.movable)
  265.         self.boxmodel = boxmodel
  266.         if self.boxmodel.destructable:
  267.             self.shape.collision_type = 3
  268.         if not self.boxmodel.destructable:
  269.             self.shape.collision_type = 4
  270.  
  271.  
  272.  
  273.  
  274.  
  275. class GameVisibleObject(GameObject):
  276.     """ This class extends GameObject for object that are visible on screen but have no physical representation (bases and flag) """
  277.  
  278.     def __init__(self, x, y, sprite):
  279.         """ It takes argument the coordinates (x,y) and the sprite. """
  280.         self.x            = x
  281.         self.y            = y
  282.         self.orientation  = 0
  283.         super().__init__(sprite)
  284.  
  285.     def screen_position(self):
  286.         return physics_to_display(pymunk.Vec2d(self.x, self.y))
  287.  
  288.     def screen_orientation(self):
  289.         return self.orientation
  290.  
  291.  
  292. class Flag(GameVisibleObject):
  293.     """ This class extends GameVisibleObject for representing flags."""
  294.  
  295.     def __init__(self, x, y):
  296.         self.is_on_tank   = False
  297.         super().__init__(x, y,  images.flag)
  298.  
  299. class Bullet(GamePhysicsObject):
  300.     def __init__(self, x, y, orientation, sprite, space):
  301.         super().__init__(x, y, orientation, sprite, space, True)
  302.         self.shape.collision_type = 1
  303.         self.velocity = 4.0
  304.         self.body.velocity = pymunk.Vec2d((0, self.velocity)).rotated(orientation)
  305.  
  306.  
  307. class Explosion(GameObject):
  308.     def __init__(self, x, y, orientation, sprite, space):
  309.         super().__init__(x, y, images.explosion, space)
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.     #Skapa en klass. Skapa object utifrån klassen. Lägg in objektet i listan
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement