基于 Python 制作的热血足球小游戏
导语
最近有读者说我发的文章太水了,都是炒冷饭的,那就带大家整点新鲜的东西吧,反正估计今年都得"坐牢"了,炒冷饭的机会有得是。
好像好久没带大家写新的小游戏了,那么今天就来带大家写个简单的足球小游戏咯(与近期热点绝对无关,狗头戏谑),废话不多说,让我们愉快地开始吧~
开发工具
Python 版本:3.7.8
相关模块:
pygame 模块;
以及一些 python 自带的模块。
环境搭建
安装 Python 并添加到环境变量,pip 安装需要的相关模块即可。
游戏实现
这里简单介绍一下原理吧,首先我们整个简单的开始界面吧:
```python
'''定义游戏开始界面''' def StartInterface(screen, resource_loader, cfg): clock = pygame.time.Clock() font, flag, count = resource_loader.fonts['default30'], True, 0 font_render = font.render('按任意键开始游戏', False, cfg.RED) while True: count += 1 if count > 20: count, flag = 0, not flag for event in pygame.event.get(): if event.type == pygame.QUIT: QuitGame() elif event.type == pygame.KEYDOWN: return True screen.blit(resource_loader.images['background_start'], (0, 0)) if flag: screen.blit(font_render, ((cfg.SCREENSIZE[0] - font.size('按任意键开始游戏')[0]) // 2, cfg.SCREENSIZE[1] - 200)) clock.tick(cfg.FPS) pygame.display.update() ```
效果大概是这样子的:
方便起见,我们设置成了按任意键都可以开始游戏。
接下来,我们来定义一下球员类,球员分为电脑自动控制和我们手动控制两种类型,其中我们手动控制的核心代码如下:
'''更新'''
def update(self, screen_size, ball):
# 电脑自动控制
if self.auto_control:
self.autoupdate(screen_size, ball)
return
# 静止状态
if not self.is_moving: return
# 切换人物动作实现动画效果
self.switch()
# 根据方向移动人物
ori_position = self.position.copy()
speed = self.speed * self.direction[0], self.speed * self.direction[1]
self.position[0] = min(max(0, self.position[0] + speed[0]), screen_size[0] - 48)
self.position[1] = min(max(0, self.position[1] + speed[1]), screen_size[1] - 48)
self.rect.left, self.rect.top = self.position
if self.rect.bottom > 305 and self.rect.top < 505 and (self.rect.right > 1121 or self.rect.left < 75):
self.position = ori_position
self.rect.left, self.rect.top = self.position
# 设置为静止状态
self.is_moving = False
电脑自动控制的核心代码如下:
```python
'''自动更新''' def autoupdate(self, screen_size, ball): # 守门员 if self.player_type == 'goalkeeper': self.speed = 1 # --沿着门漫步 def wondering(self): self.switch() self.position[1] = min(max(305, self.position[1] + self.direction[1] * self.speed), 459) self.rect.left, self.rect.top = self.position if self.rect.top == 305 or self.rect.top == 459: self.direction = self.direction[0], -self.direction[1] self.setdirection(self.direction) # --有球就随机射球 if ball.taken_by_player == self: if self.group_id == 1: if random.random() > 0.8 or self.prepare_for_kicking: self.prepare_for_kicking = True self.setdirection((1, 0)) if self.prepare_for_kicking: self.prepare_for_kicking_count += 1 if self.prepare_for_kicking_count > self.prepare_for_kicking_freq: self.prepare_for_kicking_count = 0 self.prepare_for_kicking = False ball.kick(self.direction) self.setdirection(random.choice([(0, 1), (0, -1)])) else: wondering(self) else: if random.random() > 0.8 or self.prepare_for_kicking: self.prepare_for_kicking = True self.setdirection((-1, 0)) if self.prepare_for_kicking: self.prepare_for_kicking_count += 1 if self.prepare_for_kicking_count > self.prepare_for_kicking_freq: self.prepare_for_kicking_count = 0 self.prepare_for_kicking = False ball.kick(self.direction) self.setdirection(random.choice([(0, 1), (0, -1)])) else: wondering(self) # --没球来回走 else: wondering(self) # 其他球员跟着球走 else: if ball.taken_by_player == self: self.switch() if self.group_id == 1: self.direction = min(max(1150 - self.rect.left, -1), 1), min(max(405 - self.rect.top, -1), 1) else: self.direction = min(max(350 - self.rect.left, -1), 1), min(max(405 - self.rect.top, -1), 1) self.setdirection(self.direction) if (random.random() > 0.9 and self.position[0] > 350 and self.position[0] < 1150) or self.prepare_for_kicking: if self.group_id == 1: self.direction = min(max(1190 - self.rect.left, -1), 1), min(max(405 - self.rect.top, -1), 1) else: self.direction = min(max(310 - self.rect.left, -1), 1), min(max(405 - self.rect.top, -1), 1) self.setdirection(self.direction) self.prepare_for_kicking = True if self.prepare_for_kicking: self.prepare_for_kicking_count += 1 if self.prepare_for_kicking_count > self.prepare_for_kicking_freq: self.prepare_for_kicking_count = 0 self.prepare_for_kicking = False ball.kick(self.direction) else: speed = self.speed * self.direction[0], self.speed * self.direction[1] ori_position = self.position.copy() self.position[0] = min(max(0, self.position[0] + speed[0]), screen_size[0] - 48) self.position[1] = min(max(0, self.position[1] + speed[1]), screen_size[1] - 48) self.rect.left, self.rect.top = self.position if self.rect.bottom > 305 and self.rect.top < 505 and (self.rect.right > 1121 or self.rect.left < 75): self.position = ori_position self.rect.left, self.rect.top = self.position else: self.switch() if (ball.rect.centery > 400 and self.player_type == 'bottomhalf') or (ball.rect.centery <= 400 and self.player_type == 'upperhalf') or self.player_type == 'common': self.direction = min(max(ball.rect.left - self.rect.left, -1), 1), min(max(ball.rect.top - self.rect.top, -1), 1) self.direction = self.direction[0] * random.random(), self.direction[1] * random.random() else: if self.keep_direction_count >= self.keep_direction_freq: self.direction = random.choice([-1, 0, 1]), random.choice([-1, 0, 1]) self.keep_direction_count = 0 else: self.keep_direction_count += 1 self.setdirection(self.direction) speed = self.speed * self.direction[0], self.speed * self.direction[1] ori_position = self.position.copy() self.position[0] = min(max(0, self.position[0] + speed[0]), screen_size[0] - 48) self.position[1] = min(max(0, self.position[1] + speed[1]), screen_size[1] - 48) self.rect.left, self.rect.top = self.position if self.rect.bottom > 305 and self.rect.top < 505 and (self.rect.right > 1121 or self.rect.left < 75): self.position = ori_position self.rect.left, self.rect.top = self.position ```
逻辑比较简单,大概是这样子的:
- 守门员:就在球门边上来回走
- 负责上半场的球员:在上半场出现球的时候就往球的位置移动,如果捕获到了球,则往对方球门移动并随机射门,否则随机移动;
- 负责下半场的球员:在下半场出现球的时候就往球的位置移动,如果捕获到了球,则往对方球门移动并随机射门,否则随机移动;
- 负责全场的球员:往球的位置移动,果捕获到了球,则往对方球门移动并随机射门。
接下来定义一下足球类:
python
'''定义足球类'''
class Ball(pygame.sprite.Sprite):
def __init__(self, images, position):
pygame.sprite.Sprite.__init__(self)
self.images = images
self.image = self.images[0]
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = position
self.mask = pygame.mask.from_surface(self.image)
# 球的速度
self.speed = 0
# 球的方向
self.direction = [0, 0]
# 控制球的球员
self.taken_by_player = None
# 用于切换球动作的变量
self.action_pointer = 0
self.count = 0
self.switch_frequency = 3
# 是否在运动状态
self.is_moving = False
'''更新'''
def update(self, screen_size):
# 静止状态
if not self.is_moving: return
# 切换球动作实现动画效果
self.count += 1
if self.count == self.switch_frequency:
self.count = 0
self.action_pointer = (self.action_pointer + 1) % len(self.images)
self.image = self.images[self.action_pointer]
# 如果球是被球员控制的
if self.taken_by_player is not None:
self.setdirection(self.taken_by_player.direction)
if self.taken_by_player.direction[0] < 0:
self.rect.left, self.rect.top = self.taken_by_player.rect.left - 15, self.taken_by_player.rect.top + 30
elif self.taken_by_player.direction[0] > 0:
self.rect.left, self.rect.top = self.taken_by_player.rect.left + 30, self.taken_by_player.rect.top + 30
elif self.taken_by_player.direction[1] < 0:
self.rect.left, self.rect.top = self.taken_by_player.rect.left + 15, self.taken_by_player.rect.top - 15
elif self.taken_by_player.direction[1] > 0:
self.rect.left, self.rect.top = self.taken_by_player.rect.left + 10, self.taken_by_player.rect.top + 50
return
# 根据方向移动球
ori_position = self.rect.left, self.rect.right, self.rect.top, self.rect.bottom
self.speed = max(self.speed - 1.7 * 0.05, 0.0)
if self.speed == 0.0: self.is_moving = False
vector = [self.speed * self.direction[0], self.speed * self.direction[1]]
vector[0] = vector[0] / math.pow(self.direction[0] ** 2 + self.direction[1] ** 2, 0.5)
vector[1] = vector[1] / math.pow(self.direction[0] ** 2 + self.direction[1] ** 2, 0.5)
self.rect.left = min(max(0, self.rect.left + vector[0]), screen_size[0] - 48)
if self.rect.left == 0 or self.rect.left == screen_size[0] - 48:
self.direction = self.direction[0] * -0.8, self.direction[1]
self.rect.top = min(max(0, self.rect.top + vector[1]), screen_size[1] - 48)
if ori_position[1] > 1121 or ori_position[0] < 75:
if self.rect.bottom > 305 and self.rect.top < 505:
if self.direction[1] > 0:
self.rect.bottom = 305
self.direction = self.direction[0], self.direction[1] * -0.8
elif self.direction[1] < 0:
self.rect.top = 505
self.direction = self.direction[0], self.direction[1] * -0.8
if self.rect.top == 0 or self.rect.top == screen_size[1] - 48:
self.direction = self.direction[0], self.direction[1] * -0.8
'''设置方向'''
def setdirection(self, direction):
self.is_moving = True
self.direction = direction
'''踢球'''
def kick(self, direction):
self.speed = 12
self.direction = direction
self.taken_by_player = None
self.is_moving = True
'''在屏幕上显示'''
def draw(self, screen):
screen.blit(self.image, self.rect)
比较简单,主要就是两种状态:
- 被球员捕获,跟着球员走;
- 被球员踢出去之后根据球员踢的方向和设定的初速度进行减速运动,如果碰到边界则反方向弹出。
最后写个主循环就大功告成啦:
```python
游戏主循环
clock = pygame.time.Clock() while True: # --基础背景绘制 screen.fill(cfg.LIGHTGREEN) pygame.draw.circle(screen, cfg.WHITE, (600, 400), 80, 5) pygame.draw.rect(screen, cfg.WHITE, (10, 10, 600, 790), 5) pygame.draw.rect(screen, cfg.WHITE, (600, 10, 590, 790), 5) pygame.draw.rect(screen, cfg.WHITE, (10, 150, 300, 500), 5) pygame.draw.rect(screen, cfg.WHITE, (890, 150, 300, 500), 5) screen.blit(resource_loader.images['doors'][0].convert(), (8, 305)) screen.blit(resource_loader.images['doors'][1].convert(), (1121, 305)) screen.blit(score_board, (565, 15)) # --事件监听 for event in pygame.event.get(): if event.type == pygame.QUIT: QuitGame() elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: QuitGame() pressed_keys = pygame.key.get_pressed() direction = [0, 0] if pressed_keys[pygame.K_w]: direction[1] -= 1 if pressed_keys[pygame.K_d]: direction[0] += 1 if pressed_keys[pygame.K_s]: direction[1] += 1 if pressed_keys[pygame.K_a]: direction[0] -= 1 if direction != [0, 0]: player_controlled.setdirection(direction) if pressed_keys[pygame.K_SPACE] and player_controlled == ball.taken_by_player: ball.kick(player_controlled.direction) # --更新玩家 for item in players_group1: if pygame.sprite.collide_mask(item, ball) and ball.taken_by_player != item: ball.is_moving = True ball.taken_by_player = item for item in players_group2: if pygame.sprite.collide_mask(item, ball) and ball.taken_by_player != item: ball.is_moving = True ball.taken_by_player = item for item in players_group1: item.update(cfg.SCREENSIZE_GAMING, ball) for item in players_group2: item.update(cfg.SCREENSIZE_GAMING, ball) # --更新球 ball.update(cfg.SCREENSIZE_GAMING) # --更新屏幕 ball.draw(screen) players_group1.draw(screen) players_group2.draw(screen) clock.tick(cfg.FPS) pygame.display.update() # --计算得分 if ball.rect.bottom > 305 and ball.rect.top < 505: if ball.rect.right > 1121: return 1 elif ball.rect.left < 75: return 2 ```
比较简单,就不过多介绍了,按 WASD 控制上下左右,空格键射门。
完整源代码详见相关文件~
效果展示
首先安装最新版本的 cpgames:
pip install cpgames==0.1.2
然后写如下代码调用即可运行:
``` from cpgames import cpgames
game_client = cpgames.CPGames() game_client.execute('bloodfootball') ```
效果如下:
参考文献
- 基于J2EE的球队纪念品销售管理系统的设计与实现(中国地质大学(北京)·王英杰)
- 基于SSH的大学生联谊交友管理系统设计与实现(华中科技大学·王海波)
- 面向高职信息技术教育的严肃游戏设计与实施(大连理工大学·王晓姝)
- 基于ASP.NET开发技术的BBS论坛研究与设计(中国海洋大学·马章勤)
- 3D云游戏平台的设计与实现(北京交通大学·闫璐)
- 基于VF的社区物业信息管理系统的设计与实现(电子科技大学·徐玮)
- 3D云游戏平台的设计与实现(北京交通大学·闫璐)
- 基于Android的足球球迷综合服务平台的设计与实现(北京工业大学·陈鑫)
- 基于轻量级J2EE的网络游戏虚拟物品交易系统的设计与实现(北京邮电大学·曹鹃)
- 基于.NET自定义控件的社区网站系统研究与实现(武汉理工大学·刘亚)
- 基于云平台的校园足球管理系统的设计与实现(内蒙古大学·张艳秋)
- 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航)
- 基于.NET平台的游戏门户系统设计与实现(电子科技大学·余胜鹏)
- 基于云平台的校园足球管理系统的设计与实现(内蒙古大学·张艳秋)
- 基于J2ME的Java手机软件——足球彩票手机投注系统(华侨大学·许向锋)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:源码货栈 ,原文地址:https://m.bishedaima.com/yuanma/36070.html