童心派软硬互动贪吃蛇游戏
开发环境:
童心派(上网购买)
安装库:
pip install cyberpi
pip install pygame
第一步:编写函数
import pygame
from pygame.locals import *
import random
# ---------- constants ---------- #
SCREENSIZE = (800, 600)
SCREENRECT = pygame.Rect(0, 0, SCREENSIZE[0], SCREENSIZE[1])
CAPTION = 'MiniSnake'
FPS = 40
START_TILE = (20, 20)
START_SEGMENTS = 7
MOVE_RATE = 2
DIFFICULTY_INCREASE_RATE = .05
MOVE_THRESHOLD = 5 # when moverate counts up to this the snake moves
BLOCK_SPAWN_RATE = 2
TILE_SIZE = (10, 10)
TILE_RECT = pygame.Rect(0, 0, TILE_SIZE[0], TILE_SIZE[1])
SCREENTILES = ((SCREENSIZE[0] / TILE_SIZE[0]) - 1, (SCREENSIZE[1] / TILE_SIZE[1]) - 1)
SNAKE_HEAD_RADIUS = 5
SNAKE_SEGMENT_RADIUS = 4
FOOD_RADIUS = 4
BACKGROUND_COLOR = (255, 255, 255)
SNAKE_HEAD_COLOR = (150, 0, 0)
SNAKE_SEGMENT_COLOR = (255, 0, 0)
FOOD_COLOR = (0, 255, 0)
BLOCK_COLOR = (0, 0, 150)
COLORKEY_COLOR = (255, 255, 0)
SCORE_COLOR = (0, 0, 0)
SCORE_POS = (20, 20)
SCORE_PREFIX = 'Score: '
MOVE_VECTORS = {'left' : (-1, 0),
'right' : (1, 0),
'up' : (0, -1),
'down' : (0, 1)
}
MOVE_VECTORS_PIXELS = {'left' : (-TILE_SIZE[0], 0),
'right' : (TILE_SIZE[0], 0),
'up' : (0, -TILE_SIZE[1]),
'down' : (0, TILE_SIZE[1])
}
# ----------- game objects ----------- #
class snake_segment(pygame.sprite.Sprite):
def __init__(self, tilepos, segment_groups, color = SNAKE_SEGMENT_COLOR, radius = SNAKE_SEGMENT_RADIUS):
pygame.sprite.Sprite.__init__(self)
self.image = self.image = pygame.Surface(TILE_SIZE).convert()
self.image.fill(COLORKEY_COLOR)
self.image.set_colorkey(COLORKEY_COLOR)
pygame.draw.circle(self.image, color, TILE_RECT.center, radius)
self.tilepos = tilepos
self.rect = self.image.get_rect()
self.rect.topleft = (tilepos[0] * TILE_SIZE[0], tilepos[1] * TILE_SIZE[1])
self.segment_groups = segment_groups
for group in segment_groups:
group.add(self)
self.behind_segment = None
self.movedir = 'left'
def add_segment(self):
seg = self
while True:
if seg.behind_segment == None:
x = seg.tilepos[0]
y = seg.tilepos[1]
if seg.movedir == 'left':
x += 1
elif seg.movedir == 'right':
x -= 1
elif seg.movedir == 'up':
y += 1
elif seg.movedir == 'down':
y -= 1
seg.behind_segment = snake_segment((x, y), seg.segment_groups)
seg.behind_segment.movedir = seg.movedir
break
else:
seg = seg.behind_segment
def update(self):
pass
def move(self):
self.tilepos = (self.tilepos[0] + MOVE_VECTORS[self.movedir][0], self.tilepos[1] + MOVE_VECTORS[self.movedir][1])
self.rect.move_ip(MOVE_VECTORS_PIXELS[self.movedir])
if self.behind_segment != None:
self.behind_segment.move()
self.behind_segment.movedir = self.movedir
class snake_head(snake_segment):
def __init__(self, tilepos, movedir, segment_groups):
snake_segment.__init__(self, tilepos, segment_groups, color = SNAKE_HEAD_COLOR, radius = SNAKE_HEAD_RADIUS)
self.movedir = movedir
self.movecount = 0
def update(self):
self.movecount += MOVE_RATE
if self.movecount > MOVE_THRESHOLD:
self.move()
self.movecount = 0
class food(pygame.sprite.Sprite):
def __init__(self, takenupgroup):
pygame.sprite.Sprite.__init__(self)
self.image = self.image = pygame.Surface(TILE_SIZE).convert()
self.image.fill(COLORKEY_COLOR)
self.image.set_colorkey(COLORKEY_COLOR)
pygame.draw.circle(self.image, FOOD_COLOR, TILE_RECT.center, FOOD_RADIUS)
self.rect = self.image.get_rect()
while True:
self.rect.topleft = (random.randint(0, SCREENTILES[0]) * TILE_SIZE[0], random.randint(0, SCREENTILES[1]) * TILE_SIZE[1])
for sprt in takenupgroup:
if self.rect.colliderect(sprt):
continue # collision, food cant go here
break # no collision, food can go here
class block(pygame.sprite.Sprite):
def __init__(self, takenupgroup):
pygame.sprite.Sprite.__init__(self)
self.image = self.image = pygame.Surface(TILE_SIZE).convert()
self.image.fill(BLOCK_COLOR)
self.rect = self.image.get_rect()
while True:
self.rect.topleft = (random.randint(0, SCREENTILES[0]) * TILE_SIZE[0], random.randint(0, SCREENTILES[1]) * TILE_SIZE[1])
for sprt in takenupgroup:
if self.rect.colliderect(sprt):
continue # collision, food cant go here
break # no collision, food can go here
第二步:主函数
# -------------- game logic ------------ #
def main():
pygame.init()
screen = pygame.display.set_mode(SCREENSIZE)
pygame.display.set_caption(CAPTION)
bg = pygame.Surface(SCREENSIZE).convert()
bg.fill(BACKGROUND_COLOR)
screen.blit(bg, (0, 0))
snakegroup = pygame.sprite.Group()
snakeheadgroup = pygame.sprite.Group()
foodgroup = pygame.sprite.Group()
blockgroup = pygame.sprite.Group()
takenupgroup = pygame.sprite.Group()
all = pygame.sprite.RenderUpdates()
snake = snake_head(START_TILE, 'right', [snakegroup, all, takenupgroup])
snakeheadgroup.add(snake)
for index in range(START_SEGMENTS):
snake.add_segment()
currentfood = 'no food'
block_frame = 0
currentscore = 0
pygame.display.flip()
# mainloop
quit = False
clock = pygame.time.Clock()
lose = False
while not quit:
# events
for event in pygame.event.get():
if event.type == QUIT:
quit = True
elif event.type == KEYDOWN:
currentmovedir = snake.movedir
if event.key == K_UP:
tomove = 'up'
dontmove = 'down'
elif event.key == K_DOWN:
tomove = 'down'
dontmove = 'up'
elif event.key == K_LEFT:
tomove = 'left'
dontmove = 'right'
elif event.key == K_RIGHT:
tomove = 'right'
dontmove = 'left'
else:
raise 'RuntimeError, not expected'
if not currentmovedir == dontmove:
snake.movedir = tomove
# clearing
all.clear(screen, bg)
# updates
all.update()
if currentfood == 'no food':
currentfood = food(takenupgroup)
foodgroup.add(currentfood)
takenupgroup.add(currentfood)
all.add(currentfood)
pos = snake.rect.topleft
if pos[0] < 0:
quit = True
lose = True
if pos[0] >= SCREENSIZE[0]:
quit = True
lose = True
if pos[1] < 0:
quit = True
lose = True
if pos[1] >= SCREENSIZE[1]:
quit = True
lose = True
# collisions
# head -> tail
col = pygame.sprite.groupcollide(snakeheadgroup, snakegroup, False, False)
for head in col:
for tail in col[head]:
if not tail is snake:
quit = True
lose = True
# head -> food
col = pygame.sprite.groupcollide(snakeheadgroup, foodgroup, False, True)
for head in col:
for tail in col[head]:
currentfood = 'no food'
snake.add_segment()
currentscore += 1
global MOVE_RATE, DIFFICULTY_INCREASE_RATE
MOVE_RATE += DIFFICULTY_INCREASE_RATE
block_frame += 1
if block_frame >= BLOCK_SPAWN_RATE:
block_frame = 0
b = block(takenupgroup)
blockgroup.add(b)
takenupgroup.add(b)
all.add(b)
# head -> blocks
col = pygame.sprite.groupcollide(snakeheadgroup, blockgroup, False, False)
for head in col:
for collidedblock in col[head]:
quit = True
lose = True
# score
d = screen.blit(bg, SCORE_POS, pygame.Rect(SCORE_POS, (50, 100)))
f = pygame.font.Font(None, 12)
scoreimage = f.render(SCORE_PREFIX + str(currentscore), True, SCORE_COLOR)
d2 = screen.blit(scoreimage, SCORE_POS)
# drawing
dirty = all.draw(screen)
dirty.append(d)
dirty.append(d2)
# updating
pygame.display.update(dirty)
# waiting
clock.tick(FPS)
# game over
if lose == True:
f = pygame.font.Font(None, 300)
failmessage = f.render('FAIL', True, (0, 0, 0))
failrect = failmessage.get_rect()
failrect.center = SCREENRECT.center
screen.blit(failmessage, failrect)
pygame.display.flip()
pygame.time.wait(2000)
if __name__ == "__main__":
main()
第三步:绑定童心派按键
import cyberpi
if cyberpi.controller.is_press("up"):
if direct == 'left' or direct == 'right':
direct = 'top'
if cyberpi.controller.is_press("down"):
if direct == 'left' or direct == 'right':
direct = 'bottom'
if cyberpi.controller.is_press("left"):
if direct == 'top' or direct == 'bottom':
direct = 'left'
if cyberpi.controller.is_press("right"):
if direct == 'top' or direct == 'bottom':
direct = 'right'
之前写的有点太长了,简化一下:
import pygame
from sys import exit
import random
import time
import cyberpi
class Point():
def __init__(self, row, clo):
self.row = row
self.clo = clo
def copy(self):
return Point(row=self.row, clo=self.clo)
# 初始化
pygame.init()
width = 800
hight = 400
ROW = 30
CLO = 50
direct = 'left'
window = pygame.display.set_mode((width, hight))
pygame.display.set_caption('贪吃蛇游戏')
# 蛇头坐标定在中间
head = Point(row=int(ROW / 2), clo=int(CLO / 2))
# 初始化蛇身的元素数量
snake = [
Point(row=head.row, clo=head.clo + 1),
Point(row=head.row, clo=head.clo + 2),
Point(row=head.row, clo=head.clo + 3)
]
# 生成食物并且不让食物生成在蛇的身体里面
def gen_food():
while 1:
position = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
is_coll = False
if head.row == position.row and head.clo == position.clo:
is_coll = True
for body in snake:
if body.row == position.row and body.clo == position.clo:
is_coll = True
break
if not is_coll:
break
return position
# 定义坐标
# 蛇头颜色可以自定义
head_color = (0, 158, 128)
# 食物坐标
snakeFood = gen_food()
# 食物颜色
snakeFood_color = (255, 255, 0)
snake_color = (200, 0, 18)
# 需要执行很多步画图操作 所以定义一个函数
def rect(point, color):
# 定位 画图需要left和top
left = point.clo * width / CLO
top = point.row * hight / ROW
# 将方块涂色
pygame.draw.rect(window, color, (left, top, width / CLO, hight / ROW))
quit = True
# 设置帧频率
clock = pygame.time.Clock()
while quit:
# 处理帧频 锁帧
clock.tick(30)
# cyberpi 遥杆控制
if cyberpi.controller.is_press("up"):
if direct == 'left' or direct == 'right':
direct = 'top'
if cyberpi.controller.is_press("down"):
if direct == 'left' or direct == 'right':
direct = 'bottom'
if cyberpi.controller.is_press("left"):
if direct == 'top' or direct == 'bottom':
direct = 'left'
if cyberpi.controller.is_press("right"):
if direct == 'top' or direct == 'bottom':
direct = 'right'
# 键盘控制
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = False
elif event.type == pygame.KEYDOWN:
if event.key == 273 or event.key == 119:
if direct == 'left' or direct == 'right':
direct = 'top'
if event.key == 274 or event.key == 115:
if direct == 'left' or direct == 'right':
direct = 'bottom'
if event.key == 276 or event.key == 97:
if direct == 'top' or direct == 'bottom':
direct = 'left'
if event.key == 275 or event.key == 100:
if direct == 'top' or direct == 'bottom':
direct = 'right'
# 吃东西
eat = (head.row == snakeFood.row and head.clo == snakeFood.clo)
# 处理蛇的身子
# 1.把原来的头插入到snake的头上
# 2.把最后一个snake删掉
if eat:
snakeFood = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
snake.insert(0, head.copy())
if not eat:
snake.pop()
# 移动一下
if direct == 'left':
head.clo -= 1
if direct == 'right':
head.clo += 1
if direct == 'top':
head.row -= 1
if direct == 'bottom':
head.row += 1
dead = False
if head.clo < 0 or head.row < 0 or head.clo >= CLO or head.row >= ROW:
dead = True
for body in snake:
if head.clo == body.clo and head.row == body.row:
dead = True
break
if dead:
print('Game Over')
pygame.quit()
exit()
quit = False
# 背景画图
pygame.draw.rect(window, (20, 10, 10), (0, 0, width, hight))
# 蛇头
rect(head, head_color)
# 绘制食物
rect(snakeFood, snakeFood_color)
# 绘制蛇的身子
for body in snake:
rect(body, snake_color)
# 交还控制权
pygame.display.flip()
time.sleep(0.05)
pygame.quit()
exit()
1452

被折叠的 条评论
为什么被折叠?



