preface
From the previous nine articles, hoppers bunny has been written, and this section takes it one step further and adds a cloud background.
Add cloud background
The general steps for adding a cloud background are as follows.
- 1. Write the cloud class
- 2. Load the cloud image
- 3. Randomly generated clouds
- 4. Clouds move in sync
Step by step to write, the first is to create the cloud class, the code is as follows.
# sprites.py
class Cloud(pg.sprite.Sprite):
def __init__(self, game):
self._layer = CLOUD_LAYER
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = random.choice(self.game.cloud_images)
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
# Random location
scale = random.randrange(50.101) / 100
self.image = pg.transform.scale(self.image, (int(self.rect.width * scale),
int(self.rect.height * scale)))
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(- 500..- 50)
def update(self):
# Clouds are eliminated when they are twice as high
if self.rect.top > HEIGHT * 2:
self.kill()
Copy the code
The code content is very similar to the previous content and will not be analyzed in detail.
But if you look closely, you’ll see that the Cloud class’s __init__() method creates self._layer and adds it to the appropriate groups as follows.
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
Copy the code
This is an optimization point, which will be discussed later.
Once you’ve built the Cloud class, all you need to do is load images, generate randomly, and move synchronously.
# main.py/Game
def load_data(self): # load data
#... Omit irrelevant code
# Load cloud image
self.cloud_images = []
for i in range(1.4):
self.cloud_images.append(pg.image.load(os.path.join(img_dir, 'cloud{}.png'.format(i))).convert())
def new(self):
self.score = 0
#... Omit irrelevant code
# Create clouds
for i in range(8):
c = Cloud(self)
c.rect.y += 500
self.run()
def update(self):
# when the player reaches 1/4 of the game frame (note that the head of the game frame is 0, the bottom is the length of the game frame, and the top part of the game frame is reached)
if self.player.rect.top <= HEIGHT / 4:
# Player position movement (move down)
self.player.pos.y += max(abs(self.player.vel.y), 2)
# Randomly generate new clouds
if random.randrange(100) < 10:
Cloud(self)
# Clouds move in sync
for cloud in self.clouds:
cloud.rect.y += max(abs(self.player.vel.y / 2), 2)
# Enemies move down in sync
for mob in self.mobs:
mob.rect.y += max(abs(self.player.vel.y), 2)
# When the platform is outside the game frame, log it out to avoid resource waste
for plat in self.platforms:
# Platform movement position (move down, move the same distance as the player, so that the player can still stand on the original platform)
plat.rect.y += max(abs(self.player.vel.y), 2)
if plat.rect.top >= HEIGHT:
plat.kill()
# Score increase - Platform destroy, score add
self.score += 10
Copy the code
Woo ~, done. If in doubt, pull down the Github code and look at it.
To optimize the
Now that we’ve added the cloud class, let’s do some optimizations.
First, the optimization of collision detection, if you look carefully, you will find that the player object and the object of ontology has not come into contact with the enemy, triggering the collision detection, the game is over, the causes of this phenomenon is that the players, the enemy, any element of the game is a corresponds to the size of the rectangle. The default form of collision detection is to detect these two squares, in which case the two elements themselves may not touch, but the corresponding squares do, so collision detection is triggered.
To avoid this, use PyGame’s mask mechanism to create masks for both Player and Mob.
# sprites.py
class Player(pg.sprite.Sprite):
def animate(self):
#... Omit irrelevant code
self.mask = pg.mask.from_surface(self.image) Create a mask
class Mob(pg.sprite.Sprite):
def update(self):
#... Omit irrelevant code
self.rect = self.image.get_rect()
self.mask = pg.mask.from_surface(self.image) Create a mask
self.rect.center = center
#... Omit irrelevant code
Copy the code
The pyGame.sprite. Collide_mask callback will do
def update(self):
#... Omit irrelevant code
# Collision Detection - If you hit an enemy, the game ends
mob_hits = pg.sprite.spritecollide(self.player, self.mobs, False, pg.sprite.collide_mask)
if mob_hits:
self.playing = False
Copy the code
In addition, there is another problem that needs to be optimized, which is the layer relationship of elements. After adding cloud objects, the problem of layer relationship becomes obvious. As the background of cloud, it will block player objects, enemy objects, platform objects, etc., which is not reasonable.
Start by defining the layers on which the different elements will appear.
# settings.py
# Different elements in different layers
PLAYER_LAYER = 2 # players
PLATFORM_LAYER = 1 # platform
POW_LAYER = 1 # props
MOB_LAYER = 2 # the enemy
CLOUD_LAYER = 0 # cloud
Copy the code
Then add layer logic for each of the different element objects
#Sprite.py
class Player(pg.sprite.Sprite):
def __init__(self, game):
self._layer = PLAYER_LAYER # Corresponding layer
self.groups = game.all_sprites # group
pg.sprite.Sprite.__init__(self, self.groups) Add, instantiate
#... Omit irrelevant code
class Platform(pg.sprite.Sprite):
def __init__(self, game, x, y):
self._layer = PLATFORM_LAYER # Corresponding layer
self.groups = game.all_sprites, game.platforms # group
pg.sprite.Sprite.__init__(self, self.groups) Add, instantiate
#... Omit irrelevant code
class Pow(pg.sprite.Sprite):
def __init__(self, game, plat):
self._layer = POW_LAYER
self.groups = game.all_sprites, game.powerups
pg.sprite.Sprite.__init__(self, self.groups)
#... Omit irrelevant code
class Mob(pg.sprite.Sprite):
def __init__(self, game):
self._layer = MOB_LAYER
self.groups = game.all_sprites, game.mobs
pg.sprite.Sprite.__init__(self, self.groups)
#... Omit irrelevant code
class Cloud(pg.sprite.Sprite):
def __init__(self, game):
self._layer = CLOUD_LAYER
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
#... Omit irrelevant code
Copy the code
After optimization, and then modify a new Game class () method, using pygame. Sprite. LayeredUpdates () to instantiate all_sprites object.
LayeredUpdates is a set of sprites that can work with layers and draw elements in sequence.
# main.py
class Game:
def new(self):
self.score = 0
# self.all_sprites = pg.sprite.Group()
# Add layers to avoid overlapping elements (e.g. background cloud blocking platform and player)
self.all_sprites = pg.sprite.LayeredUpdates()
self.platforms = pg.sprite.Group()
self.powerups = pg.sprite.Group() # Speed-jump item
self.mobs = pg.sprite.Group() # Enemy objects
self.clouds = pg.sprite.Group() # cloud Object
self.player = Player(self)
self.all_sprites.add(self.player)
for plat in PLATFORM_LIST:
p = Platform(self, *plat)
# self.all_sprites.add(p)
# self.platforms.add(p)
self.mob_timer = 0
# Background music for the game
pg.mixer.music.load(os.path.join(self.snd_dir, 'Happy Tune.ogg'))
# Create clouds
for i in range(8):
c = Cloud(self)
c.rect.y += 500
self.run()
Copy the code
The net effect is as follows.
The tail
This is the end of Hoppy Bunny and the end of the Pygame series of articles.
Github: github.com/ayuLiao/jum…
Pygame also has a lot of interesting features that aren’t present in Bungee Jumping.
As mentioned in the first article of this series, these articles are just study notes, along with study notes for the following two games: masturbation and ZOMBIE fighting RPG.
If you are interested, please tell me so that I will be motivated to continue sharing. I think I will share algorithms and computer basics in the form of comics in the future according to my personal plan. I hope you like it.
Finally, again, the learning is from: kidscancode.org/, the game is not original…
If the article is helpful to you, please click “watching” to give the author a little encouragement, thanks to Horn.