1 '''
2 新增功能:
3 1.完善音效类
4 2.添加开场音效
5 3.我方坦克发射子弹添加音效
6 '''
7 #导入pygame模块
8 import pygame,time,random
9 from pygame.sprite import Sprite
10
11 SCREEN_WIDTH=800
12 SCREEN_HEIGHT=500
13 BG_COLOR=pygame.Color(0,0,0)
14 TEXT_COLOR=pygame.Color(255,0,0)
15 #定义一个基类
16 class BaseItem(Sprite):
17 def __init__(self, color, width, height):
18 # Call the parent class (Sprite) constructor
19 pygame.sprite.Sprite.__init__(self)
20 class MainGame():
21 window=None
22 my_tank=None
23 #存储敌方坦克的列表
24 enemyTankList=[]
25 #定义敌方坦克的数量
26 enemyTankCount=5
27 #存储我方子弹的列表
28 myBulletList=[]
29 #存储敌方子弹的列表
30 enemyBulletList=[]
31 #存储爆炸效果的列表
32 explodeList=[]
33 #存储墙壁的列表
34 wallList=[]
35 def __init__(self):
36 pass
37 #开始游戏
38 def startGame(self):
39 #加载主窗口
40 #初始化窗口
41 pygame.display.init()
42 #设置窗口的大小及显示
43 MainGame.window=pygame.display.set_mode([SCREEN_WIDTH,SCREEN_HEIGHT])
44 #初始化我方坦克
45 self.createMytank()
46 #初始化敌方坦克,并将敌方坦克添加到列表中
47 self.createEnemyTank()
48 #初始化墙壁
49 self.createWall()
50 #设置窗口的标题
51 pygame.display.set_caption('坦克大战1.03')
52 while True:
53 #使用坦克移动的速度慢一点
54 time.sleep(0.02)
55 #给窗口设置填充色
56 MainGame.window.fill(BG_COLOR)
57 #获取事件
58 self.getEvent()
59 #绘制文字
60 MainGame.window.blit(self.getTextSuface('敌方坦克剩余数量%d'%len(MainGame.enemyTankList)),(10,10))
61 #调用坦克显示的方法
62 #判断我方坦克是否是否存活
63 if MainGame.my_tank and MainGame.my_tank.live:
64 MainGame.my_tank.displayTank()
65 else:
66 #删除我方坦克
67 del MainGame.my_tank
68 MainGame.my_tank=None
69 #循环遍历敌方坦克列表,展示敌方坦克
70 self.blitEnemyTank()
71 #循环遍历显示我方坦克的子弹
72 self.blitMyBullet()
73 #循环遍历敌方子弹列表,展示敌方子弹
74 self.blitEnemyBullet()
75 #循环遍历爆炸列表,展示爆炸效果
76 self.blitExplode()
77 #循环遍历墙壁列表,展示墙壁
78 self.blitWall()
79 #调用移动方法
80 #如果坦克的开关是开启,才可以移动
81 if MainGame.my_tank and MainGame.my_tank.live:
82 if not MainGame.my_tank.stop:
83 MainGame.my_tank.move()
84 #检测我方坦克是否与墙壁发生碰撞
85 MainGame.my_tank.hitWall()
86 #检测我方坦克是否与敌方坦克发生碰撞
87 MainGame.my_tank.myTank_hit_enemyTank()
88
89 pygame.display.update()
90 # 循环遍历墙壁列表,展示墙壁
91 def blitWall(self):
92 for wall in MainGame.wallList:
93 #判断墙壁是否存活
94 if wall.live:
95 #调用墙壁的显示方法
96 wall.displayWall()
97 else:
98 #从墙壁列表移出
99 MainGame.wallList.remove(wall)
100 #初始化墙壁
101 def createWall(self):
102 for i in range(6):
103 #初始化墙壁
104 wall=Wall(i*130,220)
105 #将墙壁添加到列表中
106 MainGame.wallList.append(wall)
107 #创建我方坦克的方法
108 def createMytank(self):
109 MainGame.my_tank = MyTank(350, 300)
110 #创建Music对象
111 music=Music('img/start.wav')
112 #播放音乐
113 music.play()
114 # 初始化敌方坦克,并将敌方坦克添加到列表中
115 def createEnemyTank(self):
116 top=100
117 #循环生成敌方坦克
118 for i in range(MainGame.enemyTankCount):
119 left=random.randint(0,600)
120 speed=random.randint(1,4)
121 enemy=EnemyTank(left,top,speed)
122 MainGame.enemyTankList.append(enemy)
123 #循环展示爆炸效果
124 def blitExplode(self):
125 for explode in MainGame.explodeList:
126 #判断是否活着
127 if explode.live:
128 #展示
129 explode.displayExplode()
130 else:
131 #在爆炸列表中移除
132 MainGame.explodeList.remove(explode)
133 # 循环遍历敌方坦克列表,展示敌方坦克
134 def blitEnemyTank(self):
135 for enemyTank in MainGame.enemyTankList:
136 #判断当前敌方坦克是否活着
137 if enemyTank.live:
138 enemyTank.displayTank()
139 enemyTank.randMove()
140 #调用检测是否与墙壁碰撞
141 enemyTank.hitWall()
142 #检测敌方坦克是否与我方坦克发生碰撞
143 if MainGame.my_tank and MainGame.my_tank.live:
144 enemyTank.enemyTank_hit_myTank()
145 # 发射子弹
146 enemyBullet = enemyTank.shot()
147 # 敌方子弹是否是None,如果不为None则添加到敌方子弹列表中
148 if enemyBullet:
149 # 将敌方子弹存储到敌方子弹列表中
150 MainGame.enemyBulletList.append(enemyBullet)
151 else:#不活着,从敌方坦克列表中移除
152 MainGame.enemyTankList.remove(enemyTank)
153
154
155 #循环遍历我方子弹存储列表
156 def blitMyBullet(self):
157 for myBullet in MainGame.myBulletList:
158 #判断当前的子弹是否是活着状态,如果是则进行显示及移动,
159 if myBullet.live:
160 myBullet.displayBullet()
161 # 调用子弹的移动方法
162 myBullet.move()
163 #调用检测我方子弹是否与敌方坦克发生碰撞
164 myBullet.myBullet_hit_enemyTank()
165 # 检测我方子弹是否与墙壁碰撞
166 myBullet.hitWall()
167 # 否则在列表中删除
168 else:
169 MainGame.myBulletList.remove(myBullet)
170
171 # 循环遍历敌方子弹列表,展示敌方子弹
172 def blitEnemyBullet(self):
173 for enemyBullet in MainGame.enemyBulletList:
174 if enemyBullet.live: #判断敌方子弹是否存活
175 enemyBullet.displayBullet()
176 enemyBullet.move()
177 #调用敌方子弹与我方坦克碰撞的方法
178 enemyBullet.enemyBullet_hit_myTank()
179 #检测敌方子弹是否与墙壁碰撞
180 enemyBullet.hitWall()
181 else:
182 MainGame.enemyBulletList.remove(enemyBullet)
183
184
185 #结束游戏
186 def endGame(self):
187 print('谢谢使用,欢迎再次使用')
188 exit()
189 #左上角文字的绘制
190 def getTextSuface(self,text):
191 #初始化字体模块
192 pygame.font.init()
193 #查看所有的字体名称
194 # print(pygame.font.get_fonts())
195 #获取字体Font对象
196 font=pygame.font.SysFont('kaiti',18)
197 #绘制文字信息
198 textSurface=font.render(text,True,TEXT_COLOR)
199 return textSurface
200 #获取事件
201 def getEvent(self):
202 #获取所有事件
203 eventList= pygame.event.get()
204 #遍历事件
205 for event in eventList:
206 #判断按下的键是关闭还是键盘按下
207 #如果按的是退出,关闭窗口
208 if event.type == pygame.QUIT:
209 self.endGame()
210 #如果是键盘的按下
211 if event.type == pygame.KEYDOWN:
212 #当坦克不重在死亡
213 if not MainGame.my_tank:
214 #判断按下的是Esc键,让坦克重生
215 if event.key == pygame.K_ESCAPE:
216 # 让我方坦克重生及调用创建坦克的方法
217 self.createMytank()
218 if MainGame.my_tank and MainGame.my_tank.live:
219 # 判断按下的是上、下、左、右
220 if event.key == pygame.K_LEFT:
221 # 切换方向
222 MainGame.my_tank.direction = 'L'
223 # 修改坦克的开关状态
224 MainGame.my_tank.stop = False
225 # MainGame.my_tank.move()
226 print('按下左键,坦克向左移动')
227 elif event.key == pygame.K_RIGHT:
228 # 切换方向
229 MainGame.my_tank.direction = 'R'
230 # 修改坦克的开关状态
231 MainGame.my_tank.stop = False
232 # MainGame.my_tank.move()
233 print('按下右键,坦克向右移动')
234 elif event.key == pygame.K_UP:
235 # 切换方向
236 MainGame.my_tank.direction = 'U'
237 # 修改坦克的开关状态
238 MainGame.my_tank.stop = False
239 # MainGame.my_tank.move()
240 print('按下上键,坦克向上移动')
241 elif event.key == pygame.K_DOWN:
242 # 切换方向
243 MainGame.my_tank.direction = 'D'
244 # 修改坦克的开关状态
245 MainGame.my_tank.stop = False
246 # MainGame.my_tank.move()
247 print('按下左键,坦克向下移动')
248 elif event.key == pygame.K_SPACE:
249 print('发射子弹')
250 # 如果当前我方子弹列表的大小 小于等于3时候才可以创建
251 if len(MainGame.myBulletList) < 3:
252 # 创建我方坦克发射的子弹
253 myBullet = Bullet(MainGame.my_tank)
254 MainGame.myBulletList.append(myBullet)
255 #我方坦克发射子弹添加音效
256 music=Music('img/hit.wav')
257 music.play()
258
259
260
261 #松开方向键,坦克停止移动,修改坦克的开关状态
262 if event.type == pygame.KEYUP:
263 #判断松开的键是上、下、左、右时候才停止坦克移动
264 if event.key==pygame.K_UP or event.key==pygame.K_DOWN or event.key == pygame.K_LEFT or event.key ==pygame.K_RIGHT:
265 if MainGame.my_tank and MainGame.my_tank.live:
266 MainGame.my_tank.stop = True
267
268
269 class Tank(BaseItem):
270 #添加距离左边left 距离上边top
271 def __init__(self,left,top):
272 #保存加载的图片
273 self.images={
274 'U':pygame.image.load('img/p1tankU.gif'),
275 'D':pygame.image.load('img/p1tankD.gif'),
276 'L':pygame.image.load('img/p1tankL.gif'),
277 'R':pygame.image.load('img/p1tankR.gif'),
278 }
279 #方向
280 self.direction='L'
281 #根据当前图片的方向获取图片 surface
282 self.image=self.images[self.direction]
283 #根据图片获取区域
284 self.rect=self.image.get_rect()
285 #设置区域的left 和top
286 self.rect.left=left
287 self.rect.top=top
288 #速度 决定移动的快慢
289 self.speed=5
290 #坦克移动的开关
291 self.stop=True
292 #是否活着
293 self.live=True
294 #新增属性原来坐标
295 self.oldLeft=self.rect.left
296 self.oldTop=self.rect.top
297
298 #移动
299 def move(self):
300 #移动后记录原始的坐标
301 self.oldLeft=self.rect.left
302 self.oldTop=self.rect.top
303 #判断坦克的方向进行移动
304 if self.direction == 'L':
305 if self.rect.left>0:
306 self.rect.left -= self.speed
307 elif self.direction == 'U':
308 if self.rect.top>0:
309 self.rect.top -= self.speed
310 elif self.direction == 'D':
311 if self.rect.top+self.rect.height<SCREEN_HEIGHT:
312 self.rect.top += self.speed
313 elif self.direction == 'R':
314 if self.rect.left+self.rect.height<SCREEN_WIDTH:
315 self.rect.left += self.speed
316
317 #射击
318 def shot(self):
319 return Bullet(self)
320 #
321 def stay(self):
322 self.rect.left=self.oldLeft
323 self.rect.top=self.oldTop
324 #检测坦克是否与墙壁发生碰撞
325 def hitWall(self):
326 for wall in MainGame.wallList:
327 if pygame.sprite.collide_rect(self,wall):
328 #将坐标设置为移动之前的坐标
329 self.stay()
330 #展示坦克的方法
331 def displayTank(self):
332 #获取展示的对象
333 self.image=self.images[self.direction]
334 #调用blit方法展示
335 MainGame.window.blit(self.image,self.rect)
336 #我方坦克
337 class MyTank(Tank):
338 def __init__(self,left,top):
339 super(MyTank, self).__init__(left,top)
340
341 #检测我方坦克与敌方坦克发生碰撞
342 def myTank_hit_enemyTank(self):
343 #循环遍历敌方坦克列表
344 for enemyTank in MainGame.enemyTankList:
345 if pygame.sprite.collide_rect(self,enemyTank):
346 self.stay()
347
348 #敌方坦克
349 class EnemyTank(Tank):
350 def __init__(self,left,top,speed):
351 #调用父类的初始化方法
352 super(EnemyTank, self).__init__(left,top)
353 #加载图片集
354 self.images={
355 'U':pygame.image.load('img/enemy1U.gif'),
356 'D':pygame.image.load('img/enemy1D.gif'),
357 'L':pygame.image.load('img/enemy1L.gif'),
358 'R':pygame.image.load('img/enemy1R.gif')
359 }
360 #方向,随机生成敌方坦克的方向
361 self.direction=self.randDirection()
362 #根据方向获取图片
363 self.image=self.images[self.direction]
364 #区域
365 self.rect=self.image.get_rect()
366 #对left和top进行赋值
367 self.rect.left=left
368 self.rect.top=top
369 #速度
370 self.speed=speed
371 #移动开关键
372 self.flag=True
373 #薪增加一个步数变量 step
374 self.step=60
375
376 #敌方坦克与我方坦克是否发生碰撞
377 def enemyTank_hit_myTank(self):
378 if pygame.sprite.collide_rect(self,MainGame.my_tank):
379 self.stay()
380 # 随机生成敌方坦克的方向
381 def randDirection(self):
382 num=random.randint(1,4)
383 if num == 1:
384 return 'U'
385 elif num == 2:
386 return 'D'
387 elif num == 3:
388 return "L"
389 elif num == 4:
390 return 'R'
391
392 #敌方坦克随机移动的方法
393 def randMove(self):
394 if self.step<=0:
395 #修改方向
396 self.direction=self.randDirection()
397 #让步数复位
398 self.step=60
399 else:
400 self.move()
401 #让步数递减
402 self.step-=1
403 #重写shot()
404 def shot(self):
405 #随机生成100以内的数
406 num=random.randint(1,100)
407 if num<10:
408 return Bullet(self)
409 #子弹类
410 class Bullet(BaseItem):
411 def __init__(self,tank):
412 #加载图片
413 self.image=pygame.image.load('img/enemymissile.gif')
414 #坦克的方向决定子弹的方向
415 self.direction=tank.direction
416 #获取区域
417 self.rect=self.image.get_rect()
418 #子弹的left和top与方向有关
419 if self.direction == 'U':
420 self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
421 self.rect.top = tank.rect.top - self.rect.height
422 elif self.direction == 'D':
423 self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
424 self.rect.top = tank.rect.top + tank.rect.height
425 elif self.direction == 'L':
426 self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2
427 self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
428 elif self.direction == 'R':
429 self.rect.left = tank.rect.left + tank.rect.width
430 self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
431 #子弹的速度
432 self.speed=6
433 #子弹的状态,是否碰到墙壁,如果碰到墙壁,修改此状态
434 self.live=True
435 #移动
436 def move(self):
437 if self.direction == 'U':
438 if self.rect.top>0:
439 self.rect.top-=self.speed
440 else:
441 #修改子弹的状态
442 self.live=False
443 elif self.direction == 'R':
444 if self.rect.left+self.rect.width<SCREEN_WIDTH:
445 self.rect.left+=self.speed
446 else:
447 #修改子弹的状态
448 self.live=False
449 elif self.direction =='D':
450 if self.rect.top+self.rect.height<SCREEN_HEIGHT:
451 self.rect.top+=self.speed
452 else:
453 #修改子弹的状态
454 self.live=False
455 elif self.direction == 'L':
456 if self.rect.left>0:
457 self.rect.left-=self.speed
458 else:
459 #修改子弹的状态
460 self.live=False
461 #子弹是否碰撞墙壁
462 def hitWall(self):
463 #循环遍历墙壁列表
464 for wall in MainGame.wallList:
465 if pygame.sprite.collide_rect(self,wall):
466 #修改子弹的生存状态,让子弹消失
467 self.live=False
468 #墙壁的生命值减小
469 wall.hp-=1
470 if wall.hp<=0:
471 #修改墙壁的生存状态
472 wall.live=False
473
474
475 #展示子弹的方法
476 def displayBullet(self):
477 #将图片surface加载到窗口
478 MainGame.window.blit(self.image,self.rect)
479
480 #我方子弹与敌方坦克的碰撞
481 def myBullet_hit_enemyTank(self):
482 #循环遍历敌方坦克列表,判断是否发生碰撞
483 for enemyTank in MainGame.enemyTankList:
484 if pygame.sprite.collide_rect(enemyTank,self):
485 #修改敌方坦克和我方子弹的状态
486 enemyTank.live=False
487 self.live=False
488 #创建爆炸对象
489 explode=Explode(enemyTank)
490 #将爆炸对象添加到爆炸列表中
491 MainGame.explodeList.append(explode)
492 #敌方子弹与我方坦克的碰撞
493 def enemyBullet_hit_myTank(self):
494 if MainGame.my_tank and MainGame.my_tank.live:
495 if pygame.sprite.collide_rect(MainGame.my_tank, self):
496 # 产生爆炸对象
497 explode = Explode(MainGame.my_tank)
498 # 将爆炸对象添加到爆炸列表中
499 MainGame.explodeList.append(explode)
500 # 修改敌方子弹与我方坦克的状态
501 self.live = False
502 MainGame.my_tank.live = False
503
504 class Wall():
505 def __init__(self,left,top):
506 #加载墙壁图片
507 self.image=pygame.image.load('img/steels.gif')
508 #获取墙壁的区域
509 self.rect=self.image.get_rect()
510 #设置位置left、top
511 self.rect.left=left
512 self.rect.top=top
513 #是否存活
514 self.live=True
515 #设置生命值
516 self.hp=3
517 #展示墙壁的方法
518 def displayWall(self):
519 MainGame.window.blit(self.image,self.rect)
520 class Explode():
521 def __init__(self,tank):
522 #爆炸的位置由当前子弹打中的坦克位置决定
523 self.rect=tank.rect
524 self.images=[
525 pygame.image.load('img/blast0.gif'),
526 pygame.image.load('img/blast1.gif'),
527 pygame.image.load('img/blast2.gif'),
528 pygame.image.load('img/blast3.gif'),
529 pygame.image.load('img/blast4.gif'),
530 ]
531 self.step=0
532 self.image=self.images[self.step]
533 #是否活着
534 self.live=True
535
536 #展示爆炸效果的方法
537 def displayExplode(self):
538 if self.step<len(self.images):
539 #根据索引获取爆炸对象
540 self.image=self.images[self.step]
541 self.step+=1
542 #添加到主窗口
543 MainGame.window.blit(self.image,self.rect)
544 else:
545 #修改活着的状态
546 self.live=False
547 self.step=0
548 class Music():
549 def __init__(self,filename):
550 self.filename=filename
551 #初始化音乐混合器
552 pygame.mixer.init()
553 #加载音乐
554 pygame.mixer.music.load(self.filename)
555 #播放音乐
556 def play(self):
557 pygame.mixer.music.play()
558 if __name__=='__main__':
559 MainGame().startGame()
560 # MainGame().getTextSuface()