# pygame写贪吃蛇

2018-02-24 07:51:36来源:cnblogs.com作者:ansver人点击

python小白尝试写游戏..

• 数据(变量)
• 处理数据(函数,方法)

`import pygameimport syspygame.init()screen = pygame.display.set_mode((800, 600))pygame.display.set_caption("贪吃蛇")food = (4, 5)body = [(1, 1),(1,2)]head = (1, 3)BLOCK = 0, 0, 0GREEN = 0, 255, 0RED = 255, 0, 0BLUE = 0, 0, 255WHITE = 255, 255, 255while 1:    for event in pygame.event.get():        if event.type == pygame.QUIT:            sys.exit()`

pygame.draw.rect()是根据矩形四元数组绘制图像的,那就写个函数"对接"下我的二元坐标

`def new_draw_rect(zb, color,screen):    pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))`

`...while 1:    for event in pygame.event.get():        if event.type == pygame.QUIT:            sys.exit()    screen.fill(WHITE)    new_draw_rect(food, RED, screen)    for i in body:        new_draw_rect(i, BLUE, screen)    new_draw_rect(head, GREEN, screen)        pygame.display.update()`

由静到动

两个问题:

1.什么时候动

2.怎么动

• 间隔固定时间(1秒),动一次
• 按一次键动一次,无操作一定时间(1秒)后,重复最后一次操作

PS:程序结束之前,很难知道要用多少变量

`import pygameimport syspygame.init()screen = pygame.display.set_mode((800, 600))pygame.display.set_caption("贪吃蛇")fclock = pygame.time.Clock()food = (4, 5)body = [(1, 1)]head = (1, 2)times = 0direction = 'right'BLOCK = 0, 0, 0GREEN = 0, 255, 0RED = 255, 0, 0BLUE = 0, 0, 255WHITE = 255, 255, 255def new_draw_rect(zb, color,screen):    pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))    passwhile 1:    for event in pygame.event.get():        if event.type == pygame.QUIT:            sys.exit()        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                direction = "up"            elif event.key == pygame.K_LEFT:                direction = "left"            elif event.key == pygame.K_DOWN:                direction = "down"            elif event.key == pygame.K_RIGHT:                direction = "right"    if times >= 100:        pass#动一动        times = 0    else:        times += 1    screen.fill(WHITE)    new_draw_rect(food, RED, screen)    for i in body:        new_draw_rect(i, BLUE, screen)    new_draw_rect(head, GREEN, screen)    fclock.tick(100)    pygame.display.update()`

蛇头的运动规律 : 向临近的格子移动,上下左右具体那个格子由键盘确定

`def get_front(head,direction):    x, y = head    if direction == "up":        return x-1, y    elif direction == "left":        return x, y-1    elif direction == "down":        return x+1, y    elif direction == "right":        return x, y+1`

PS:front可以不是全局变量

`def ask_alive(front,body):    x, y = front    if x < 0 or x > 12 or y < 0 or y >16 :        return False    if front in body:        return False    return True`

if alive:

`    if times >= 100 and alive:        front = get_front(head,direction)        alive = ask_alive(front,body)        if alive:            body.append(head)            head = front            body.pop(0)        times = 0    else:        times += 1`

`def new_food(head,body):    while 1:        x = random.randint(1, 12)        y = random.randint(1, 16)        if (x, y) != head and (x, y) not in body:            return x, y`

`def new_food(head,body):    i = 0    while i < 100:        x = random.randint(1, 12)        y = random.randint(1, 16)        if (x, y) != head and (x, y) not in body:            return (x, y), True        i += 1    else:        return (0, 0), Falsefood, alive = new_food()`

100次机会 否则就死(￣へ￣)     --来自开发者的恶意

`        if alive:            body.append(head)            head = front            if food == head:                food = new_food(head, body)            else:                body.pop(0)`

1,

back_color一开始等于WHITE , alive为假时变为BLOCK

`    if times >= 100 and alive:        front = get_front(head, direction)        alive = ask_alive(front, body)        if alive:            body.append(head)            head = front            if food == head:                food, alive = new_food(head, body)            else:                body.pop(0)        else:            back_color = BLOCK            pygame.display.set_caption("游戏结束")        times = 0    else:        times += 1`

2,

`old_direction = "right"def direction_yes_no(direction,old_direction):    d = {"up": "down", "down": "up", "left": "right", "right": "left"}    if d[direction] == old_direction:        return old_direction    return direction`

PS : 字典代替if-elif结构省心省时

`　　if times >= 100 and alive:        direction = direction_yes_no(direction, old_direction)        old_direction = direction        front = get_front(head, direction)        alive = ask_alive(front, body)`

Q : direction也可以在按键事件处理时限制呀,例如

`        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                direction = "up"                   """改为"""        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                if direction != "down"                    direction = "up"`

A:在发现这个方法的BUG之前,我也是这样想的

3,

Q : 我要暂停!!!

A : 好好玩游戏,不要动不动就暂停

`pause = False            elif event.key == pygame.K_p:                pause = not pause    if times >= 100 and alive and (not pause):    ....`

↓↓↓↓

`import pygameimport sysimport randompygame.init()screen = pygame.display.set_mode((800, 600))pygame.display.set_caption("贪吃蛇")fclock = pygame.time.Clock()food = (4, 5)body = [(1, 1)]head = (1, 2)times = 0direction = "right"old_direction = "right"alive = Truepause = FalseBLOCK = 0, 0, 0GREEN = 0, 255, 0RED = 255, 0, 0BLUE = 0, 0, 255WHITE = 255, 255, 255back_color = WHITEdef new_draw_rect(zb, color,screen):    pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))def get_front(head, direction):    x, y = head    if direction == "up":        return x-1, y    elif direction == "left":        return x, y-1    elif direction == "down":        return x+1, y    elif direction == "right":        return x, y+1def ask_alive(front, body):    x, y = front    if x < 0 or x > 12 or y < 0 or y >16 :        return False    if front in body:        return False    return Truedef new_food(head, body):    i = 0    while i < 100:        x = random.randint(1, 12)        y = random.randint(1, 16)        if (x, y) != head and (x, y) not in body:            return (x, y), True        i += 1    else:        return (0, 0), Falsedef direction_yes_no(direction, old_direction):    d = {"up": "down", "down": "up", "left": "right", "right": "left"}    if d[direction] == old_direction:        return old_direction    return direction#food = new_food(head,body)while 1:    for event in pygame.event.get():        if event.type == pygame.QUIT:            sys.exit()        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                direction = "up"            elif event.key == pygame.K_LEFT:                direction = "left"            elif event.key == pygame.K_DOWN:                direction = "down"            elif event.key == pygame.K_RIGHT:                direction = "right"            elif event.key == pygame.K_p:                pause = not pause    if times >= 100 and alive and (not pause):        direction = direction_yes_no(direction, old_direction)        old_direction = direction        front = get_front(head, direction)        alive = ask_alive(front, body)        if alive:            body.append(head)            head = front            if food == head:                food, alive = new_food(head, body)            else:                body.pop(0)        else:            back_color = BLOCK            pygame.display.set_caption("游戏结束")        times = 0    else:        times += 1    screen.fill(back_color)    new_draw_rect(food, RED, screen)    for i in body:        new_draw_rect(i, BLUE, screen)    new_draw_rect(head, GREEN, screen)    fclock.tick(100)    pygame.display.update()`

↑↑↑↑

↑↑↑↑

↑↑↑↑

4,

Q : 游戏结束或者暂停后因为times >= 100 and alive and (not pause)始终为假

times += 1 一直运行,,,,会不会不太妥当

A : 又不会溢出,,,,,,,,取消暂停时蛇能迅速跑起来要是time==100那问题就大了,,幸亏当初留了些余地写成 >=

(～￣▽￣)～

5,

Q : 蛇跑的太慢我想加速

A : 上面的times>=100的100随便改一下就行

0->100动一动   变成    0->80 动一动

0->100动一动   变成    20->100动一动

6,

direction那里可以使用0,1,2,3

7,

Q : 第一个food的位置是固定的,不能"动"吗?

A : 因为我是先定义变量,再定义函数

• 间隔固定时间(1秒),动一次
• 按一次键动一次,无操作一定时间(1秒)后,重复最后一次操作

`    if event.key == pygame.K_UP:        direction = "up"        times = 100    elif event.key == pygame.K_LEFT:        direction = "left"        times = 100  `

while循环当轮就能动一动

pygame : 我得跑完事件列表的每个元素

`    if event.key == pygame.K_UP:        direction = "up"        '动一动'    elif event.key == pygame.K_LEFT:        direction = "left"        '动一动'`

`    if times >= 100 and alive and (not pause):        direction = direction_yes_no(direction, old_direction)        old_direction = direction        front = get_front(head, direction)        alive = ask_alive(front, body)        if alive:            body.append(head)            head = front            if food == head:                food, alive = new_food(head, body)            else:                body.pop(0)        else:            back_color = BLOCK            pygame.display.set_caption("游戏结束")        times = 0    else:        times += 1`

"动一动"前还得加上if alive and (not pause):

times没必要加

Q : 不知道你是不是记得我,优化2就是我问的.....是这样的,我对我的方法还不死心...."动手术"改第二方案后能用吗?

`        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                direction = "up"                   """改为"""        elif event.type == pygame.KEYDOWN:            if event.key == pygame.K_UP:                if direction != "down"                    direction = "up"`

A : 对于第一方法实现的第二方案还是会有小毛病

while循环当轮就能动一动

pygame : 我得跑完事件列表的每个元素

完结撒花✿✿ヽ(°▽°)ノ✿

Q : 我想在加宽屏幕在右侧显示一下时间分数之类的信息,你还有什么"交待"吗?

A : 在pygame显示字体比较有难度....我只能祝你程序不出BUG...另外点(800,0)到点(800,600)别忘了画到线,提醒玩家"边界"还是存在的,让玩家摔键盘动怒就不好了

Q : 我就是对你的颜色搭配有意见,颜色有点扎眼....

A : 我又不是美工,,,,,,,,,,,,颜色搭配的问题,应该,,,,,,,,,应该可以原谅,,,,,,,,,,

Q : 游戏太没挑战性,加点障碍物呗~~