热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python+pygame实现多线程的贪吃蛇游戏

本游戏是在http:www.csdn.netarticle2013-05-022815101多线程的Python教程——“贪吃蛇”基础上改编而来,原教程里只实现了多个蛇在跑,然而不

本游戏是在http://www.csdn.net/article/2013-05-02/2815101多线程的 Python 教程——“贪吃蛇”基础上改编而来,原教程里只实现了多个蛇在跑,然而不能吃东西。本在添加了生成苹果的程序,且加了向苹果靠近的算法。此程序须看原教程的简介,在看本文的代码简介,才能明白。

具体可以参考一下步骤学习:

1)看原教程http://www.csdn.net/article/2013-05-02/2815101

2)懂了之后看本文的源码

 

# Threadworms (a Python/Pygame threading demonstration)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/blog
# Released under a "Simplified BSD" license
# This is meant to be an educational example of multithreaded programming,
# so I get kind of verbose in the comments.
import random, pygame, sys, threading
from pygame.locals import *
# Setting up constants
NUM_WORMS = 3 # the number of worms in the grid
FPS = 30 # frames per second that the program runs
CELL_SIZE = 20 # how many pixels wide and high each "cell" in the grid is
CELLS_WIDE = 32 # how many cells wide the grid is
CELLS_HIGH = 24 # how many cells high the grid is
# Create the global grid data structure. GRID[x][y] contains None for empty
# space or an RGB triplet. The grid is the shared data structure that the worms
# write data to, and since each worm runs in a separate thread we will have to
# add locks so that the worms don't step over each other when checking and
# updating the values in this shared data structure.
#
# If we were not using threads, then it would be impossible for the worms
# to step over each other since their code would always be executing in
# normal order. (But then our program wouldn't be multithreaded.)
GRID = []
for x in range(CELLS_WIDE):
GRID.append([None] * CELLS_HIGH)
GRID_LOCK = threading.Lock() # pun was not intended
# Constants for some colors.
# R G B
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
DARKGRAY = ( 40, 40, 40)
BGCOLOR = BLACK # color to use for the background of the grid
GRID_LINES_COLOR = DARKGRAY # color to use for the lines of the grid
# Calculate total pixels wide and high that the full window is
WINDOWWIDTH = CELL_SIZE * CELLS_WIDE
WINDOWHEIGHT = CELL_SIZE * CELLS_HIGH
# Constants for the four cardinal directions, because a mistyped variable
# like DWON will cause an immediate NameError crash and be easy to spot. But a
# mistyped string like 'dwon' is still syntactically valid Python code, so
# it will cause bugs that might be hard to track down.
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
# Since the data structure for a worm's body segments is a list
# where the "head" is the first item in the list, we can use
# HEAD as the index.
HEAD = 0
# In queues in computer science, the "tail" often doesn't refer to the last
# item but rather *every* item after the head. So I'll use "butt" to refer
# to the index of the last body segment for a worm.
BUTT = -1 # negative indexes count from the end, so -1 will always be the last index
# A global variable that the Worm threads check to see if they should exit.
WORMS_RUNNING = True
class Worm(threading.Thread): # "Thread" is a class in the "threading" module.
def __init__(self, name='Worm', maxsize=None, color=None, speed=50):
# name can be used for debugging purposes. It will appear in any thrown exceptions so you can tell which thread crashed.
# maxsize is the length of the worm (in body segments).
# color is an RGB tuple for the worm. The darker shade is automatically calculated.
# speed is an integer of milliseconds the worm waits after moving once. 1000=move once a second, 0=move as fast as possible
threading.Thread.__init__(self) # since we are overriding the Thread class, we need to first call its __init__() method.
self.name = name
# Set the maxsize to the parameter, or to a random maxsize.
if maxsize is None:
self.maxsize = random.randint(4, 10)
# Have a small chance of a super long worm.
if random.randint(0,4) == 0:
self.maxsize += random.randint(10, 20)
else:
self.maxsize = maxsize
# Set the color to the parameter, or to a random color.
if color is None:
self.color = (random.randint(60, 255), random.randint(60, 255), random.randint(60, 255))
else:
self.color = color
# Set the speed to the parameter, or to a random number.
if speed is None:
self.speed = random.randint(20, 500) # wait time before movements will be between 0.02 and 0.5 seconds
else:
self.speed = speed
# This thread will wait until the global GRID_LOCK lock is released
# (if it is currently acquired by a different thread). If another thread
# has currently acquired the lock, the acquire() call will not return
# (i.e. it will "block") until the lock is released by that other thread.
# (There may be a queue of threads that are currently waiting to acquire
# the lock, and they might be selected to run first. In that case, we
# have to wait until _they_ call release().)
GRID_LOCK.acquire() # block until this thread can acquire the lock
# The body starts as a single segment at a random location (but make sure
# it is unoccupied.)
# As the worm begins to move, new segments will be added until it reaches full length.
while True:
startx = random.randint(0, CELLS_WIDE - 1)
starty = random.randint(0, CELLS_HIGH - 1)
if GRID[startx][starty] is None:
break # we've found an unoccupied cell in the grid
GRID[startx][starty] = self.color # modify the shared data structure
# Now that we're done modifying the data structure that is shared
# by all the threads (i.e. GRID), we can release the lock so that
# other threads can acquire it.
GRID_LOCK.release()
# The worm's body starts as a single segment, and keeps growing until it
# reaches full length. This makes setup easier.
self.body = [{'x': startx, 'y': starty}]
self.direction = random.choice((UP, DOWN, LEFT, RIGHT))
self.CREATE_APPLE = True#标记是否可以产生一个苹果
self.apple = []
def run(self):
# Note that this thread's code only updates GRID, which is the variable
# that tracks which cells have worm body segments and which are free.
# Nothing in this thread draws pixels to the screen. So we could have this
# code run separate from the visualization of the worms entirely!
#
# This means that instead of the Pygame grid display, we could write
# code that displays the worms in 3D without changing the Worm class's
# code at all. The visualization code just has to read the GRID variable
# (in a thread-safe manner by using GRID_LOCK, of course).
while True:
if not WORMS_RUNNING:
return # A thread terminates when run() returns.
# Randomly decide to change direction
#if random.randint(0, 100) <20: # 20% to change direction

# We are going to make modifications to GRID, so we need to acquire
# the lock first.
GRID_LOCK.acquire() # don't return (that is, block) until this thread can acquire the lock
#生成苹果
if self.CREATE_APPLE == True:
while True:
applex = random.randint(0,CELLS_WIDE-1)
appley = random.randint(0,CELLS_HIGH-1)
if GRID[applex][appley] is None:
self.CREATE_APPLE = False
break
if self.CREATE_APPLE == False:
GRID[applex][appley] = self.color
self.apple = list([applex,appley])
self.direction = self.getNewDirection()
# Really, we should check if nextx <0 or nextx >= CELLS_WIDE, but
# since worms only move one space at a time, we can get away with
# just checking if they are at -1 or CELLS_WIDE/CELLS_HIGH.
if self.direction is None:
# No places to move, so try reversing our worm.
self.body.reverse() # Now the head is the butt and the butt is the head. Magic!
self.direction = self.getNewDirection()
if self.direction is not None:
# It is possible to move in some direction, so reask for the next postion.
nextx, nexty = self.getNextPosition()
# Space on the grid is free, so move there.
#如果下一个位置是苹果,则吃掉,且把产生苹果的标志位设为True,以便再产生苹果
if (nextx == self.apple[0]) and (nexty == self.apple[1]):
self.body.insert(0, {'x': nextx, 'y': nexty})
self.CREATE_APPLE = True
if len(self.body) > self.maxsize:
GRID[self.body[BUTT]['x']][self.body[BUTT]['y']] = None # update the GRID state
del self.body[BUTT] # update this worm's own state (heh heh, worm butt)
else:
GRID[nextx][nexty] = self.color # update the GRID state
self.body.insert(0, {'x': nextx, 'y': nexty}) # update this worm's own state
GRID[self.body[BUTT]['x']][self.body[BUTT]['y']] = None # update the GRID state
del self.body[BUTT] # update this worm's own state (heh heh, worm butt)
# On a technical note, a worm could get stuck inside itself if its
# head and butt are in this pattern:
#
# With lines: Where "A" is the head and "L" is the butt:
# /\/\ CBKJ
# |HB| DALI
# \--/ EFGH
# I call this a worm knot. I left my computer running with 24 worms
# moving with 0 speed overnight, but I didn't see any of these worm
# knots form, so I'm guessing it is super rare.
# Done modifying GRID, so release the GRID_LOCK lock.
GRID_LOCK.release()
# Pygame's pygame.time.wait() and the Python Standard Library's
# time.time() functions (and the tick() method) are smart enough
# to tell the operating system to put the thread to sleep for a
# while and just run other threads instead. Of course, while the
# OS could interrupt our thread at any time to hand execution off
# to a different thread, calling wait() or sleep() is a way we can
# explicitly say, "Go ahead and don't run this thread for X
# milliseconds."
#
# This wouldn't happen if we have "wait" code like this:
# startOfWait = time.time()
# while time.time() - 5 > startOfWait:
# pass # do nothing for 5 seconds
#
# The above code also implements "waiting", but to the OS it looks
# like your thread is still executing code (even though this code
# is doing nothing but looping until 5 seconds has passed).
# This is inefficient, because time spent executing the above pointless
# loop is time that could have been spent executing other thread's
# code.
# Of course, if ALL worms' threads are sleeping, then the computer
# can know it can use the CPU to run other programs besides
# our Python Threadworms script.
pygame.time.wait(self.speed)
# The beauty of using multiple threads here is that we can have
# the worms move at different rates of speed just by passing a
# different integer to wait().
# If we did this program in a single thread, we would have to
# calculate how often we update the position of each worm based
# on their speed relative to all the other worms, which would
# be a headache. But now we have the threads doing this work
# for us!
def getNextPosition(self):
# Figure out the x and y of where the worm's head would be next, based
# on the current position of its "head" and direction member.
#根据前进的方向,计算出下一个点
if self.direction == UP:
nextx = self.body[HEAD]['x']
nexty = self.body[HEAD]['y'] - 1
elif self.direction == DOWN:
nextx = self.body[HEAD]['x']
nexty = self.body[HEAD]['y'] + 1
elif self.direction == LEFT:
nextx = self.body[HEAD]['x'] - 1
nexty = self.body[HEAD]['y']
elif self.direction == RIGHT:
nextx = self.body[HEAD]['x'] + 1
nexty = self.body[HEAD]['y']
else:
assert False, 'Bad value for self.direction: %s' % self.direction
# Remember that nextx & nexty could be invalid (by referring to a location
# on the grid already taken by a body segment or beyond the boundaries
# of the window.)
return nextx, nexty
def getNewDirection(self):
x = self.body[HEAD]['x'] # syntactic sugar, makes the code below more readable
y = self.body[HEAD]['y']
# Compile a list of possible directions the worm can move.
newDirection = []#可以移动的方向
bestDirection = []#可以移动的且向苹果靠拢的方向

if y - 1 not in (-1, CELLS_HIGH) and (GRID[x][y - 1] is None or \
(x == self.apple[0] and y-1 == self.apple[1])):
newDirection.append(UP)
if self.apple[1] - y <0:
bestDirection.append(UP)
if y + 1 not in (-1, CELLS_HIGH) and (GRID[x][y + 1] is None or \
(x == self.apple[0] and y+1 == self.apple[1])):
newDirection.append(DOWN)
if self.apple[1] - y > 0:
bestDirection.append(DOWN)
if x - 1 not in (-1, CELLS_WIDE) and (GRID[x - 1][y] is None or \
(x-1 == self.apple[0] and y == self.apple[1])):
newDirection.append(LEFT)
if self.apple[0] - x <0:
bestDirection.append(LEFT)
if x + 1 not in (-1, CELLS_WIDE) and (GRID[x + 1][y] is None or \
(x+1 == self.apple[0] and y == self.apple[1])):
newDirection.append(RIGHT)
if self.apple[0] - x > 0:
bestDirection.append(RIGHT)


if newDirection == []:
return None # None is returned when there are no possible ways for the worm to move.
elif bestDirection == []:
return random.choice(newDirection)
else:
return random.choice(bestDirection)
def main():
global FPSCLOCK, DISPLAYSURF
# Draw some walls on the grid
squares = """
...........................
...........................
...........................
.H..H..EEE..L....L.....OO..
.H..H..E....L....L....O..O.
.HHHH..EE...L....L....O..O.
.H..H..E....L....L....O..O.
.H..H..EEE..LLL..LLL...OO..
...........................
.W.....W...OO...RRR..MM.MM.
.W.....W..O..O..R.R..M.M.M.
.W..W..W..O..O..RR...M.M.M.
.W..W..W..O..O..R.R..M...M.
..WW.WW....OO...R.R..M...M.
...........................
...........................
"""
#setGridSquares(squares)
# Pygame window set up.
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Threadworms')
# Create the worm objects.
worms = [] # a list that contains all the worm objects
for i in range(NUM_WORMS):
worms.append(Worm())
worms[-1].start() # Start the worm code in its own thread.
while True: # main game loop
handleEvents()
drawGrid()
pygame.display.update()
FPSCLOCK.tick(FPS)
def handleEvents():
# The only event we need to handle in this program is when it terminates.
global WORMS_RUNNING
for event in pygame.event.get(): # event handling loop
if (event.type == QUIT) or (event.type == KEYDOWN and event.key == K_ESCAPE):
WORMS_RUNNING = False # Setting this to False tells the Worm threads to exit.
pygame.quit()
sys.exit()
def drawGrid():
# Draw the grid lines.
DISPLAYSURF.fill(BGCOLOR)
for x in range(0, WINDOWWIDTH, CELL_SIZE): # draw vertical lines
pygame.draw.line(DISPLAYSURF, GRID_LINES_COLOR, (x, 0), (x, WINDOWHEIGHT))
for y in range(0, WINDOWHEIGHT, CELL_SIZE): # draw horizontal lines
pygame.draw.line(DISPLAYSURF, GRID_LINES_COLOR, (0, y), (WINDOWWIDTH, y))
# The main thread that stays in the main loop (which calls drawGrid) also
# needs to acquire the GRID_LOCK lock before modifying the GRID variable.
GRID_LOCK.acquire()
for x in range(0, CELLS_WIDE):
for y in range(0, CELLS_HIGH):
if GRID[x][y] is None:
continue # No body segment at this cell to draw, so skip it
color = GRID[x][y] # modify the GRID data structure
# Draw the body segment on the screen
darkerColor = (max(color[0] - 50, 0), max(color[1] - 50, 0), max(color[2] - 50, 0))
pygame.draw.rect(DISPLAYSURF, darkerColor, (x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE ))
pygame.draw.rect(DISPLAYSURF, color, (x * CELL_SIZE + 4, y * CELL_SIZE + 4, CELL_SIZE - 8, CELL_SIZE - 8))
GRID_LOCK.release() # We're done messing with GRID, so release the lock.
def setGridSquares(squares, color=(192, 192, 192)):
# "squares" is a multiline string that has '.' to express "no change", a
# ' ' space to set the cell to be empty, and any other character will
# set the space with the value in "color"
# Blank lines in squares are ignored for the first and last line, to make
# typing the string easier.
#
# squares is set to a value like:
# """
# ......
# ...XX.
# ...XX.
# ......
# """
squares = squares.split('\n')
if squares[0] == '':
del squares[0]
if squares[-1] == '':
del squares[-1]
GRID_LOCK.acquire()

python,pygame下载地址http://www.lfd.uci.edu/~gohlke/pythonlibs/(在比较下面的位置)    for y in range(min(len(squares), CELLS_HIGH)): for x in range(min(len(squares[y]), CELLS_WIDE)): if squares[y][x] == &#8216; &#8216;: GRID[x][y] = None elif squares[y][x] == &#8216;.&#8217;: pass else: GRID[x][y] = color GRID_LOCK.release()main()

地址http://www.lfd.uci.edu/~gohlke/pythonlibs/网站上包含了几乎关于python所有的软件


推荐阅读
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • SmartRefreshLayout自定义头部刷新和底部加载
    1.添加依赖implementation‘com.scwang.smartrefresh:SmartRefreshLayout:1.0.3’implementation‘com.s ... [详细]
  • 湍流|低频_youcans 的 OpenCV 例程 200 篇106. 退化图像的逆滤波
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了youcans的OpenCV例程200篇106.退化图像的逆滤波相关的知识,希望对你有一定的参考价值。 ... [详细]
author-avatar
那朵逆风的蔷薇_708
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有