• 第一个python+pygame小游戏


    没有周队那么有情调,自己写故事做rpg,又没什么绘画功底,只能做这样的休闲棋类游戏。本来是用java写的,但里面绘图太麻烦了(或者说我不会多线程),又想起前几天看到的pygame,于是果断python搞起了,从安装pygame,连学代做,到基本功能完成一共也不过两三个小时(小自恋一下~),又花了一个下午时间调整修正,终于可以拿出手了~~

    五子连珠是老妈最喜欢的游戏了,移动棋子使五个棋子在一条线上即可消去;移动后如果没有消去任何棋子,则会随机落下几颗棋子;另外移动时要保证起点和重点之间存在一条没有棋子的路径;如果棋盘满了则游戏结束,否则... 没有否则,没有胜利条件,就刷分数

    自己ps的图片太土了,干脆全用程序绘图,不用任何图片,所以看起来很简陋,使用的颜色是office上的推荐色,还算和谐(Hard难度凑不齐8种颜色,就自己调了两个,看起来好怪),棋子圆形锯齿消不掉,就那样好了,也就这些了......

    游戏界面

      

    项目包含两个文件,Row5.py 和 Game.py,Game.py里有两个类,一个是Core内核类,控制游戏棋子信息什么的,一个Draw类,绘制游戏的相关信息,Row5.py是主文件,调用两个类实现游戏,下面代码+注释,中文注释可能会编译出错,看网上的方法改一下编码好了

    Row5.py

    View Code
      1 '''
    2 Created on 2011-12-19
    3
    4 @author: Amb
    5 '''
    6
    7 #Row5.py
    8
    9 import pygame
    10 import Game
    11
    12 #初始化pygame
    13 pygame.init()
    14
    15 #初始化游戏
    16 def initgame(size,coln,fdropn,dropn):
    17 global game,draw,menu_pos
    18 game = Game.Core(size,coln,fdropn,dropn) #建立内核类
    19 draw = Game.Draw(size,dropn) #建立绘图类
    20 game.initcore() #初始化内核类
    21 menu_pos=draw.initdraw(game) #初始化绘图类
    22
    23 #点击方格后执行该函数
    24 def run(pos):
    25 global fclick,over
    26 global start_pos,target_pos
    27 if pos[0] >= lx or pos[1] >= ly: return #不在棋盘范围内,跳出
    28 if fclick: #如果是第一次点击
    29 if game.getcolor(pos) != -1: #如果有棋子,则标记第一颗棋子
    30 start_pos = pos
    31 fclick = False
    32 draw.circle(start_pos,game.getcolor(start_pos),1) #高亮该棋子
    33 else: #否则第二次点击
    34 if game.getcolor(pos) != -1: #如果第二次点击仍然是有棋子的格子
    35 if pos == start_pos: #如果和第一次是同一个棋子,则取消选择
    36 fclick = True
    37 draw.circle(start_pos,game.getcolor(start_pos))
    38 else: #否则切换第一颗棋子到当前棋子
    39 pre = start_pos
    40 draw.circle(pre,game.getcolor(pre),0)
    41 start_pos = pos
    42 draw.circle(start_pos,game.getcolor(start_pos),1)
    43 else: #没棋子
    44 target_pos = pos
    45 path = game.getpath(start_pos, target_pos) #得到路径
    46 if path != []: #路径不为空,可以到达,则沿途绘制棋子移动动画
    47 col = game.getcolor(target_pos)
    48 draw.path(start_pos,path,col)
    49 clock.tick(40)
    50 else: return #为空说明不能到达,直接返回
    51 fclick = True
    52 clear_arr = game.clearmap() #检查棋盘有没有可以消去的棋子
    53 if clear_arr == []: #为空,则随机落子
    54 fill_arr = game.fillcolors() #形参为空,为tip颜色随机位置,返回位置和颜色
    55 for tfill in fill_arr:
    56 draw.circle(tfill[0],tfill[1])
    57 game.randcolor() #形参为空,得到随机色为tip
    58 draw.tip(game.gettip()) #绘制tip
    59 clear_arr = game.clearmap() #再进行一次棋盘清除
    60 for tpos in clear_arr:
    61 draw.rectangle(tpos)
    62 else: #如果有棋子可以消去,则直接消去
    63 for tpos in clear_arr:
    64 draw.rectangle(tpos)
    65 draw.score(game.getscore()) #绘制分数
    66
    67 #行列数,颜色种类,起始时落子个数,每次落子个数
    68 lx = 10
    69 ly = 10
    70 coln = 6
    71 fdropn = 4
    72 dropn = 3
    73
    74 #初始化游戏为默认值
    75 initgame([lx,ly],coln,fdropn,dropn)
    76 #一些标记清空
    77 fclick = True
    78 over = False
    79 pause = False
    80 level_pos = []
    81
    82 #控制刷新频率
    83 clock = pygame.time.Clock()
    84
    85 end = False
    86 while end == False:
    87 clock.tick(30) #间隔刷新次数,如果配置较低,玩起来比较卡,就设置的高一些
    88 for event in pygame.event.get():
    89 if event.type == pygame.QUIT: end = True #退出命令
    90 if event.type == pygame.MOUSEBUTTONDOWN: #没判断鼠标键,所以中键,右键点击都是有效的
    91 point = pygame.mouse.get_pos() #点击位置
    92 if pause: #如果是在选择难度状态,那么只判断点击地方是否是按钮
    93 if pygame.Rect(level_pos[0]).collidepoint(point): #取消选择
    94 draw.initdraw(game) #重新把之前的状态绘出来
    95 pause = False
    96 continue
    97 #下面是三种难度
    98 elif pygame.Rect(level_pos[1]).collidepoint(point):
    99 lx = 10
    100 ly = 10
    101 fdropn = 4
    102 coln = 5
    103 dropn = 3
    104 pause = False
    105 over = True
    106 elif pygame.Rect(level_pos[2]).collidepoint(point):
    107 lx = 12
    108 ly = 12
    109 fdropn = 4
    110 coln = 6
    111 dropn = 4
    112 pause = False
    113 over = True
    114 elif pygame.Rect(level_pos[3]).collidepoint(point):
    115 lx = 16
    116 ly = 16
    117 fdropn = 4
    118 coln = 8
    119 dropn = 4
    120 pause = False
    121 over = True
    122 else: continue
    123 #如果游戏结束,或者点击了Start,则重新开始游戏
    124 if over or pygame.Rect(menu_pos[0]).collidepoint(point):
    125 game.updatascore() #关之前把最高分保存了
    126 initgame([lx,ly],coln,fdropn,dropn)
    127 over = False
    128 fclick = True
    129 continue
    130 elif pygame.Rect(menu_pos[1]).collidepoint(point): #level,进入level菜单
    131 pause = True
    132 level_pos=draw.level()
    133 game.updatascore()
    134 elif pygame.Rect(menu_pos[2]).collidepoint(point): #Exit,退出
    135 end = True
    136 else: #否则的话就去run一下
    137 pos = draw.getpos(point)
    138 run(pos)
    139 if game.isover(): #游戏结束,退出,并保存最高分
    140 over = True
    141 draw.over()
    142 game.updatascore()
    143
    144 game.updatascore()
    145 #退出pygame
    146 pygame.quit()

      

    两个类

    View Code
      1 '''
    2 Created on 2011-12-19
    3
    4 @author: Amb
    5 '''
    6
    7 #Game.py
    8
    9 import pygame
    10 import struct
    11 import random
    12 import os
    13 import Queue
    14
    15 class Core:
    16 #根据传入信息,初始化内核类
    17 def __init__(self,size,coln,fdropn,dropn):
    18 self.lx = size[0]
    19 self.ly = size[1]
    20 self.coln=coln
    21 self.fdropn=fdropn
    22 self.dropn=dropn
    23 self.map = [[-1 for y in range(self.ly)] for x in range(self.lx)]
    24 self.score = 0
    25 self.empty = self.lx*self.ly
    26 self.tip = []
    27
    28 if coln == 5: self.level = 0
    29 elif coln == 6: self.level = 1
    30 elif coln == 8: self.level = 2
    31
    32 self.topscore = self.readdata()
    33
    34 #得到某一个位置的颜色信息
    35 def getcolor(self,pos):
    36 return self.map[pos[0]][pos[1]]
    37
    38 #得到分数,返回[当前分,最高分]
    39 def getscore(self):
    40 return [self.score,self.topscore]
    41
    42 #返回游戏是否已经结束
    43 def isover(self):
    44 if self.empty == 0: return True
    45 else: return False
    46
    47 #返回下一组颜色提示信息,[col......]
    48 def gettip(self):
    49 return self.tip
    50
    51 #返回num个随机颜色,如果未传入参数,则随机出tip个数,并赋值给类的tip数组
    52 def randcolor(self,num = -1):
    53 if num == -1: cnt = self.dropn
    54 else: cnt = num
    55 col = []
    56 for i in range(cnt):
    57 col.append(random.randint(0,self.coln-1))
    58 if num == -1: self.tip = col
    59 return col
    60
    61 #填充颜色到一个随机位置,返回位置信息
    62 def fill(self,col):
    63 if self.empty==0: return [];
    64 while True:
    65 rx = random.randint(0,self.lx-1)
    66 ry = random.randint(0,self.ly-1)
    67 if self.map[rx][ry] == -1:
    68 self.map[rx][ry] = col
    69 self.empty-=1
    70 return [rx,ry]
    71
    72 #填充一个颜色数组,返回[[位置,颜色]...]信息
    73 def fillcolors(self,col=[]):
    74 if col == []: col = self.tip
    75 fillarray = []
    76 for i in col:
    77 tpos = self.fill(i)
    78 if tpos == []: return fillarray
    79 else: fillarray.append([tpos,i])
    80 return fillarray
    81
    82 #写入文件最高分数,如果没有传参,则初始化文件
    83 def writedata(self,score=-1):
    84 try:
    85 if score == -1:
    86 fout = open('game.dat','wb')
    87 _bytes = struct.pack('iii',0,0,0)
    88 fout.write(_bytes)
    89 fout.close()
    90 else:
    91 fin = open('game.dat','rb')
    92 _bytes = fin.read()
    93 fin.close()
    94 val = [0,0,0]
    95 val[0],val[1],val[2] = struct.unpack('iii',_bytes)
    96 #不知道这个地方为什么用元组取出来不能赋值
    97 val[self.level] = score
    98 _bytes = struct.pack('iii',val[0],val[1],val[2])
    99 fout = open('game.dat','wb')
    100 fout.write(_bytes)
    101 fout.close()
    102 except IOError:
    103 print 'IOError'
    104
    105 #读取文件信息,如果不存在文件,则建立文件
    106 def readdata(self):
    107 try:
    108 fin = open('game.dat','rb')
    109 _bytes = fin.read()
    110 fin.close()
    111 val=struct.unpack('iii',_bytes)
    112 return val[self.level]
    113 except:
    114 self.writedata()
    115 return 0
    116
    117 #更新最高分数
    118 def updatascore(self):
    119 self.writedata(self.topscore)
    120
    121 #初始化内核:包括第一次填充颜色,和随机出下一步tip
    122 def initcore(self):
    123 self.fillcolors(self.randcolor(self.fdropn))
    124 self.randcolor()
    125
    126 #得到移动路径,如果不能移动,返回[]
    127 def getpath(self,spos,tpos):
    128 pre = [[[-1,-1] for y in range(self.ly)] for x in range(self.lx)]
    129 _dir = [[1,0],[0,1],[-1,0],[0,-1]]
    130 que = Queue.Queue();
    131 que.put(spos)
    132 pre[spos[0]][spos[1]] = [-2,-2];
    133 while que.empty() == False:
    134 upos = que.get()
    135 for i in range(4):
    136 vpos = [upos[0]+_dir[i][0],upos[1]+_dir[i][1]]
    137 if vpos[0] < 0 or vpos[0] >= self.lx: continue
    138 if vpos[1] < 0 or vpos[1] >= self.ly: continue
    139 if self.map[vpos[0]][vpos[1]] != -1: continue
    140 if pre[vpos[0]][vpos[1]][0] != -1: continue
    141 pre[vpos[0]][vpos[1]] = upos
    142 if vpos == tpos:
    143 vx = vpos[0]
    144 vy = vpos[1]
    145 path = [[vx,vy]]
    146 while pre[vx][vy][0]!=-2:
    147 path.append(pre[vx][vy])
    148 vx=pre[vpos[0]][vpos[1]][0]
    149 vy=pre[vpos[0]][vpos[1]][1]
    150 vpos = [vx,vy]
    151 path.reverse()
    152
    153 self.map[tpos[0]][tpos[1]]=self.map[spos[0]][spos[1]]
    154 self.map[spos[0]][spos[1]]=-1;
    155 return path
    156 que.put(vpos)
    157 return []
    158
    159 #清空五连棋子,返回要清空的位置元组
    160 def clearmap(self):
    161 vis = [[False for y in range(self.ly)] for x in range(self.ly)]
    162 _dir = [[1,0],[-1,0],[0,1],[0,-1],[1,1],[-1,-1],[1,-1],[-1,1]]
    163 for i in range(self.lx):
    164 for j in range(self.ly):
    165 if self.map[i][j] == -1: continue
    166 for k in [0,2,4,6]:
    167 tx = i
    168 ty = j
    169 cnt = 1
    170 while True:
    171 tx += _dir[k][0]
    172 ty += _dir[k][1]
    173 if tx < 0 or tx >= self.lx: break
    174 if ty < 0 or ty >= self.ly: break
    175 if self.map[tx][ty] != self.map[i][j]: break
    176 cnt+=1
    177 if cnt >= 5:
    178 while True:
    179 tx -= _dir[k][0]
    180 ty -= _dir[k][1]
    181 if tx < 0 or tx >= self.lx: break
    182 if ty < 0 or ty >= self.ly: break
    183 if self.map[tx][ty] != self.map[i][j]: break
    184 vis[tx][ty] = True
    185 block = []
    186 for i in range(self.lx):
    187 for j in range(self.ly):
    188 if vis[i][j]:
    189 self.empty+=1
    190 self.score+=1 #算出分数,这个地方有待改进
    191 block.append([i,j])
    192 self.map[i][j]=-1
    193 if self.score>self.topscore:
    194 self.topscore = self.score
    195 return block
    196
    197
    198
    199
    200
    201
    202 #graph
    203 #各种颜色
    204 black = (0,0,0)
    205 white = (255,255,255)
    206 background = (100,100,100)
    207 font_col = (192,80,77)
    208
    209 color = [[(31,73,125),(192,80,77),(155,187,89),(128,100,162),(75,172,198),(247,150,70),(255,241,59),(232,12,122)],\
    210 [(135,176,225),(227,176,175),(217,229,193),(202,190,216),(185,223,233),(252,211,178),(255,248,160),(231,120,169)]]
    211
    212 xlen=30
    213 ylen=30
    214 glen=2
    215 rlen=12
    216
    217 class Draw:
    218 #初始化绘图,主要是初始pygame和窗口
    219 def __init__(self,size,tipn):
    220 pygame.init()
    221
    222 self.lx=size[0]
    223 self.ly=size[1]
    224 self.tipn=tipn
    225 sizex=(xlen+glen)*self.lx+50
    226 sizey=(ylen+glen)*(self.ly+self.tipn)+40
    227 self.screen = pygame.display.set_mode([sizey,sizex])
    228 pygame.display.set_caption('Row 5')
    229 self.font = pygame.font.Font("PLAYBILL.TTF", 28)
    230 icon=pygame.image.load('Row5.png').convert_alpha()
    231 pygame.display.set_icon(icon)
    232
    233 #返回某一个坐标对应的格子位置
    234 def getpos(self,pos):
    235 px = (pos[0]-glen-20)/(xlen+glen)
    236 py = (pos[1]-glen-20)/(ylen+glen)
    237 return [px,py]
    238
    239 #画矩形,在棋盘pos(注意是格子id)处绘制一个30*30的白色矩形,主要是起始初始化棋盘和覆盖棋盘用
    240 def rectangle(self,pos):
    241 px = (xlen+glen)*pos[0]+glen+20
    242 py = (ylen+glen)*pos[1]+glen+20
    243 pygame.draw.rect(self.screen,white,[px,py,xlen,ylen])
    244 pygame.display.update([px,py,xlen,ylen])
    245
    246 #画格子,调用rectangle函数,绘制棋盘
    247 def grid(self):
    248 for i in range(self.lx):
    249 for j in range(self.ly):
    250 self.rectangle([i,j])
    251
    252 #绘制棋子,在棋盘pos处
    253 def circle(self,pos,col,islight=0):
    254 if col == -1: return
    255 px = (xlen+glen)*pos[0]+glen+xlen/2+20
    256 py = (ylen+glen)*pos[1]+glen+ylen/2+20
    257 pygame.draw.circle(self.screen,color[islight][col],[px,py],rlen)
    258 pygame.draw.circle(self.screen,black,[px,py],rlen,2)
    259 pygame.display.update([px-xlen/2,py-ylen/2,xlen,ylen])
    260
    261 #路径绘制,沿path一格一格绘制
    262 def path(self,spos,path,col):
    263 clock = pygame.time.Clock()
    264 pre = spos
    265 for pos in path:
    266 clock.tick(40)
    267 self.circle(pos,col)
    268 self.rectangle(pre)
    269 pre = pos
    270
    271 #绘制tip
    272 def tip(self,col):
    273 for i in range(self.tipn):
    274 px = (xlen+glen)*self.lx+glen+(xlen+glen)*i+xlen/2+30
    275 py = ylen/2+30
    276 pygame.draw.circle(self.screen,color[0][col[i]],[px,py],rlen)
    277 pygame.draw.circle(self.screen,black,[px,py],rlen,2)
    278 pygame.display.update()
    279
    280 #绘制分数,一个最高分,一个当前分
    281 def score(self,val):
    282 px = (xlen+glen)*(self.lx+self.tipn)-45
    283 py = 80
    284 score = self.font.render('%8d' %(val[1]),True,font_col,background)
    285 self.screen.blit(score,[px,py])
    286 py = 110
    287 score = self.font.render('%8d' %(val[0]),True,color[0][0],background)
    288 self.screen.blit(score,[px,py])
    289 pygame.display.update()
    290
    291 #绘制菜单,返回菜单位置矩形
    292 def menu(self):
    293 menu_pos = []
    294
    295 px = (xlen+glen)*(self.lx+self.tipn)-60
    296 py = (ylen+glen)*(self.ly+self.tipn)-225
    297 menu_pos.append([px,py,70,30])
    298 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    299 py = (ylen+glen)*(self.ly+self.tipn)-190
    300 menu_pos.append([px,py,70,30])
    301 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    302 py = (ylen+glen)*(self.ly+self.tipn)-155
    303 menu_pos.append([px,py,70,30])
    304 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    305
    306
    307 px = (xlen+glen)*(self.lx+self.tipn)-45
    308 py = (ylen+glen)*(self.ly+self.tipn)-225
    309 button = self.font.render('Start',True,font_col)
    310 self.screen.blit(button,[px,py])
    311 py = (ylen+glen)*(self.ly+self.tipn)-190
    312 button = self.font.render('Level',True,font_col)
    313 self.screen.blit(button,[px,py])
    314 py = (ylen+glen)*(self.ly+self.tipn)-155
    315 button = self.font.render('Exit',True,font_col)
    316 self.screen.blit(button,[px,py])
    317 pygame.display.update()
    318 return menu_pos
    319
    320 #绘制level菜单,返回level菜单位置
    321 def level(self):
    322 menu_pos = []
    323 pygame.draw.rect(self.screen,background,self.screen.get_rect())
    324 px = self.screen.get_width()/2-40
    325 py = self.screen.get_height()/2+60
    326 menu_pos.append([px,py,70,30])
    327 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    328 py = self.screen.get_height()/2-60
    329 menu_pos.append([px,py,70,30])
    330 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    331 py = self.screen.get_height()/2-20
    332 menu_pos.append([px,py,70,30])
    333 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    334 py = self.screen.get_height()/2+20
    335 menu_pos.append([px,py,70,30])
    336 pygame.draw.rect(self.screen,[80,80,80],[px,py,70,30])
    337
    338 px = self.screen.get_width()/2-30
    339 py = self.screen.get_height()/2-60
    340 button = self.font.render('Easy',True,font_col)
    341 self.screen.blit(button,[px,py])
    342 py = self.screen.get_height()/2-20
    343 button = self.font.render('Normal',True,font_col)
    344 self.screen.blit(button,[px,py])
    345 py = self.screen.get_height()/2+20
    346 button = self.font.render('Hard',True,font_col)
    347 self.screen.blit(button,[px,py])
    348 py = self.screen.get_height()/2+60
    349 button = self.font.render('Cancel',True,font_col)
    350 self.screen.blit(button,[px,py])
    351 pygame.display.update()
    352 return menu_pos
    353
    354 #初始绘图,在初始core之后调用这个,返回菜单位置
    355 def initdraw(self,core):
    356 self.screen.fill(background)
    357 self.grid()
    358 for i in range(self.lx):
    359 for j in range(self.ly):
    360 self.circle([i,j],core.getcolor([i,j]))
    361 self.tip(core.gettip())
    362 self.score(core.getscore())
    363 menu_pos = self.menu()
    364 return menu_pos
    365
    366 #绘制游戏结束标志
    367 def over(self):
    368 px = (xlen+glen)*self.lx/2-20
    369 py = (ylen+glen)*self.ly/2-20
    370 pygame.draw.rect(self.screen,background,[px,py,100,50])
    371 px = (xlen+glen)*self.lx/2-10
    372 py = (ylen+glen)*self.ly/2-10
    373 over = self.font.render('Game over',True,font_col,background)
    374 self.screen.blit(over,[px,py])
    375 pygame.display.update()
    376
    377


      

    exe和源码下载-12月30更新

    一些学python和pygame的资料

    doc

    http://docs.python.org/

    http://pygame.org/docs/

    教程

    http://sebug.net/paper/python/

    http://www.korokithakis.net/tutorials/python/

    http://hyperpolyglot.org/scripting?utm_source 几种脚本对比

    http://coolshell.cn/articles/4710.html

    http://eyehere.net/2011/python-pygame-novice-professional-index/ 这个很不错哦



  • 相关阅读:
    Activity之间的数据传递
    解析JSON
    使用HTTP协议访问网路
    WebView的初体验
    Alarm机制用于定时服务
    IntentService和Service执行子线程对比
    前台服务
    Android四大组件之服务
    异步消息处理机制,UI更新
    Git学习
  • 原文地址:https://www.cnblogs.com/ambition/p/Row5Pygame.html
Copyright © 2020-2023  润新知