4.5 - Game Class

4.5 Game Class

Init Method

We can run App’s init method. We should also set a constant NUM_TARGETS to 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"))

Create Objects Method

This should run at the end of the init function. 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[0] / 2 - self.tank.size[0], # move to middle x self.size[1] - self.tank.size[1], # 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[0] - target.size[0] ), # random x random.randint( 0, self.size[1] - target.size[1] ), # random y ) ) # bullets (none because no shots fired) self.bullets = [] # score text self.font = pygame.font.SysFont(pygame.font.get_default_font(), 32)

Move Objects Method

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()

Update Display Method

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)

Check Collisions Method

This method should check for collisions between bullets and targets and between the tank and targets. So, we use the pre-built check_collision method.ch
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[0] - a.size[0]), random.randint(0, self.size[1] - a.size[1]), ) ) self.targets.append(a)

Check Events Method

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[1])) ) # move the bullet to the front of the tank # math stuff to calculate trajectory mouse_pos = pygame.mouse.get_pos() h = mouse_pos[1] - bul.rect.center[1] w = mouse_pos[0] - bul.rect.center[0] hyp = math.sqrt(h ** 2 + w ** 2) vertical_speed = ( BULLETSPEED[1] * (h / hyp) if hyp != 0 else BULLETSPEED[1] * h ) horizontal_speed = ( BULLETSPEED[0] * (w / hyp) if hyp != 0 else BULLETSPEED[0] * 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)

Previous Section

4.4 - App Class
Copyright © 2021 Code 4 Tomorrow. All rights reserved. The code in this course is licensed under the MIT License. If you would like to use content from any of our courses, you must obtain our explicit written permission and provide credit. Please contact classes@code4tomorrow.org for inquiries.