上一篇:无
我的贪吃蛇
1202 2019-07-29 2020-06-25
前言:富教于乐,自己用python写一个贪吃蛇。
一、源代码
"""
贪吃蛇小游戏,只依赖于pygame库
按照自己的逻辑完全重写,简化了部分操作,后期有待完善
源地址 https://github.com/guliang21/pygame
Created by HK on 2019-07-26
"""
import random
import sys
import time
import pygame
from collections import deque
from pygame.locals import *
Color = pygame.color.Color
# 方格大小
SIZE = 20
# 网格线宽度
LINE_WIDTH = 1
LINE_COLOR = Color("white")
# 格子倍数
W_MULTIPLE = 30
H_MULTIPLE = W_MULTIPLE // 6 * 5
# 屏幕宽度
SCREEN_WIDTH = SIZE * W_MULTIPLE + LINE_WIDTH * (W_MULTIPLE + 1)
# 屏幕高度
SCREEN_HEIGHT = SIZE * H_MULTIPLE + LINE_WIDTH * (H_MULTIPLE + 1)
# 背景色
BG_COLOR = Color("grey")
SNAKE_COLOR = Color("green")
# 蛇运动的速度,值越低速度越快
ORIGIN_SPEED = 0.2
# 初始游戏网格、背景
def paint_game_bg(screen):
# 填充背景色
screen.fill(BG_COLOR)
i = 0
# H_MULTIPLE + 1条横线
while i <= H_MULTIPLE:
pygame.draw.line(screen, LINE_COLOR, (0, i * SIZE + i * LINE_WIDTH), (SCREEN_WIDTH, i * SIZE + i * LINE_WIDTH),
LINE_WIDTH)
i += 1
# W_MULTIPLE + 1条横线
i = 0
while i <= W_MULTIPLE:
pygame.draw.line(screen, LINE_COLOR, (i * SIZE + i * LINE_WIDTH, 0), (i * SIZE + i * LINE_WIDTH, SCREEN_HEIGHT),
LINE_WIDTH)
i += 1
class FoodStyle:
score = 0
Color = None
def __init__(self, score, color1):
self.score = score
self.Color = color1
def __str__(self):
return "(score=%d, Color=%s)" % (self.score, self.Color)
# 食物的分值及颜色
FOOT_STYLES = [FoodStyle(10, Color("red")), FoodStyle(20, Color("orange")), FoodStyle(30, Color("yellow"))]
class Food:
x, y, style = 0, 0, 0
def __init__(self, x, y, style):
self.x, self.y, self.style = x, y, style
def print_self(self, screen):
x = self.x * SIZE + self.x * LINE_WIDTH + LINE_WIDTH
y = SCREEN_HEIGHT - (self.y * SIZE + SIZE) - self.y * LINE_WIDTH - LINE_WIDTH
pygame.draw.rect(screen, self.style.Color, (x, y, SIZE, SIZE), 0)
@staticmethod
def create_random_food(snake):
# 新出的随机点必须在屏幕内
food_x = random.randint(0, W_MULTIPLE - 1)
food_y = random.randint(0, H_MULTIPLE - 1)
# 如果食物出现在蛇身上,则重来
while Point(food_x, food_y) in snake.snake:
food_x = random.randint(0, W_MULTIPLE - 1)
food_y = random.randint(0, H_MULTIPLE - 1)
food_style = FOOT_STYLES[random.randint(0, FOOT_STYLES.__len__() - 1)]
print('食物坐标为(%d, %d), 样式为%s' % (food_x, food_y, food_style))
return Food(food_x, food_y, food_style)
class Point:
x, y = 0, 0
def __init__(self, x, y):
self.x, self.y = x, y
def __str__(self):
return "(x=%d, y=%d)" % (self.x, self.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
class Direction:
UP, DOWN, LEFT, RIGHT = Point(0, 1), Point(0, -1), Point(-1, 0), Point(1, 0)
class Snake:
snake = None
# 初始化蛇,依赖一个双端队列,每次蛇进食都是在蛇头部,即队列右边append一个point
# (0,0) (1,0) (2.0) 坐标轴为自然坐标轴
def __init__(self):
self.snake = deque()
self.snake.append(Point(0, 0))
self.snake.append(Point(1, 0))
self.snake.append(Point(2, 0))
def __str__(self):
info = '遍历蛇节点,从尾到头依次输出如下\n'
it = iter(self.snake)
for x in it:
info += x.__str__() + ' '
return info
def get_head(self):
return self.snake[self.snake.__len__() - 1]
def move(self, pos):
head = self.get_head()
new_head = Point(head.x + pos.x, head.y + pos.y)
if (0 <= new_head.x <= W_MULTIPLE - 1 and 0 <= new_head.y <= H_MULTIPLE - 1
and new_head not in self.snake):
self.snake.append(new_head)
self.snake.popleft()
return True
return False
def eat_food(self, pos, food):
head = self.get_head()
new_head = Point(head.x + pos.x, head.y + pos.y)
if food == new_head:
self.snake.append(new_head)
print('吃到食物啦:%s' % new_head)
return True
return False
# 画蛇,注意这里坐标选定及边框宽度的问题
def print_self(self, screen):
paint_game_bg(screen)
for point in self.snake:
x = point.x * SIZE + point.x * LINE_WIDTH + LINE_WIDTH
y = SCREEN_HEIGHT - (point.y * SIZE + SIZE) - point.y * LINE_WIDTH - LINE_WIDTH
w, h = SIZE, SIZE
# rect参数为((x, y, width, height))
pygame.draw.rect(screen, SNAKE_COLOR, (x, y, w, h), 0)
def paint(screen, snake, food):
paint_game_bg(screen)
snake.print_self(screen)
food.print_self(screen)
def main():
# 初始化pygame
pygame.init()
# 初始化屏幕画布
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 初始化标题
pygame.display.set_caption('贪吃蛇')
# 初始化游戏背景
paint_game_bg(screen)
# 初始化蛇
snake = Snake()
snake.print_self(screen)
# 初始化食物
food = Food.create_random_food(snake)
food.print_self(screen)
# 初始化方向
pos = Direction.RIGHT
# 输入锁, 当值为true是才接收输入,有待后续完善
# lock = False
# 系统参数
game_over = False
pause = False
last_move_time = time.time()
while True:
for event in pygame.event.get():
# 当点击关闭窗口时触发
if event.type == QUIT:
sys.exit()
# 键盘事件
elif event.type == KEYDOWN:
# 回车键
if event.key == K_RETURN:
# 如果游戏结束,则初始化数据,从新开始
if game_over:
print('再来一盘')
game_over = False
snake = Snake()
food = Food.create_random_food(snake)
pos = Direction.RIGHT
last_move_time = time.time()
# 空格键暂停游戏
elif event.key == K_SPACE:
if not game_over:
print('暂停/恢复游戏')
pause = not pause
# 断绝后面的输键值入
if pause:
continue
# w键或W键或上方向键
if event.key in (K_w, K_UP):
# 如果不是y轴向下,则方向为y轴向上,下同
if pos != Direction.DOWN:
pos = Direction.UP
elif event.key in (K_s, K_DOWN):
if pos != Direction.UP:
pos = Direction.DOWN
elif event.key in (K_a, K_LEFT):
if pos != Direction.RIGHT:
pos = Direction.LEFT
elif event.key in (K_d, K_RIGHT):
if pos != Direction.LEFT:
pos = Direction.RIGHT
# 使按键效果明显
if snake.eat_food(pos, food):
food = Food.create_random_food(snake)
elif snake.move(pos):
pass
elif not game_over:
game_over = True
print('Game Over')
# 就不使用线程了,依靠时间差来判定移动,这一步可能会存在误判
now_time = time.time()
if not game_over and not pause:
if now_time - last_move_time > ORIGIN_SPEED:
if snake.eat_food(pos, food):
food = Food.create_random_food(snake)
elif snake.move(pos):
pass
elif not game_over:
game_over = True
print('Game Over')
last_move_time = now_time
paint(screen, snake, food)
pygame.display.update()
if __name__ == '__main__':
main()
总访问次数: 379次, 一般般帅 创建于 2019-07-29, 最后更新于 2020-06-25
欢迎关注微信公众号,第一时间掌握最新动态!