preface
Today, we will reconstruct a version of the little dinosaur jump game and share it with you. There is no more nonsense. Let's start happily~
Effect display
development tool
Python version: 3.6 four
Related modules:
pygame module;
And some python built-in modules.
Environment construction
Install Python and add it to the environment variable. pip can install the relevant modules required.
Principle introduction
Here is the implementation principle of the game. First, for the convenience of dragon training, I didn't add the scene effect of night, that is, the game only has the scene of day.
First, we need to initialize the game:
# Game initialization pygame.init() screen = pygame.display.set_mode(cfg.SCREENSIZE) pygame.display.set_caption('T-Rex Rush - Charles Picchu') # Import all sound files sounds = {} for key, value in cfg.AUDIO_PATHS.items(): sounds[key] = pygame.mixer.Sound(value)
Next, let's consider what game elements are in the game:
- Little dinosaur: controlled by the player to avoid obstacles on the road;
- Pavement: the background of the game;
- Cloud: the background of the game;
- Flying Dragon: one of the obstacles on the road, the little dinosaur will die if it meets;
- Cactus: one of the obstacles on the road, the little dinosaur will die if it meets;
- Scoreboard: record the current score and the highest score in history.
Let's define these game element classes in turn. For clouds, roads and cactus, the definition is very simple. We only need to load the corresponding game element pictures:
Then write two class internal methods update and draw.
The two methods are respectively used to move the scene to the left to realize the animation effect of the small dinosaur moving forward and to display the scene in the corresponding position of the game interface.
Specifically, the code implementation is as follows:
'''floor''' class Ground(pygame.sprite.Sprite): def __init__(self, imagepath, position, **kwargs): pygame.sprite.Sprite.__init__(self) # import picture self.image_0 = pygame.image.load(imagepath) self.rect_0 = self.image_0.get_rect() self.rect_0.left, self.rect_0.bottom = position self.image_1 = pygame.image.load(imagepath) self.rect_1 = self.image_1.get_rect() self.rect_1.left, self.rect_1.bottom = self.rect_0.right, self.rect_0.bottom # Define some necessary parameters self.speed = -10 '''Renew floor''' def update(self): self.rect_0.left += self.speed self.rect_1.left += self.speed if self.rect_0.right < 0: self.rect_0.left = self.rect_1.right if self.rect_1.right < 0: self.rect_1.left = self.rect_0.right '''Draw floor to screen''' def draw(self, screen): screen.blit(self.image_0, self.rect_0) screen.blit(self.image_1, self.rect_1) '''cloud''' class Cloud(pygame.sprite.Sprite): def __init__(self, imagepath, position, **kwargs): pygame.sprite.Sprite.__init__(self) # import picture self.image = pygame.image.load(imagepath) self.rect = self.image.get_rect() self.rect.left, self.rect.top = position # Define some necessary parameters self.speed = -1 '''Draw clouds to the screen''' def draw(self, screen): screen.blit(self.image, self.rect) '''Update cloud''' def update(self): self.rect = self.rect.move([self.speed, 0]) if self.rect.right < 0: self.kill() '''cactus''' class Cactus(pygame.sprite.Sprite): def __init__(self, imagepaths, position=(600, 147), sizes=[(40, 40), (40, 40)], **kwargs): pygame.sprite.Sprite.__init__(self) # import picture self.images = [] image = pygame.image.load(imagepaths[0]) for i in range(3): self.images.append(pygame.transform.scale(image.subsurface((i*101, 0), (101, 101)), sizes[0])) image = pygame.image.load(imagepaths[1]) for i in range(3): self.images.append(pygame.transform.scale(image.subsurface((i*68, 0), (68, 70)), sizes[1])) self.image = random.choice(self.images) self.rect = self.image.get_rect() self.rect.left, self.rect.bottom = position self.mask = pygame.mask.from_surface(self.image) # Define some necessary variables self.speed = -10 '''Draw to screen''' def draw(self, screen): screen.blit(self.image, self.rect) '''to update''' def update(self): self.rect = self.rect.move([self.speed, 0]) if self.rect.right < 0: self.kill()
The definition of scoreboard is similar, but it does not need to be moved, but it needs to update the current score in real time:
'''Scoreboard''' class Scoreboard(pygame.sprite.Sprite): def __init__(self, imagepath, position, size=(11, 13), is_highest=False, bg_color=None, **kwargs): pygame.sprite.Sprite.__init__(self) # import picture self.images = [] image = pygame.image.load(imagepath) for i in range(12): self.images.append(pygame.transform.scale(image.subsurface((i*20, 0), (20, 24)), size)) if is_highest: self.image = pygame.Surface((size[0]*8, size[1])) else: self.image = pygame.Surface((size[0]*5, size[1])) self.rect = self.image.get_rect() self.rect.left, self.rect.top = position # Some necessary variables self.is_highest = is_highest self.bg_color = bg_color self.score = '00000' '''Set score''' def set(self, score): self.score = str(score).zfill(5) '''Draw to screen''' def draw(self, screen): self.image.fill(self.bg_color) for idx, digital in enumerate(list(self.score)): digital_image = self.images[int(digital)] if self.is_highest: self.image.blit(digital_image, ((idx+3)*digital_image.get_rect().width, 0)) else: self.image.blit(digital_image, (idx*digital_image.get_rect().width, 0)) if self.is_highest: self.image.blit(self.images[-2], (0, 0)) self.image.blit(self.images[-1], (digital_image.get_rect().width, 0)) screen.blit(self.image, self.rect)
The above code uses is_ The highest variable is used to distinguish whether the scoreboard is used to record the highest score of the game or only the current score. The reason for this distinction is that the highest score of the game is preceded by the HI logo, so it takes up more space:
The definition of flying dragon is a little more complicated, because it not only needs to move to the left, but also needs to make the effect of constantly flapping its wings. Specifically, Feilong has two pictures:
What you need to do is to switch the current flying dragon picture every other period of time to achieve the effect of flying dragon flapping its wings:
'''Flying dragon''' class Ptera(pygame.sprite.Sprite): def __init__(self, imagepath, position, size=(46, 40), **kwargs): pygame.sprite.Sprite.__init__(self) # import picture self.images = [] image = pygame.image.load(imagepath) for i in range(2): self.images.append(pygame.transform.scale(image.subsurface((i*92, 0), (92, 81)), size)) self.image_idx = 0 self.image = self.images[self.image_idx] self.rect = self.image.get_rect() self.rect.left, self.rect.centery = position self.mask = pygame.mask.from_surface(self.image) # Define some necessary variables self.speed = -10 self.refresh_rate = 10 self.refresh_counter = 0 '''Draw to screen''' def draw(self, screen): screen.blit(self.image, self.rect) '''to update''' def update(self): if self.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0 self.image_idx = (self.image_idx + 1) % len(self.images) self.loadImage() self.rect = self.rect.move([self.speed, 0]) if self.rect.right < 0: self.kill() self.refresh_counter += 1 '''Load pictures in the current state''' def loadImage(self): self.image = self.images[self.image_idx] rect = self.image.get_rect() rect.left, rect.top = self.rect.left, self.rect.top self.rect = rect self.mask = pygame.mask.from_surface(self.image)
Finally, we need to define the little dinosaur class, which is the most complex game wizard class. It has three states: bow, jump and ordinary forward. For the bow:
You just need to switch two pictures with your head down to achieve the effect of small dinosaurs running, just like flying dragons flapping their wings.
The same is true for normal states:
For the jumping state, we can model the upward throwing and free fall motion formulas learned in junior high school, so as to calculate the position of the small dinosaur in the vertical direction. Specifically, the code implementation is as follows:
'''Little dinosaur''' class Dinosaur(pygame.sprite.Sprite): def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs): pygame.sprite.Sprite.__init__(self) # Import all pictures self.images = [] image = pygame.image.load(imagepaths[0]) for i in range(5): self.images.append(pygame.transform.scale(image.subsurface((i*88, 0), (88, 95)), size[0])) image = pygame.image.load(imagepaths[1]) for i in range(2): self.images.append(pygame.transform.scale(image.subsurface((i*118, 0), (118, 95)), size[1])) self.image_idx = 0 self.image = self.images[self.image_idx] self.rect = self.image.get_rect() self.rect.left, self.rect.bottom = position self.mask = pygame.mask.from_surface(self.image) # Define some necessary variables self.init_position = position self.refresh_rate = 5 self.refresh_counter = 0 self.speed = 11.5 self.gravity = 0.6 self.is_jumping = False self.is_ducking = False self.is_dead = False self.movement = [0, 0] '''jump''' def jump(self, sounds): if self.is_dead or self.is_jumping: return sounds['jump'].play() self.is_jumping = True self.movement[1] = -1 * self.speed '''Bow your head''' def duck(self): if self.is_jumping or self.is_dead: return self.is_ducking = True '''Don't bow your head''' def unduck(self): self.is_ducking = False '''dead ''' def die(self, sounds): if self.is_dead: return sounds['die'].play() self.is_dead = True '''Draw dinosaurs to the screen''' def draw(self, screen): screen.blit(self.image, self.rect) '''Load pictures in the current state''' def loadImage(self): self.image = self.images[self.image_idx] rect = self.image.get_rect() rect.left, rect.top = self.rect.left, self.rect.top self.rect = rect self.mask = pygame.mask.from_surface(self.image) '''Update little dinosaur''' def update(self): if self.is_dead: self.image_idx = 4 self.loadImage() return if self.is_jumping: self.movement[1] += self.gravity self.image_idx = 0 self.loadImage() self.rect = self.rect.move(self.movement) if self.rect.bottom >= self.init_position[1]: self.rect.bottom = self.init_position[1] self.is_jumping = False elif self.is_ducking: if self.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0 self.image_idx = 5 if self.image_idx == 6 else 6 self.loadImage() else: if self.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0 if self.image_idx == 1: self.image_idx = 2 elif self.image_idx == 2: self.image_idx = 3 else: self.image_idx = 1 self.loadImage() self.refresh_counter += 1
After defining the game wizard class, we can instantiate the TA S:
# Define some necessary elements and variables in the game score = 0 score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(534, 15), bg_color=cfg.BACKGROUND_COLOR) highest_score = highest_score highest_score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(435, 15), bg_color=cfg.BACKGROUND_COLOR, is_highest=True) dino = Dinosaur(cfg.IMAGE_PATHS['dino']) ground = Ground(cfg.IMAGE_PATHS['ground'], position=(0, cfg.SCREENSIZE[1])) cloud_sprites_group = pygame.sprite.Group() cactus_sprites_group = pygame.sprite.Group() ptera_sprites_group = pygame.sprite.Group() add_obstacle_timer = 0 score_timer = 0
Then write the main cycle of the game:
# Game main loop clock = pygame.time.Clock() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE or event.key == pygame.K_UP: dino.jump(sounds) elif event.key == pygame.K_DOWN: dino.duck() elif event.type == pygame.KEYUP and event.key == pygame.K_DOWN: dino.unduck() screen.fill(cfg.BACKGROUND_COLOR) # --Add cloud randomly if len(cloud_sprites_group) < 5 and random.randrange(0, 300) == 10: cloud_sprites_group.add(Cloud(cfg.IMAGE_PATHS['cloud'], position=(cfg.SCREENSIZE[0], random.randrange(30, 75)))) # --Add cactus / flying dragon randomly add_obstacle_timer += 1 if add_obstacle_timer > random.randrange(50, 150): add_obstacle_timer = 0 random_value = random.randrange(0, 10) if random_value >= 5 and random_value <= 7: cactus_sprites_group.add(Cactus(cfg.IMAGE_PATHS['cacti'])) else: position_ys = [cfg.SCREENSIZE[1]*0.82, cfg.SCREENSIZE[1]*0.75, cfg.SCREENSIZE[1]*0.60, cfg.SCREENSIZE[1]*0.20] ptera_sprites_group.add(Ptera(cfg.IMAGE_PATHS['ptera'], position=(600, random.choice(position_ys)))) # --Update game elements dino.update() ground.update() cloud_sprites_group.update() cactus_sprites_group.update() ptera_sprites_group.update() score_timer += 1 if score_timer > (cfg.FPS//12): score_timer = 0 score += 1 score = min(score, 99999) if score > highest_score: highest_score = score if score % 100 == 0: sounds['point'].play() if score % 1000 == 0: ground.speed -= 1 for item in cloud_sprites_group: item.speed -= 1 for item in cactus_sprites_group: item.speed -= 1 for item in ptera_sprites_group: item.speed -= 1 # --Collision detection for item in cactus_sprites_group: if pygame.sprite.collide_mask(dino, item): dino.die(sounds) for item in ptera_sprites_group: if pygame.sprite.collide_mask(dino, item): dino.die(sounds) # --Draw game elements to the screen dino.draw(screen) ground.draw(screen) cloud_sprites_group.draw(screen) cactus_sprites_group.draw(screen) ptera_sprites_group.draw(screen) score_board.set(score) highest_score_board.set(highest_score) score_board.draw(screen) highest_score_board.draw(screen) # --Update screen pygame.display.update() clock.tick(cfg.FPS) # --Is the game over if dino.is_dead: break
The logic of the main cycle of the game is very simple, that is, we need to check the player's operation for each game screen. If the player presses the space bar or ↑ key, the little dinosaur jumps. If the player presses the ↓ key, the little dinosaur lowers its head, otherwise the little dinosaur rushes forward normally.
Then in the game, we randomly generate game scenes and obstacles such as clouds, flying dragons and cactus, and move to the left at the same speed with the road, so as to realize the visual effect of the little dinosaur moving to the right. In the process of moving, we need to detect the collision between the small dinosaur and the cactus, the small dinosaur and the flying dragon. When the small dinosaur encounters these obstacles, the small dinosaur will die, and the game of this bureau will end.
Note that we should use collide_mask function for more accurate collision detection, rather than the previous collapse_ Rect function:
That is, when the minimum circumscribed rectangles of two targets overlap, collapse_ Rect will judge that the two targets collide, which is obviously unreasonable and will bring poor game experience to players.
In addition, when the score increases by 1000 points, we will increase the speed of the scene and obstacles moving to the left (that is, increase the speed of the little dinosaur moving to the right) as in the original game.
Finally, bind all the current game elements to the screen and update the current screen.
This is the end of the article. Thank you for watching, Python 24 games series , the next article will share the Python Network Security Series
In order to thank readers, I would like to share some of my recent collection of programming dry goods with you and give back to every reader. I hope I can help you.
Dry goods mainly include:
① More than 2000 Python e-books (both mainstream and classic books should be available)
② Python standard library materials (the most complete Chinese version)
③ Project source code (forty or fifty interesting and classic hand training projects and source code)
④ Videos on basic introduction to Python, crawler, web development and big data analysis (suitable for Xiaobai)
⑤ Python learning roadmap (bid farewell to non stream learning)
⑥ Two days of Python crawler training camp live rights
All done ~ get the complete source code by private letter..
Python implementation of remake flappybird games
Python implementation of upgraded tank war games
Python implementation of minesweeping games
Python implementation of bomber games
Python implementation of classic bean eating games
Python real dinosaur jump games
Python implementation of simple version of aircraft war games
Tetris games implemented in Python
Python implements "Bunny and Bun" game
Python implementation of eight tone symbol games
Python implements the classic 90 tank war
Python implementation of fruit and gold coin games
Python implementation of table tennis games
Python implementation of brick games