pygame的贪吃蛇,一次投递多个食物,默认画布15*15,一次投递20个食物,食物之间、食物与蛇之间不会重叠。当方块总数 - 蛇身长度 - 食物个数 < 20时,判断玩家胜利。有生之年终于可以看到贪吃蛇的结局了!
本版本的贪吃蛇Snake、Food和World均独立于具体库,稍作修改可成为命令行版本的贪吃蛇,也可迁移到其他引擎中。
# -*- coding: utf-8 -*-
"""
Created on Tue May 16 07:24:28 2017
@author: zbg
"""
import pygame
from pygame.locals import *
from random import randint, choice, shuffle
class Map(dict):
def __init__(self, w, h):
dict.__init__(self)
self.w = w
self.h = h
self.clear()
def __str__(self):
s = ''
for j in range(self.h):
for i in range(self.w):
s += self[(i, j)]
s += '\n'
return s
def clear(self):
for i in range(self.w):
for j in range(self.h):
self[(i, j)] ='.'
class Food(object):
def __init__(self, world, n = 1):
self.n = n #一次产生n个食物
self.m = world.m
self.world = world
self.w = self.m.w
self.h = self.m.h
self.locations = {}#用字典是为了吃食物时方便删除
def generate(self):#由外部world调用,维持n个食物
space = []#除开蛇以外的地方的坐标
for i in range(self.w):
for j in range(self.h):
if (i, j) not in self.world.snake.body:
space.append((i, j))
shuffle(space)
while len(self.locations) < self.n:
self.locations[space[-1]] = 1 #后面的值1并没有意义。
del space[-1]
def draw(self):
for l in self.locations:
self.m[l] = 'o'
class Snake(object):
'''
蛇做一些简单的移动、计算和绘制
改变移动方向交给外部的World来处理
'''
def __init__(self, world):
self.world = world
self.m = world.m
self.h = self.m.h
self.w = self.m.w
self.direction = "left" #
self.state = 'alive' # 'alive' or 'dead'
cw, ch = self.w / 2, self.h / 2
self.body = [(cw, ch), (cw + 1, ch), (cw + 2, ch)]
def draw(self):
for b in self.body:
self.m[b] = 'x'
def newhead(self):
headw, headh = self.body[0]
newheadw, newheadh = headw, headh
if self.direction == "left":
newheadw = headw - 1
elif self.direction == "right":
newheadw = headw + 1
elif self.direction == "up":
newheadh = headh - 1
elif self.direction == "down":
newheadh = headh + 1
return newheadw, newheadh
def move(self):
x, y = self.newhead()
if len(self.body) + self.world.food.n + 20 > self.w * self.h:
print "fine, you win!!"
elif x == -1 or y == -1 or x == self.w or y == self.h:
print "error, dead"
elif (x, y) in self.body:
print "error, dead"
elif (x, y) in self.world.food.locations:
self.body = [self.newhead()] + self.body[:]
del world.food.locations[(x, y)]
else:
self.body = [self.newhead()] + self.body[0: -1]
def changedirection(self, direction):
self.direction = direction
class World(object):
def __init__(self, w, h):
self.m = Map(w, h)
self.snake = Snake(self)
self.food = Food(self, 20)
self.w, self.h = w, h
def run(self):
self.food.generate()
self.m.clear()
self.snake.move()
self.food.draw()
self.snake.draw()
def show(screen, m):
for i in range(m.w):
for j in range(m.h):
if m[(i, j)] == 'x':
r = pygame.Rect(i * unit, j * unit, unit, unit)
pygame.draw.rect(screen,(136,0,21),r,0)
elif m[(i, j)] == 'o':
r = pygame.Rect(i * unit, j * unit, unit, unit)
pygame.draw.rect(screen,(0,174,21),r,0)
h = 15
w = 15
unit = 30
SCREEN_SIZE = (w * unit, h * unit)
DIRECTION = {pygame.K_UP: 'up', pygame.K_DOWN: "down", pygame.K_LEFT: "left", pygame.K_RIGHT:"right"}
world = World(15,15)
clock = pygame.time.Clock()
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit(0)
if event.type == pygame.KEYDOWN:
if event.key in DIRECTION:
direction = DIRECTION[event.key]
if direction in ['up', 'down'] and world.snake.direction in ['up', 'down']:
pass
elif direction in ['left', 'right'] and world.snake.direction in ['left', 'right']:
pass
else:
world.snake.changedirection(direction)
screen.fill((255,255,255))
world.run()
show(screen, world.m)
pygame.display.update()
print world.m
clock.tick(3)