童心派软硬互动贪吃蛇游戏

童心派软硬互动贪吃蛇游戏

开发环境:

Download 慧编程​​​​​​

童心派(上网购买)

安装库:

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()

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值