4.5 Game ClassInit MethodCreate Objects MethodMove Objects MethodUpdate Display MethodCheck Collisions MethodCheck Events Method
We can run
initmethod. We should also set a constant
NUM_TARGETSto the number of targets that we want at one time in our game. Lastly, we need to set the player’s score to 0.
def __init__(self): # this can be changed, it's the number of targets allowed at a time. # we initialize this before super().__init__ because super().__init__ calls # create_objects, which utilizes self.NUM_TARGETS self.NUM_TARGETS = 3 super().__init__(title="Tanks") self.playerscore = 0 # the player's score # sets the display icon to the TankIcon.png provided pygame.display.set_icon(pygame.image.load("./TankIcon.png"))
This should run at the end of the
initfunction. This will initialize the objects that we will need for the game. Since we already have objects, this is pretty simple.
def create_objects(self): """ This creates the initial objects seen when the game first starts up. """ # tank self.tank = Tank(speed=TANKSPEED) self.tank.moveto( ( self.size / 2 - self.tank.size, # move to middle x self.size - self.tank.size, # move to bottom y ) ) # targets # create targets self.targets = [Target(speed=[0, 0]) for i in range(self.NUM_TARGETS)] # move each target to a random position for target in self.targets: target.moveto( ( random.randint( 0, self.size - target.size ), # random x random.randint( 0, self.size - target.size ), # random y ) ) # bullets (none because no shots fired) self.bullets =  # score text self.font = pygame.font.SysFont(pygame.font.get_default_font(), 32)
This method is pretty easy since all we have to do is use the move methods that we built.
def move_objects(self): """ This method moves the objects within the game. If a bullet is outside of the screen, it is not moved and is unreferenced. """ self.tank.move() self.bullets = [ bullet for bullet in self.bullets if bullet.check_out_of_screen(self.size) is False ] for bullet in self.bullets: bullet.move()
For this method, we just need to fill the screen with
SANDBROWN(to clear the past screen), use our pre-built draw methods, and then draw the score text onto the screen.
def update_display(self): self.screen.fill(SANDBROWN) # tank self.tank.draw(self.screen, SANDBROWN) # targets for target in self.targets: target.draw(self.screen, BLACK) # bullets for bullet in self.bullets: bullet.draw(self.screen, BLACK) # score text font_img = self.font.render( "Score: %s" % str(self.playerscore), True, BLACK ) font_rect = font_img.get_rect() pygame.draw.rect(self.screen, SANDBROWN, font_rect, 1) self.screen.blit(font_img, font_rect)
This method should check for collisions between bullets and targets and between the tank and targets. So, we use the pre-built
def check_collisions(self): """ This checks whether any of the objects within the game have collided with each other. Specifically, we are looking for collisions between bullets and targets or the tank and targets """ deletions = 0 # number of targets deleted num_bullets = len(self.bullets) # check bullet-target collisions for i in range(num_bullets): for target in self.targets: # if the bullet collided with the target if self.bullets[i - deletions].check_collision(target) is True: # pop both the bullet and target so that they will be # effectively deleted self.bullets.pop(i - deletions) self.targets.pop(self.targets.index(target)) # give points for hitting the target self.playerscore += 20 deletions += 1 break # stop the current iteration since the target and # bullet are popped, so referencing them would error. # check tank-target collisions for target in self.targets: if self.tank.check_collision(target) is True: self.targets.pop(self.targets.index(target)) deletions += 1 self.playerscore += 10 # only 10 for running over targets lol # create a new target for every deleted target for i in range(deletions): a = Target(speed=[0, 0]) a.moveto( ( random.randint(0, self.size - a.size), random.randint(0, self.size - a.size), ) ) self.targets.append(a)
This is probably the most complex method since we want the tank to be moved if keys are pressed and bullets to be created if the mouse is clicked.
def check_events(self, event): """ We imported all from pygame.locals, so that means that we can check KEYDOWN and KEYUP and individual keys such as K_w (w key), K_a (a key), etc. """ # change the path of the tank if w, a, s, or d was pressed if event.type == KEYDOWN: if event.key == K_w: self.tank.set_path("up") if event.key == K_s: self.tank.set_path("down") if event.key == K_a: self.tank.set_path("left") if event.key == K_d: self.tank.set_path("right") if event.type == KEYUP: if event.key == K_w: self.tank.unset_path("up") if event.key == K_s: self.tank.unset_path("down") if event.key == K_a: self.tank.unset_path("left") if event.key == K_d: self.tank.unset_path("right") self.tank.set_speed() # create bullets if mouse button was pressed if event.type == MOUSEBUTTONDOWN: bul = Bullet(speed=BULLETSPEED) bul.moveto( (self.tank.rect.centerx, (self.tank.rect.top - bul.size)) ) # move the bullet to the front of the tank # math stuff to calculate trajectory mouse_pos = pygame.mouse.get_pos() h = mouse_pos - bul.rect.center w = mouse_pos - bul.rect.center hyp = math.sqrt(h ** 2 + w ** 2) vertical_speed = ( BULLETSPEED * (h / hyp) if hyp != 0 else BULLETSPEED * h ) horizontal_speed = ( BULLETSPEED * (w / hyp) if hyp != 0 else BULLETSPEED * w ) # set the bullet's speed and add it to self.bullets (for # future collision checking and displaying) bul.set_speed((horizontal_speed, vertical_speed)) self.bullets.append(bul)