preface

Today’s Python implementation is a bomb man small game, without further ado, let’s happily start ~

Results show

The development tools

Python version: 3.6.4

Related modules:

Pygame module;

And some modules that come with Python.

Environment set up

Install Python and add it to the environment variables. PIP installs the required related modules.

Introduction of the principle

Rules of the game:

The player controls the action of zelda(green) by pressing ↑↓←→. When the player presses the space bar, the bomb can be placed in the current position. The rest of the characters (DK and Batman) do random actions controlled by computers. [Fixed] All characters lose health when they are burned by the flame of a bomb (including their own bombs). All characters regain a certain amount of health when they eat fruit. In addition, the wall prevents the flames from spreading further. The front row is 762, the middle row is 459, and the back row is 510. She will arrange to learn the three groups of letters together.

When zelda reaches 0 health, the game fails. When the computer side of all characters health is 0, the game victory, into the next level.

Step by step:

First, let’s clarify what sprites are included in the game:

  • The bomb class
  • Character class
  • Wall type
  • Background class
  • Fruit class

The wall and background classes are well defined, so you can import the image and bind it to the specified location:

Def __init__(self, imagepath, coordinate, blocksize, **kwargs): def __init__(self, imagepath, coordinate, blocksize, **kwargs): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(imagepath) self.image = pygame.transform.scale(self.image, (blocksize, blocksize)) self.rect = self.image.get_rect() self.rect.left, self.rect.top = coordinate[0] * blocksize, Coordinate [1] * blocksize self. Coordinate = coordinate self. Blocksize = blocksize "def draw(self, screen): Screen.blit (self.image, self.rect) return True "" class Background(Pygame.sprite.sprite): def __init__(self, imagepath, coordinate, blocksize, **kwargs): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(imagepath) self.image = pygame.transform.scale(self.image, (blocksize, blocksize)) self.rect = self.image.get_rect() self.rect.left, self.rect.top = coordinate[0] * blocksize, Coordinate [1] * blocksize self. Coordinate = coordinate self. Blocksize = blocksize "def draw(self, screen): screen.blit(self.image, self.rect) return TrueCopy the code

The definition of the fruit class is similar, but different fruits can help a character regain different amounts of health:

Class Fruit(pygame.sprite): def __init__(self, imagepath, coordinate, blocksize, **kwargs): pygame.sprite.Sprite.__init__(self) self.kind = imagepath.split('/')[-1].split('.')[0] if self.kind == 'banana': self.value = 5 elif self.kind == 'cherry': self.value = 10 else: raise ValueError('Unknow fruit <%s>... ' % self.kind) self.image = pygame.image.load(imagepath) self.image = pygame.transform.scale(self.image, (blocksize, blocksize)) self.rect = self.image.get_rect() self.rect.left, self.rect.top = coordinate[0] * blocksize, Coordinate [1] * blocksize self. Coordinate = coordinate self. Blocksize = blocksize "def draw(self, screen): screen.blit(self.image, self.rect) return TrueCopy the code

Bomb classes and character classes are a little more complicated. Character classes need to move up, down, left, and right according to the instructions of the player or computer, and can also generate bombs in their position and restore a certain number of health after eating fruit:

Class Hero(PyGame.sprite.sprite): def __init__(self, imagepaths, coordinate, blocksize, map_parser, **kwargs): pygame.sprite.Sprite.__init__(self) self.imagepaths = imagepaths self.image = pygame.image.load(imagepaths[-1]) self.image = pygame.transform.scale(self.image, (blocksize, blocksize)) self.rect = self.image.get_rect() self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksize self.coordinate = coordinate self.blocksize = blocksize self.map_parser = map_parser Self.hero_name = kwargs.get('hero_name') # Health self.health_value = 50 # Bomb cooldown self.bomb_cooling_time = 5000 Cooling_time = 100 self.randommove_cooling_count = 0 Def move(self, direction): self.__updateImage(direction) if direction == 'left': if self.coordinate[0]-1 < 0 or self.map_parser.getElemByCoordinate([self.coordinate[0]-1, self.coordinate[1]]) in ['w', 'x', 'z']: return False self.coordinate[0] = self.coordinate[0] - 1 elif direction == 'right': if self.coordinate[0]+1 >= self.map_parser.width or self.map_parser.getElemByCoordinate([self.coordinate[0]+1, self.coordinate[1]]) in ['w', 'x', 'z']: return False self.coordinate[0] = self.coordinate[0] + 1 elif direction == 'up': if self.coordinate[1]-1 < 0 or self.map_parser.getElemByCoordinate([self.coordinate[0], self.coordinate[1]-1]) in ['w', 'x', 'z']: return False self.coordinate[1] = self.coordinate[1] - 1 elif direction == 'down': if self.coordinate[1]+1 >= self.map_parser.height or self.map_parser.getElemByCoordinate([self.coordinate[0], self.coordinate[1]+1]) in ['w', 'x', 'z']: return False self.coordinate[1] = self.coordinate[1] + 1 else: raise ValueError('Unknow direction <%s>... ' % direction) self.rect.left, self.rect.top = self.coordinate[0] * self.blocksize, Self. Coordinate [1] * self. Blocksize return True "" def randomAction(self, dt): If self. Randommove_cooling_count > 0: self.randommove_cooling_count -= dt action = random.choice(['left', 'left', 'right', 'right', 'up', 'up', 'down', 'down', 'dropbomb']) flag = False if action in ['left', 'right', 'up', 'down']: if self.randommove_cooling_count <= 0: flag = True self.move(action) self.randommove_cooling_count = self.randommove_cooling_time elif action in ['dropbomb']: if self.bomb_cooling_count <= 0: Self. Bomb_cooling_count = self. Bomb_cooling_time return action, "def generateBomb" "def generateBomb(self, imagepath, digitalcolor, explode_imagepath): return Bomb(imagepath=imagepath, coordinate=copy.deepcopy(self.coordinate), blocksize=self.blocksize, Def draw(self, screen, dt): def draw(self, screen, dt): # cooldown countdown if self.bomb_cooling_count > 0: Self.bomb_cooling_count -= dt screen.blit(self.image, self.rect) return True "" def eatFruit(self, fruit_sprite_group): eaten_fruit = pygame.sprite.spritecollide(self, fruit_sprite_group, True, None) for fruit in eaten_fruit: Self.health_value += fruit.value "" def __updateImage(self, direction): directions = ['left', 'right', 'up', 'down'] idx = directions.index(direction) self.image = pygame.image.load(self.imagepaths[idx]) self.image = pygame.transform.scale(self.image, (self.blocksize, self.blocksize))Copy the code

Bomb class need to have the countdown prompt functions, as well as after the end of the countdown to produce flame effects in the bomb blast radius (poor, estimate a value of 1 cent effects T_T, everybody excuse me), so students want to learn, it is necessary to listen to the teacher’s class, get the python welfare, want to learn the students can go to the dream of the teacher, wai xin (in Chinese) : in the front row is: 762, the middle row is: 459, the back row is: 510, put the above three groups of letters together in order, she will arrange to learn.

Class Bomb(Pygame.sprite.sprite): def __init__(self, imagepath, coordinate, blocksize, digitalcolor, explode_imagepath, **kwargs): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(imagepath) self.image = pygame.transform.scale(self.image, (blocksize, Blocksize)) self.rect = self.image.get_rect() # pixel position self.rect.left, self.rect.top = coordinate[0] * blocksize, Coordinate [1] * blocksize # Coordinate (element block is unit length) self.coordinate = coordinate self.blocksize = blocksize # Countdown to explosion self.explode_millisecond = 6000 * 1 - 1 self.explode_second = int(self.explode_millisecond / 1000) self.start_explode = Self.harm_value = 1 # Whether the bomb still exists self.is_being = True self.font = Pygame.font.SysFont('Consolas', 20) self. digitalColor = digitalcolor "" def draw(self, screen, dt) map_parser): if not self.start_explode: # self.explode_millisecond -= dt self.explode_second = int(self.explode_millisecond / 1000) if self.explode_millisecond < 0: self.start_explode = True screen.blit(self.image, self.rect) text = self.font.render(str(self.explode_second), True, self.digitalcolor) rect = text.get_rect(center=(self.rect.centerx-5, self.rect.centery+5)) screen.blit(text, Self. exploding_count -= dt if self.exploding_count > 0: return self.__explode(screen, map_parser) else: Self. is_being = False return False "" def __explode(self, screen, map_parser): explode_area = self.__calcExplodeArea(map_parser.instances_list) for each in explode_area: image = pygame.image.load(self.explode_imagepath) image = pygame.transform.scale(image, (self.blocksize, self.blocksize)) rect = image.get_rect() rect.left, rect.top = each[0] * self.blocksize, Each [1] * self.blocksize screen.blit(image, rect) return explode_area "" def __calcExplodeArea(self, instances_list): Explode_area = [] # The calculation rule is that the wall can prevent explosion diffusion and the explosion range is only within the scope of the game map for ymin in range(self. Coordinate [1], self. Coordinate [1]-5, -1): if ymin < 0 or instances_list[ymin][self.coordinate[0]] in ['w', 'x', 'z']: break explode_area.append([self.coordinate[0], ymin]) for ymax in range(self.coordinate[1]+1, self.coordinate[1]+5): if ymax >= len(instances_list) or instances_list[ymax][self.coordinate[0]] in ['w', 'x', 'z']: break explode_area.append([self.coordinate[0], ymax]) for xmin in range(self.coordinate[0], self.coordinate[0]-5, -1): if xmin < 0 or instances_list[self.coordinate[1]][xmin] in ['w', 'x', 'z']: break explode_area.append([xmin, self.coordinate[1]]) for xmax in range(self.coordinate[0]+1, self.coordinate[0]+5): if xmax >= len(instances_list[0]) or instances_list[self.coordinate[1]][xmax] in ['w', 'x', 'z']: break explode_area.append([xmax, self.coordinate[1]]) return explode_areaCopy the code

Since the bomb and character classes are bound to the game screen each frame, some of the countdown operations are written into the draw function together, although it would be better to write a new function to do this, so the code structure looks cleaner.

Next, we design our game map in a.map file:

Then use a map parser class to parse the.map file, so that every time you switch levels, you only need to import a new.map file, which also makes it easy to expand later:

Class mapParser(): def __init__(self, mapFilepath, bg_paths, wall_paths, blocksize, **kwargs): self.instances_list = self.__parse(mapfilepath) self.bg_paths = bg_paths self.wall_paths = wall_paths self.blocksize = blocksize self.height = len(self.instances_list) self.width = len(self.instances_list[0]) self.screen_size = (blocksize * self.width, blocksize * self.height) "def draw(self, screen): for j in range(self. Height): for i in range(self.width): instance = self.instances_list[j][i] if instance == 'w': elem = Wall(self.wall_paths[0], [i, j], self.blocksize) elif instance == 'x': elem = Wall(self.wall_paths[1], [i, j], self.blocksize) elif instance == 'z': elem = Wall(self.wall_paths[2], [i, j], self.blocksize) elif instance == '0': elem = Background(self.bg_paths[0], [i, j], self.blocksize) elif instance == '1': elem = Background(self.bg_paths[1], [i, j], self.blocksize) elif instance == '2': elem = Background(self.bg_paths[2], [i, j], self.blocksize) else: raise ValueError('instance parse error in mapParser.draw... Def randomGetSpace(self, used_spaces=None): while True: return () {return () {return () {return (); i = random.randint(0, self.width-1) j = random.randint(0, self.height-1) coordinate = [i, j] if used_spaces and coordinate in used_spaces: continue instance = self.instances_list[j][i] if instance in ['0', '1', '2']: Def getElemByCoordinate(self, coordinate): Return self.instances_list[coordinate[1]][coordinate[0]] "" def __parse(self, mapFilepath): instances_list = [] with open(mapfilepath) as f: for line in f.readlines(): instances_line_list = [] for c in line: if c in ['w', 'x', 'z', '0', '1', '2']: instances_line_list.append(c) instances_list.append(instances_line_list) return instances_listCopy the code

So if you want to learn Python, you should listen to the teacher’s lecture and receive python benefits. If you want to learn Python, you can go to Mengya’s Weixin (same pronunciation) : The front row is 762, the middle row is 459, and the back row is: 510, just put these three groups of letters together in the right order. She’ll arrange the study.

Def main(CFG): Init () PyGame.mixer.music.load (cfg.bgmpath) PyGame.mixer.music.play (-1, 0.0) Screen = Pygame.display.set_mode (cfg.screensize) Pygame.display.set_caption ('Bomber Man - 🛰️: Font = pygame.font.SysFont('Consolas', 'Consolas') 15) for gamemap_path in cfg.GAMEMAPPATHS: Map_parser = mapParser(gamemap_path, bg_paths= CFG.BACKGROUNDPATHS, wall_paths= CFG. Blocksize = cfg.blocksize) # - Fruit_sprite_group = pygame.sprite.group () used_spaces = [] for I in range(5): coordinate = map_parser.randomGetSpace(used_spaces) used_spaces.append(coordinate) fruit_sprite_group.add(Fruit(random.choice(cfg.FRUITPATHS), coordinate=coordinate, # - Hero coordinate = map_parser.randomgetSpace (used_spaces) used_spaces.append(coordinate) ourhero = Hero(imagepaths=cfg.HEROZELDAPATHS, coordinate=coordinate, blocksize=cfg.BLOCKSIZE, map_parser=map_parser, Hero_name ='ZELDA') # - computer Hero aihero_sprite_group = Pygame.sprite.group () coordinate = map_parser.randomGetSpace(used_spaces) aihero_sprite_group.add(Hero(imagepaths=cfg.HEROBATMANPATHS, coordinate=coordinate, blocksize=cfg.BLOCKSIZE, map_parser=map_parser, hero_name='BATMAN')) used_spaces.append(coordinate) coordinate = map_parser.randomGetSpace(used_spaces) aihero_sprite_group.add(Hero(imagepaths=cfg.HERODKPATHS, coordinate=coordinate, blocksize=cfg.BLOCKSIZE, map_parser=map_parser, Hero_name ='DK')) used_spaces.append(coordinate) # - Bomb bomb bomb_sprite_group = Pygame.sprite.group () # - Flag used to determine victory or failure of the game Is_win_flag = False # - Main loop screen = pygame.display.set_mode(map_parser.screen_size) clock = pygame.time.clock () while True: dt = clock.tick(cfg.FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: Pygame.quit () sys.exit(-1) # --↑↓←→ Key control up and down, left and right, space bar drop bomb elif Event. type == PyGame.keyDown: if event.key == PyGame.k_up: ourhero.move('up') elif event.key == pygame.K_DOWN: ourhero.move('down') elif event.key == pygame.K_LEFT: ourhero.move('left') elif event.key == pygame.K_RIGHT: ourhero.move('right') elif event.key == pygame.K_SPACE: if ourhero.bomb_cooling_count <= 0: bomb_sprite_group.add(ourhero.generateBomb(imagepath=cfg.BOMBPATH, digitalcolor=cfg.YELLOW, Fill (cfg.white) # -- Hero random action for Hero in aihero_sprite_group: action, flag = hero.randomAction(dt) if flag and action == 'dropbomb': bomb_sprite_group.add(hero.generateBomb(imagepath=cfg.BOMBPATH, digitalcolor=cfg.YELLOW, # explode_imagepath= cfg.firePath) # Fruit_sprite_group for hero in aihero_sprite_group: Map_parser. Draw (screen) for bomb in bomb_sprite_group: if not bomb.is_being: bomb_sprite_group.remove(bomb) explode_area = bomb.draw(screen, dt, map_parser) if explode_area: # -- Hero health in the flame area will continue to decrease. ourhero.health_value -= bomb.harm_value for hero in aihero_sprite_group: if hero.coordinate in explode_area: hero.health_value -= bomb.harm_value fruit_sprite_group.draw(screen) for hero in aihero_sprite_group: Hero.draw (screen, dt) ourhero.draw(screen, dt) ourhero.draw(screen, dt) # text=ourhero.hero_name+'(our):'+str(ourhero.health_value), color=cfg.YELLOW, position=[5, 5]) for hero in aihero_sprite_group: pos_x, pos_y = pos_x+15, 5 pos_x = showText(screen, font, text=hero.hero_name+'(ai):'+str(hero.health_value), Color = CFG.YELLOW, position=[pos_x, pos_y]) # if ourhero.health_value <= 0: is_win_flag = False break for hero in aihero_sprite_group: if hero.health_value <= 0: aihero_sprite_group.remove(hero) if len(aihero_sprite_group) == 0: is_win_flag = True break pygame.display.update() clock.tick(cfg.FPS) if is_win_flag: Interface(screen, cfg, mode='game_switch') else: break Interface(screen, cfg, mode='game_end')Copy the code

That’s the end of this article. Thank you for watching. In my next article, I shared maze games

To thank you readers, I’d like to share some of my recent programming favorites to give back to each and every one of you in the hope that they can help you.

Dry goods mainly include:

① Over 2000 Python ebooks (both mainstream and classic books should be available)

②Python Standard Library (Most Complete Chinese version)

③ project source code (forty or fifty interesting and classic practice projects and source code)

④Python basic introduction, crawler, Web development, big data analysis video (suitable for small white learning)

⑤ A Roadmap for Learning Python

⑥ Two days of Python crawler boot camp live access

All done~ see personal profile or private letter for complete source code.

If you do meet a good coworker, you’ll be lucky. Come on!

Include Python, PythonWeb, crawler, data analysis and other Python skills, as well as artificial intelligence, big data, data mining, automated office learning methods. Build from zero to the project development hands-on combat all-round analysis!