前言
今年世界杯有人欢喜有人愁,我想愁的人应该居多,不得不说,小日本是真菜啊,特么的!
今天还是搞点咱们好玩点的,世界杯嘛,大家看看就行,大家不是都说,看国足比看相声还搞笑吗?
好了,不笑了。今天给大家带来一款非常简单的足球小游戏,希望大家喜欢,也喜欢大家能在这次世界杯旗开得胜。如果喜欢的话,点点小赞呗
开发工具
Python版本:3.7.8
相关模块:
pygame模块;
以及一些python自带的模块。
环境搭建
安装Python并添加到环境变量,pip安装需要的相关模块即可。
游戏实现
这里简单介绍一下原理吧,首先我们整个简单的开始界面吧:
'''定义游戏开始界面'''
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
电脑自动控制的核心代码如下:
'''自动更新'''
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
逻辑比较简单,大概是这样子的:
-
守门员:就在球门边上来回走
-
负责上半场的球员:在上半场出现球的时候就往球的位置移动,如果捕获到了球,则往对方球门移动并随机射门,否则随机移动;
-
负责下半场的球员:在下半场出现球的时候就往球的位置移动,如果捕获到了球,则往对方球门移动并随机射门,否则随机移动;
-
负责全场的球员:往球的位置移动,果捕获到了球,则往对方球门移动并随机射门。
接下来定义一下足球类:
'''定义足球类'''
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)
比较简单,主要就是两种状态:
-
被球员捕获,跟着球员走;
-
被球员踢出去之后根据球员踢的方向和设定的初速度进行减速运动,如果碰到边界则反方向弹出。
最后写个主循环就大功告成啦:
# 游戏主循环
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')
效果展示
是不是很简单吗,是个非常简易版的游戏,适合和自己的小孩边看世界杯边玩,谢谢大家观看到这里,需要源代码的可以关注下方小卡片哦,点点赞呗。