赞
踩
今天我们来看看如何使用Pygame框架制作一个简单的跑酷游戏。这个游戏包含了基本的游戏元素,如玩家角色、障碍物、背景、音效等,可以作为入门Pygame游戏开发的一个不错的示例。
这是一个简单的横版跑酷游戏,玩家控制一个忍者角色,通过跳跃来躲避迎面而来的各种障碍物(汽车、飞机、外星人等)。游戏有三个状态:准备、游戏中和结束。
主要的游戏元素包括:
玩家角色(忍者)
障碍物(汽车、飞机等)
滚动背景
音效和背景音乐
计分系统
游戏UI(开始、结束界面等)
游戏的主要代码结构如下:
class AudioManage: # 音频管理
class BaseSprite: # 基础精灵类
class EnemySprite: # 敌人精灵
class EnemyManage: # 敌人管理
class PlayerSprite: # 玩家精灵
class PlayerManage: # 玩家管理
class BGSprite: # 背景精灵
class BGManage: # 背景管理
class UISprite: # UI精灵
class UIManage: # UI管理
class GameManage: # 游戏主管理类
1. 玩家控制
玩家通过上键控制忍者跳跃:
- def is_jump(self):
- if self.jump_count > 0:
- AudioManage().set_sound_music(5)
- self.jump_count -= 1
- self.velocity_y = -12
- self.jump()
2. 障碍物生成
通过定时器事件定期生成新的障碍物:
- pygame.time.set_timer(ENEMY_BORN, BORN_RATE)
-
- # 在事件循环中
- if event.type == ENEMY_BORN:
- self.enemy.broth()
3. 碰撞检测
使用pygame的sprite collision检测玩家与障碍物的碰撞:
- r = pygame.sprite.groupcollide(self.enemy.enemy_group, self.player.player_group, False, False)
- if r:
- # 处理碰撞后的游戏结束逻辑
4. 背景滚动
通过不断移动两个背景图片实现无缝滚动:
- def update(self):
- self.rect.left -= self.speed
- if self.rect.left <= -WIDTH:
- self.rect.left = WIDTH
这里我把我的代码放在这里,给大家做个参考,里面还有很多不完善的地方,图片素材什么的也需要大家自行寻找,我的素材大多数都是使用 " 非常糟糕的城市 " 这个游戏的图片素材。
- import random
-
- import pygame
-
- WIDTH, HEIGHT = 500, 500
- ENEMY_BORN = pygame.USEREVENT + 1
- BORN_RATE = 3000
-
-
- class AudioManage:
-
- @staticmethod
- def playing_bg_music():
- pygame.mixer.music.load("./music/紧张.mp3")
- pygame.mixer.music.play(loops=True)
- pygame.mixer.music.set_volume(0.3)
-
- @staticmethod
- def ready_bg_music():
- pygame.mixer.music.load("./music/split.mp3")
- pygame.mixer.music.play(loops=True)
- pygame.mixer.music.set_volume(0.3)
-
- @staticmethod
- def end_bg_music():
- pygame.mixer.music.load("./music/沮丧.mp3")
- pygame.mixer.music.play(loops=True)
- pygame.mixer.music.set_volume(0.3)
-
- @staticmethod
- def set_sound_music(i):
- l0 = ["./music/汽车.mp3", "./music/直升机.mp3", "./music/飞机.mp3",
- "./music/降落伞.mp3", "./music/外星人.mp3", "./music/跳跃.mp3",
- "./music/失败.mp3"]
- pygame.mixer.Sound(l0[i]).play()
-
-
- class BaseSprite(pygame.sprite.Sprite):
- def __init__(self, image_name):
- super().__init__()
- self.image = pygame.image.load(image_name)
- self.rect = self.image.get_rect()
-
-
- class EnemySprite(BaseSprite):
- def __init__(self, image_name, em, speed=5):
- super().__init__(image_name)
- self.em = em
- self.image_name = image_name
- self.image = pygame.transform.flip(self.image, True, False)
- self.set_pos()
- self.speed = speed
-
- def set_pos(self):
- self.rect.left = WIDTH
- if self.image_name in ["./image/car1.png", "./image/car2.png", "./image/car3.png"]:
- AudioManage().set_sound_music(0)
- self.rect.bottom = 300
- elif self.image_name in ["./image/plan.png"]:
- AudioManage().set_sound_music(2)
- self.rect.bottom = 225
- elif self.image_name in ["./image/滑翔伞.png", "./image/直升机.png"]:
- if self.image_name == "./image/滑翔伞.png":
- AudioManage().set_sound_music(3)
- else:
- AudioManage().set_sound_music(1)
- self.rect.bottom = 150
- elif self.image_name in ["./image/外星人1.png", "./image/外星人2.png"]:
- AudioManage().set_sound_music(4)
- self.rect.bottom = 75
-
- def update(self):
- self.rect.left -= self.speed
- if self.rect.right < 0:
- self.kill()
- self.em.gm.ui.update_lab()
-
-
- class EnemyManage:
- def __init__(self, gm_):
- self.gm = gm_
- self.init_enemy()
-
- def init_enemy(self):
- self.enemy_group = pygame.sprite.Group()
- self.enemy = EnemySprite("./image/car1.png", self)
- self.enemy.add(self.enemy_group)
-
- def broth(self):
- em_img_name = random.choice(
- ["./image/car1.png", "./image/car2.png", "./image/car3.png", "./image/外星人1.png", "./image/外星人2.png",
- "./image/滑翔伞.png", "./image/直升机.png", "./image/plan.png"])
- self.enemy = EnemySprite(em_img_name, self)
- self.enemy.add(self.enemy_group)
-
- def clear(self):
- self.enemy_group.empty()
-
- def update(self):
- self.enemy_group.draw(self.gm.screen)
- self.enemy_group.update()
-
-
- class PlayerSprite(pygame.sprite.Sprite):
- def __init__(self, image_names):
- super().__init__()
- self.index = 0
- self.images = [pygame.image.load(image) for image in image_names]
- self.image = self.images[self.index]
- self.rect = self.image.get_rect()
- self.rect.bottom = 300
- self.rect.left = 100
- self.velocity_y = 0
- self.jump_count = 2
-
- def jump(self):
- if self.rect.bottom >= 300:
- self.jump_count = 2
-
- def is_jump(self):
- if self.jump_count > 0:
- AudioManage().set_sound_music(5)
- self.jump_count -= 1
- self.velocity_y = -12
- self.jump()
-
- def update(self):
- self.index += 1
- if self.index >= len(self.images) * 10:
- self.index = 0
- self.image = self.images[self.index // 10]
-
- self.velocity_y += 0.5
- self.rect.y += self.velocity_y
- self.jump()
- if self.rect.bottom > 300:
- self.rect.bottom = 300
- elif self.rect.top < 0:
- self.rect.top = 0
-
-
-
- class PlayerManage:
- def __init__(self, gm_):
- self.gm = gm_
- self.init_player()
-
- def init_player(self):
- self.player_group = pygame.sprite.Group()
- self.images = [f"./image/忍者{i}.png" for i in range(1, 3)]
- self.player = PlayerSprite(self.images)
- self.player.add(self.player_group)
-
- def broth(self):
- self.player = PlayerSprite([f"./image/忍者{i}.png" for i in range(1, 3)])
- self.player.add(self.player_group)
-
- def clear(self):
- self.player_group.empty()
-
- def update(self):
- if not self.player_group:
- self.broth()
- self.player.update()
- self.player_group.draw(self.gm.screen)
-
-
- class BGSprite(BaseSprite):
- def __init__(self, image_name, start_x, speed=3):
- super().__init__(image_name)
- self.rect.left = start_x
- self.speed = speed
-
- def update(self):
- self.rect.left -= self.speed
- if self.rect.left <= -WIDTH:
- self.rect.left = WIDTH
-
-
- class BGManage:
- def __init__(self, gm_):
- self.gm = gm_
- self.init_bg()
-
- def init_bg(self):
- self.bg_gaming_group = pygame.sprite.Group()
- self.bg1 = BGSprite("./image/load.png", 0)
- self.bg1.add(self.bg_gaming_group)
- self.bg2 = BGSprite("./image/load.png", WIDTH)
- self.bg2.add(self.bg_gaming_group)
- self.bg_ready_group = pygame.sprite.Group()
- self.bg3 = BGSprite("./image/background.png", 0)
- self.bg3.add(self.bg_ready_group)
-
- def update(self):
- if self.gm.game_state == "gaming":
- self.bg_gaming_group.draw(self.gm.screen)
- self.bg_gaming_group.update()
- else:
- self.bg_ready_group.draw(self.gm.screen)
-
-
- class UISprite(BaseSprite):
- def __init__(self, image_name, yes_no="yes", start_x=0, start_y=0):
- super().__init__(image_name)
- self.y_n = yes_no
- if self.y_n == "yes":
- self.rect.center = (WIDTH / 2, HEIGHT / 2)
- else:
- self.rect.left = start_x
- self.rect.top = start_y
-
- def is_collide(self):
- mouse_pos = pygame.mouse.get_pos()
- if self.rect.collidepoint(mouse_pos):
- return True
-
-
- class UIManage:
- def __init__(self, gm_ui):
- self.gm = gm_ui
-
- self.init_ready()
- self.init_end()
- self.font = pygame.font.Font("./font/幼圆.TTF", size=24)
- self.set_lab()
-
- def init_ready(self):
- self.ready_group = pygame.sprite.Group()
- self.ready_btn = UISprite("./image/ready.png")
- self.ready_btn.add(self.ready_group)
-
-
- def init_end(self):
- self.end_group = pygame.sprite.Group()
-
- self.end_btn = UISprite("./image/game_over.png")
- self.end_btn.add(self.end_group)
- self.con_btn = UISprite("./image/继续.png", "no", WIDTH - 180, HEIGHT - 88)
- self.con_btn.add(self.end_group)
-
- def set_lab(self):
- self.score_value = 0
- self.labile = self.font.render(f"score:{self.score_value}",
- True, "red")
-
- def update_lab(self):
- self.score_value += 1
- self.labile = self.font.render(f"score:{self.score_value}",
- True, "red")
-
- def check_collision(self):
- if self.gm.game_state == "ready":
- if self.ready_btn.is_collide():
- self.gm.game_state = "gaming"
- self.gm.set_time()
- AudioManage().playing_bg_music()
- elif self.gm.game_state == "end":
- if self.con_btn.is_collide():
- self.gm.game_state = "ready"
- AudioManage().ready_bg_music()
-
- def update(self):
- if self.gm.game_state == "ready":
- self.ready_group.draw(self.gm.screen)
- elif self.gm.game_state == "gaming":
- self.gm.screen.blit(self.labile, (200, 10))
- elif self.gm.game_state == "end":
- self.gm.screen.blit(self.labile, (210, 200))
- self.end_group.draw(self.gm.screen)
-
-
- class GameManage:
- def __init__(self):
- pygame.init()
- pygame.display.set_caption("小城跑酷")
- self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
- self.game_state = "ready"
-
- self.ui = UIManage(self)
- self.bg = BGManage(self)
- self.player = PlayerManage(self)
- self.enemy = EnemyManage(self)
- self.clock = pygame.time.Clock()
- AudioManage().ready_bg_music()
-
- def set_time(self):
- pygame.time.set_timer(ENEMY_BORN, BORN_RATE)
-
- def check_event(self):
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- pygame.quit()
- exit()
- if event.type == pygame.KEYUP:
-
- if event.key == pygame.K_UP or event.key == pygame.K_w:
- if self.game_state == "gaming":
- self.player.player.is_jump()
-
-
- if event.type == ENEMY_BORN:
- self.enemy.broth()
-
- if event.type == pygame.MOUSEBUTTONUP:
- if event.button == 1:
- self.ui.check_collision()
-
- def update_draw(self):
- self.bg.update()
- if self.game_state == "ready":
- self.ui.update()
- self.reset_score()
- elif self.game_state == "gaming":
- self.ui.update()
- self.player.update()
- self.enemy.update()
- elif self.game_state == "end":
- self.ui.update()
-
- pygame.display.flip()
-
- def check_collider(self):
- # pass
- r = pygame.sprite.groupcollide(self.enemy.enemy_group, self.player.player_group, False, False)
- if r:
- for players in r.values():
- for player in players:
- player.kill()
- self.game_state = "end"
- self.enemy.clear()
- pygame.time.set_timer(ENEMY_BORN, 0)
- AudioManage().set_sound_music(6)
- AudioManage().end_bg_music()
-
- def reset_score(self):
- self.ui.score_value = -1
- self.ui.update_lab()
-
- def run(self):
- while True:
- self.clock.tick(60)
- self.check_event()
- self.update_draw()
- self.check_collider()
-
-
- gm = GameManage()
- gm.run()

部分游戏截图:
这个简单的跑酷游戏涵盖了游戏开发的许多基本要素。通过这个项目,我们可以学习到:
- Pygame的基本使用
- 精灵(Sprite)的概念和应用
- 游戏循环的实现
- 用户输入处理
- 碰撞检测
- 音效和音乐的添加
- 简单的游戏UI实现
希望这个示例能帮助你更好地理解游戏开发的基本概念,并为你的Pygame学习之旅提供一个良好的起点。通过修改和扩展这个基础代码,你可以添加更多的游戏特性,如:
- 多种玩家角色
- 更复杂的障碍物模式
- 道具系统
- 关卡设计
- 更精美的图形和动画
- 存档和读档功能
- 多人游戏模式
记住,游戏开发是一个需要不断学习和实践的过程。从这个简单的项目开始,逐步提高你的技能,你将能够创造出更加复杂和有趣的游戏。
最后,建议你深入研究Pygame的官方文档,参与开源游戏项目,并在实践中不断总结经验。祝你在游戏开发的道路上取得成功!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。