python pygame 编写贪吃蛇
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
player1 wasd ,player2 up left down right,esc退出当前场景 space 暂停。
# 效果
一、main.py
启动页
1 background
背景
2 player
蛇头
speed 速度 每格20
2.1 init
初始化,随机位置,记录方向用于定时移动,记录蛇头上一个位置,用于判断 不能反向移动,key_status 移动方式 True wasd False 上下左右
2.2 update
接收键盘输入,修改当前方向 ,并校验方向+当前位置不等于上一个位置
2.3 go
移动 每250秒执行一次,检查是否出边界
2.4check
检查是否出边界
3 foodSprite
食物精灵
3.1 init
食物,初始化随机位置
4 bodySprite
蛇身精灵
4.1 init
初始化位置
4.2 update
移动
5 game
游戏主函数
5.1 init
初始化背景,玩家,存入精灵组中,创建蛇身精灵组,食物精灵组,创建玩家移动事件每250毫秒,生成食物事件1500毫秒,创建得分
5.2 plant_line
背景显示方格,调试用,不用可以关掉
5.3 show_text
显示字体 得分
5.4 place_sprites
绘制精灵组里的精灵,食物、背景、玩家、蛇身
5.5 check_sprites
碰撞检测,蛇头和蛇身、蛇头和食物,玩家和玩家
5.6 key_listener
键盘监听 wasd、上下左右 esc退出 空格暂停
5.7 run
循环绘制执行 限制120帧
6 buttonSprite
按钮精灵,主界面使用
7 show_text
绘制字体通用方法
8 Menu
主界面
8.1 init
菜单页面初始化,初始化两个按钮 1个玩家 2个玩家
8.2 run
循环函数,选择完以后调用game方法
#coding=utf-8
from numpy import floor
try:
import sys
import random
import math
import os
import getopt
import pygame as pygame
from socket import *
from pygame.locals import *
except ImportError as err:
print("couldn't load module. %s" % (err))
sys.exit(2)
class background(pygame.sprite.Sprite):
def __init__(self,size):
super().__init__()
self.surf = pygame.Surface(size)
self.surf = self.surf.convert()
self.surf.fill((125, 125, 125))
self.rect = self.surf.get_rect()
class player(pygame.sprite.Sprite):
speed = 20
def __init__(self,size, key_status=True):
super().__init__()
self.background_size = size
self.surf = pygame.Surface((20,20))
self.surf = self.surf.convert()
self.surf.fill((139,0,139))
self.rect = self.surf.get_rect(center=(int(floor(random.randint(0,self.background_size[0]/20)) * 20-10),int(floor(random.randint(0,self.background_size[1]/20))) * 20-10))
self.direction = 0, -self.speed
self.last_pos = (0,0)
self.key_status = key_status
def update(self, key, flag=False):
direction = self.direction
if self.key_status:
if key == K_UP:
self.direction = (0, -self.speed)
# self.rect.move_ip(0, -self.speed)
elif key == K_DOWN:
self.direction = (0, self.speed)
# self.rect.move_ip(0, self.speed)
elif key == K_LEFT:
self.direction = (-self.speed, 0)
# self.rect.move_ip(-self.speed, 0)
elif key == K_RIGHT:
self.direction = (self.speed, 0)
else:
if key == K_w:
self.direction = (0, -self.speed)
# self.rect.move_ip(0, -self.speed)
elif key == K_s:
self.direction = (0, self.speed)
# self.rect.move_ip(0, self.speed)
elif key == K_a:
self.direction = (-self.speed, 0)
# self.rect.move_ip(-self.speed, 0)
elif key == K_d:
self.direction = (self.speed, 0)
# self.rect.move_ip(self.speed, 0)
if flag:
x, y = self.rect.center
lx, ly = self.last_pos
dx,dy = self.direction
if (x + dx) == lx and (y+dy)==ly:
#上一个位置
self.direction = direction
self.check()
def go(self):
self.last_pos = self.rect.center
self.rect.move_ip(self.direction)
self.check()
def check(self):
# 限定player在屏幕中
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > self.background_size[0]:
self.rect.right = self.background_size[0]
if self.rect.top <= 0:
self.rect.top = 0
elif self.rect.bottom >= self.background_size[1]:
self.rect.bottom = self.background_size[1]
class foodSprite(pygame.sprite.Sprite):
def __init__(self,size):
super().__init__()
self.background_size = size
self.surf = pygame.Surface((20, 20))
self.surf = self.surf.convert()
self.surf.fill((255,182,193))
self.rect = self.surf.get_rect(center=(int(floor(random.randint(0,self.background_size[0]/20)) * 20-10),int(floor(random.randint(0,self.background_size[1]/20))) * 20-10))
class bodySprite(pygame.sprite.Sprite):
def __init__(self,pos):
super(bodySprite, self).__init__()
self.surf = pygame.Surface((20,20))
self.surf = self.surf.convert()
self.surf.fill((0,0,0))
self.rect = self.surf.get_rect(center=pos)
self.direction = ()
def update(self, direction):
self.direction = direction
self.rect.move_ip(direction)
class game():
def __init__(self,num="1"):
pygame.init()
self.screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption('贪吃蛇')
self.num = num
#是否显示线
self.plant_flag = True
#初始化背景
self.background = background(self.screen.get_size())
self.screen.blit(self.background.surf,self.background.rect)
self.player = player(self.screen.get_size(),True)
self.all_sprites = pygame.sprite.Group()
self.all_sprites.add(self.background)
self.all_sprites.add(self.player)
self.players = pygame.sprite.Group()
self.players.add(self.player)
self.player2 = player(self.screen.get_size(),False)
#用户
if num == "2":
self.all_sprites.add(self.player2)
self.players.add(self.player2)
self.foods_sprites = pygame.sprite.Group()
self.bodys_sprites = pygame.sprite.Group()
self.bodys_sprites2 = pygame.sprite.Group()
self.ADDENEMY = pygame.USEREVENT + 1 # 事件本质上就是整数常量。比 USEREVENT 小的数值已经对应内置事件,因此任何自定义事件都必须比 USEREVENT 大)
pygame.time.set_timer(self.ADDENEMY, 250) # 每隔 250 毫秒(四分之一秒) 触发
self.GEN_FOOD = pygame.USEREVENT + 2 # 事件本质上就是整数常量。比 USEREVENT 小的数值已经对应内置事件,因此任何自定义事件都必须比 USEREVENT 大)
pygame.time.set_timer(self.GEN_FOOD, 1500) # 每隔 250 毫秒(四分之一秒) 触发
self.score = 0 #得分
self.score2 = 0 # 得分
"""
调试用
"""
def plant_line(self, space=20):
color = (0,0,0)
w,h = self.screen.get_size()
ws,hs = w//space , h//space
for i in range(hs):
pygame.draw.line(self.screen, color, (0, 20*i), (640, 20*i), 1)
for i in range(ws):
pygame.draw.line(self.screen, color, (20*i, 0), (20*i, 480), 1)
#显示字体
def show_text(self, font_size=40, font_bold=True, font_italic=False):
cur_font = pygame.font.SysFont("华文宋体", font_size)
cur_font.set_bold(font_bold)
cur_font.set_italic(font_italic)
text_message = cur_font.render("Score: "+str(self.score), 12, (220,20,60))
self.screen.blit(text_message, (460,20))
if self.num == "2":
text_message2 = cur_font.render("Score: " + str(self.score2), 12, (220, 20, 60))
self.screen.blit(text_message2, (40, 20))
def place_sprites(self):
for sprite in self.all_sprites:
self.screen.blit(sprite.surf, sprite.rect)
for sprite in self.foods_sprites:
self.screen.blit(sprite.surf, sprite.rect)
for sprite in self.bodys_sprites:
self.screen.blit(sprite.surf, sprite.rect)
for sprite in self.bodys_sprites2:
self.screen.blit(sprite.surf, sprite.rect)
#碰撞检测
def check_sprites(self):
collide_list = pygame.sprite.spritecollide(self.player, self.bodys_sprites, False)
if len(collide_list) > 0:
print('碰到自己身体了,分数清零 重新开始')
self.bodys_sprites = pygame.sprite.Group()
self.score = 0
collide_list = pygame.sprite.spritecollide(self.player, self.foods_sprites, False)
for c in collide_list:
print("撞上了")
self.foods_sprites.remove(c)
self.score += 1
body = bodySprite(self.player.last_pos)
self.bodys_sprites.add(body)
collide_list = pygame.sprite.spritecollide(self.player2, self.bodys_sprites2, False)
if len(collide_list) > 0:
print('碰到自己身体了,分数清零 重新开始')
self.bodys_sprites2 = pygame.sprite.Group()
self.score2 = 0
collide_list = pygame.sprite.spritecollide(self.player2, self.foods_sprites, False)
for c in collide_list:
print("撞上了")
self.foods_sprites.remove(c)
self.score2 += 1
body = bodySprite(self.player2.last_pos)
self.bodys_sprites2.add(body)
collide = pygame.sprite.collide_rect(self.player2, self.player)
if collide:
print("撞上了")
self.bodys_sprites2 = pygame.sprite.Group()
self.score2 = 0
self.bodys_sprites = pygame.sprite.Group()
self.score = 0
#键盘监听
def key_listener(self):
for event in pygame.event.get():
if event.type == QUIT:
return True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
return True
elif event.key == K_SPACE:
paused = True
while paused:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
return
elif event.type == KEYDOWN:
if event.key == K_SPACE:
paused = False
elif event.key == K_ESCAPE:
return True
else:
self.player.update(event.key, flag=True if len(self.bodys_sprites) > 0 else False)
self.player2.update(event.key, flag=True if len(self.bodys_sprites2) > 0 else False)
elif event.type == self.ADDENEMY: # 自定义事件
self.player.go()
self.player2.go()
body_pos = None
for i, sprite in enumerate(self.bodys_sprites):
if i == 0:
body_pos = sprite.rect.center
sprite.rect.center = self.player.last_pos
else:
a = sprite.rect.center
sprite.rect.center = body_pos
body_pos = a
pygame.display.flip()
for i, sprite in enumerate(self.bodys_sprites2):
if i == 0:
body_pos = sprite.rect.center
sprite.rect.center = self.player2.last_pos
else:
a = sprite.rect.center
sprite.rect.center = body_pos
body_pos = a
pygame.display.flip()
elif event.type == self.GEN_FOOD: # 自定义事件
f = foodSprite(self.screen.get_size())
self.foods_sprites.add(f)
def run(self):
clock = pygame.time.Clock()
while True:
#键盘监听
flag = self.key_listener()
if flag:
return
#放置精灵组
self.place_sprites()
# 显示得分
self.show_text()
#碰撞检测
self.check_sprites()
#是否显示调试图
if self.plant_flag:
self.plant_line()
pygame.display.flip()
clock.tick(120)
class buttonSprite(pygame.sprite.Sprite):
def __init__(self, name, pos):
super(buttonSprite, self).__init__()
self.name = name
self.surf = pygame.Surface((180,150))
self.surf = self.surf.convert()
self.surf.fill((225, 225, 225))
self.rect = self.surf.get_rect(center=pos)
#显示字体
def show_text(screen, text,pos,color, font_size=40, font_bold=True, font_italic=False):
cur_font = pygame.font.SysFont("华文宋体", font_size)
cur_font.set_bold(font_bold)
cur_font.set_italic(font_italic)
text_message = cur_font.render(text, 12, color)
screen.blit(text_message, pos)
class Menu():
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption('贪吃蛇')
# 初始化背景
self.background = background(self.screen.get_size())
self.screen.blit(self.background.surf, self.background.rect)
one_player_button = buttonSprite("1",(220,160))
two_player_button = buttonSprite("2",(410, 160))
self.all_sprite = pygame.sprite.Group()
self.all_sprite.add(one_player_button)
self.all_sprite.add(two_player_button)
def run(self):
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
return
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for s in self.all_sprite:
if s.rect.collidepoint(event.pos):
game(s.name).run()
self.screen.blit(self.background.surf,self.background.rect)
for sprite in self.all_sprite:
self.screen.blit(sprite.surf,sprite.rect)
show_text(self.screen, "1个玩家", (140, 140), (220, 20, 60))
show_text(self.screen, "2个玩家", (330, 140), (220, 20, 60))
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
# game().run()
Menu().run()