上篇写的动画示例其实算不上一个游戏,顶多算是利用pygame进行的图形操作,今天着手实现一个小游戏:传说哥大战剧毒术士。名字很玄乎,其实就是最简单的一个射击游戏。好了废话不多说,先上截图吧:
一、初始化程序和定义变量
import pygame import math import random # 1 - Initialize the game pygame.init() # prepare the variables width, height = 640, 480 screen=pygame.display.set_mode((width, height)) playerpos=[100,100] speed_x=5 speed_y=5 speed_bullet=10 speed_shit=3 shot=0 alive=True bullet=[] shit=[] green=[0,255,0] # 2 - Load images player = pygame.image.load("1.bmp") badguy = pygame.image.load("2.bmp") backgroud= pygame.image.load("3.bmp") bullet_bmp=pygame.image.load("4.bmp") shit_bmp=pygame.image.load("5.bmp") player.set_colorkey([0,0,0]) badguy.set_colorkey([0,0,0]) shit_bmp.set_colorkey([255,255,255])
第一部分声明的变量中主要是传说哥的移动速度,子弹的数据,剧毒术士喷出的便便速度等。第二部分预载入图片资源:角色,背景图等。注意设置set_colorkey进行透明色处理(书上有介绍)。
二、响应事件处理相关
1 # 4 - clear the screen before drawing it again 2 screen.fill(0) 3 # 5 - draw the backgroud 4 for x in range(width/backgroud.get_width()+1): 5 for y in range(height/backgroud.get_height()+1): 6 screen.blit(backgroud,(x*90,y*65)) 7 # 6 - loop through the events 8 for event in pygame.event.get(): 9 # check if the event is the X button 10 if event.type==pygame.QUIT: 11 # if it is quit the game 12 pygame.quit() 13 exit(0) 14 if event.type==pygame.KEYDOWN: 15 if event.key == pygame.K_w: 16 playerpos[1]-=speed_y 17 elif event.key == pygame.K_s: 18 playerpos[1]+=speed_y 19 elif event.key == pygame.K_a: 20 playerpos[0]-=speed_x 21 elif event.key == pygame.K_d: 22 playerpos[0]+=speed_x 23 position = pygame.mouse.get_pos() 24 angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+32)) 25 playerrot = pygame.transform.rotate(player, 360-angle*57.29) 26 playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2) 27 if event.type==pygame.MOUSEBUTTONDOWN: 28 position=pygame.mouse.get_pos() 29 bullet.append([math.atan2(position[1]-(playerpos1[1]+32), 30 position[0]-(playerpos1[0]+32)),playerpos1[0]+32,playerpos1[1]+32])
这一部分首先将加载进的背景图片利用blit函数贴到窗口里。随后进入事件循环:这里主要是两种事件:WSAD控制人物运动,鼠标点击射出子弹,由于是用鼠标控制射击方向,因此需要获取图片的新位置,简单的数学知识,偏转角计算如下图,这块的处理具体参照一篇不错的文章http://bbs.chinaunix.net/thread-4094150-1-2.html,这个小东东借鉴了里面很多知识。
三、处理对战逻辑
1 # 7 - process fight 2 screen.blit(playerrot, playerpos1) 3 for oneshot in bullet: 4 index=0 5 velx=math.cos(oneshot[0])*speed_bullet 6 vely=math.sin(oneshot[0])*speed_bullet 7 oneshot[1]+=velx 8 oneshot[2]+=vely 9 if oneshot[1]<-64 or oneshot[1]>640 or oneshot[2]<-64 or oneshot[2]>480: 10 bullet.pop(index) 11 index+=1 12 for eachone in bullet: 13 pos_x=int(eachone[1]) 14 pos_y=int(eachone[2]) 15 pos=[pos_x,pos_y] 16 bullet_bmp_new=pygame.transform.rotate(bullet_bmp,360-eachone[0]*57.29) 17 screen.blit(bullet_bmp_new,pos) 18 pygame.display.flip() 19 for oneshot in bullet: 20 if oneshot[1]<badguy_pos[0]+57 and oneshot[1]>badguy_pos[0] and\ 21 oneshot[2]<badguy_pos[1]+70 and oneshot[2]>badguy_pos[1]: 22 shot+=1 23 alive=False 24 break 25 if shot<5 and alive==False: 26 badguy_x=random.randrange(0,640-57) 27 badguy_y=random.randrange(0,480-70) 28 badguy_pos=[badguy_x,badguy_y] 29 alive=True 30 if alive ==True: 31 screen.blit(badguy, badguy_pos) 32 else: 33 pygame.quit() 34 exit(0) 35 if len(shit)<2: 36 shit.append([math.atan2(playerpos1[1]-(badguy_pos[1]+32), 37 playerpos1[0]-(badguy_pos[0]+32)),badguy_pos[0]+32,badguy_pos[1]+32]) 38 for oneshit in shit: 39 index=0 40 velx=math.cos(oneshit[0])*speed_shit 41 vely=math.sin(oneshit[0])*speed_shit 42 oneshit[1]+=velx 43 oneshit[2]+=vely 44 if oneshit[1]<-64 or oneshit[1]>640 or oneshit[2]<-64 or oneshit[2]>480: 45 shit.pop(index) 46 index+=1 47 for eachshit in shit: 48 pos_x=int(eachshit[1]) 49 pos_y=int(eachshit[2]) 50 pos=[pos_x,pos_y] 51 shit_bmp_new=pygame.transform.rotate(shit_bmp,360-eachshit[0]*57.29) 52 screen.blit(shit_bmp_new,pos) 53 pygame.display.flip() 54 for oneshit in shit: 55 if oneshit[1]<playerpos1[0]+66 and oneshit[1]>playerpos1[0] and\ 56 oneshit[2]<playerpos1[1]+66 and oneshit[2]>playerpos1[1]: 57 pygame.quit() 58 exit(0) 59 pygame.display.flip()
每次点击一次鼠标,子弹发射,保存到列表中,但是当子弹离开屏幕需要删除掉改子弹,同时记得由第二部分保存的偏转角计算子弹的偏转。剧毒喷出的大便处理类似,也要由传说哥的位置计算出偏转角利用设定的速度甩向我们的主人公火枪哥。
这里的输赢判定为火枪打死5个剧毒即获取胜利,扔出的便便有一次砸到我们的主人公,游戏失败即结束,不管胜利还是失败,游戏均退出处理。
以上便是整个游戏的大体逻辑,可以看出利用python 100行左右的代码即可以实现一个最简单的人机对战,不过代码写的比较乱得说,也没有用函数编程和面向对象的东西。另外提一下写游戏这块效率性能确实不敢恭维(明显的迟钝)。。不管怎么样,利用pygame实现小游戏还是比较方便的。
这个小游戏写的确实虽然简单和幼稚,不过花了半天时间就能从零搞起来,确实有所收获。有时间的话可以进一步增加敌方的难度和可玩性,先这样吧。
附下代码吧:
1 import pygame 2 import math 3 import random 4 5 # 1 - Initialize the game 6 pygame.init() 7 # prepare the variables 8 width, height = 640, 480 9 screen=pygame.display.set_mode((width, height)) 10 playerpos=[100,100] 11 speed_x=5 12 speed_y=5 13 speed_bullet=10 14 speed_shit=3 15 shot=0 16 alive=True 17 bullet=[] 18 shit=[] 19 badguy_x=random.randrange(0,640) 20 badguy_y=random.randrange(0,480) 21 badguy_pos=[badguy_x,badguy_y] 22 green=[0,255,0] 23 # 2 - Load images 24 player = pygame.image.load("1.bmp") 25 badguy = pygame.image.load("2.bmp") 26 backgroud= pygame.image.load("3.bmp") 27 bullet_bmp=pygame.image.load("4.bmp") 28 shit_bmp=pygame.image.load("5.bmp") 29 player.set_colorkey([0,0,0]) 30 badguy.set_colorkey([0,0,0]) 31 shit_bmp.set_colorkey([255,255,255]) 32 # 3 - main loop 33 while 1: 34 # 4 - clear the screen before drawing it again 35 screen.fill(0) 36 # 5 - draw the backgroud 37 for x in range(width/backgroud.get_width()+1): 38 for y in range(height/backgroud.get_height()+1): 39 screen.blit(backgroud,(x*90,y*65)) 40 41 42 # 6 - loop through the events 43 for event in pygame.event.get(): 44 # check if the event is the X button 45 if event.type==pygame.QUIT: 46 # if it is quit the game 47 pygame.quit() 48 exit(0) 49 if event.type==pygame.KEYDOWN: 50 if event.key == pygame.K_w: 51 playerpos[1]-=speed_y 52 elif event.key == pygame.K_s: 53 playerpos[1]+=speed_y 54 elif event.key == pygame.K_a: 55 playerpos[0]-=speed_x 56 elif event.key == pygame.K_d: 57 playerpos[0]+=speed_x 58 position = pygame.mouse.get_pos() 59 angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+32)) 60 playerrot = pygame.transform.rotate(player, 360-angle*57.29) 61 playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2) 62 if event.type==pygame.MOUSEBUTTONDOWN: 63 position=pygame.mouse.get_pos() 64 bullet.append([math.atan2(position[1]-(playerpos1[1]+32), 65 position[0]-(playerpos1[0]+32)),playerpos1[0]+32,playerpos1[1]+32]) 66 # 7 - process fight 67 screen.blit(playerrot, playerpos1) 68 for oneshot in bullet: 69 index=0 70 velx=math.cos(oneshot[0])*speed_bullet 71 vely=math.sin(oneshot[0])*speed_bullet 72 oneshot[1]+=velx 73 oneshot[2]+=vely 74 if oneshot[1]<-64 or oneshot[1]>640 or oneshot[2]<-64 or oneshot[2]>480: 75 bullet.pop(index) 76 index+=1 77 for eachone in bullet: 78 pos_x=int(eachone[1]) 79 pos_y=int(eachone[2]) 80 pos=[pos_x,pos_y] 81 bullet_bmp_new=pygame.transform.rotate(bullet_bmp,360-eachone[0]*57.29) 82 screen.blit(bullet_bmp_new,pos) 83 pygame.display.flip() 84 for oneshot in bullet: 85 if oneshot[1]<badguy_pos[0]+57 and oneshot[1]>badguy_pos[0] and\ 86 oneshot[2]<badguy_pos[1]+70 and oneshot[2]>badguy_pos[1]: 87 shot+=1 88 alive=False 89 break 90 if shot<5 and alive==False: 91 badguy_x=random.randrange(0,640-57) 92 badguy_y=random.randrange(0,480-70) 93 badguy_pos=[badguy_x,badguy_y] 94 alive=True 95 if alive ==True: 96 screen.blit(badguy, badguy_pos) 97 else: 98 pygame.quit() 99 exit(0) 100 if len(shit)<2: 101 shit.append([math.atan2(playerpos1[1]-(badguy_pos[1]+32), 102 playerpos1[0]-(badguy_pos[0]+32)),badguy_pos[0]+32,badguy_pos[1]+32]) 103 for oneshit in shit: 104 index=0 105 velx=math.cos(oneshit[0])*speed_shit 106 vely=math.sin(oneshit[0])*speed_shit 107 oneshit[1]+=velx 108 oneshit[2]+=vely 109 if oneshit[1]<-64 or oneshit[1]>640 or oneshit[2]<-64 or oneshit[2]>480: 110 shit.pop(index) 111 index+=1 112 for eachshit in shit: 113 pos_x=int(eachshit[1]) 114 pos_y=int(eachshit[2]) 115 pos=[pos_x,pos_y] 116 shit_bmp_new=pygame.transform.rotate(shit_bmp,360-eachshit[0]*57.29) 117 screen.blit(shit_bmp_new,pos) 118 pygame.display.flip() 119 for oneshit in shit: 120 if oneshit[1]<playerpos1[0]+66 and oneshit[1]>playerpos1[0] and\ 121 oneshit[2]<playerpos1[1]+66 and oneshit[2]>playerpos1[1]: 122 pygame.quit() 123 exit(0) 124 pygame.display.flip()