小时候玩的“坦克大战”,你还记得吗?
满满的回忆
!
今天,我们使用Python以及强大的第三方库来实现一个简单的坦克大战游戏。
整体效果
环境依赖
python3.7
pygame1.9.6
urllib
内置库,如random、sys、time、os等
pygame介绍
Pygame被设计用来写游戏的python模块集合,基于SDL库开发。使用python可以导入pygame来开发具有全部特性的游戏和多媒体软件,Pygame是极度轻便的并且可以运行在几乎所有的平台和操作系统上。
1. 导入依赖 & 通用配置
1importrandom
2importsys
3importtime
4fromurllib.requestimporturlretrieve
5importos
6importpygame
7
8
9SCREEN_WIDTH, SCREEN_HEIGHT =1200,700# 画面大小
10MY_BIRTH_LEFT, MY_BIRTH_TOP = SCREEN_WIDTH /2, SCREEN_HEIGHT -60
11DIRECTION = [U, D, L, R] = [ U , D , L , R ]# 控制键
12Tank_IMAGE_POSITION =r D:/tank_img
13URL = https://gitee.com/tyoui/logo/raw/master/img/
2. 通用加载函数
1# 加载图片
2defload_img(name_img):
3save = Tank_IMAGE_POSITION + os.sep + name_img + .gif
4ifnotos.path.exists(save):
5urlretrieve(URL + name_img + .gif , save)
6returnpygame.image.load(save)
7
8# 加载背景音乐
9defload_music(name_music):
10save = Tank_IMAGE_POSITION + os.sep + name_music + .wav
11ifnotos.path.exists(save):
12urlretrieve(URL + name_music + .wav , save)
13pygame.mixer.music.load(save)
14pygame.mixer.music.play()
3. 通用基础类
1
2* pygame.sprite模块,官方文档上说这个模块是轻量级的,在游戏开发中也未必要使用。
3* sprite翻译为精灵,在游戏动画一般是指一个独立运动的画面元素,在pygame中,
4就可以是一个带有图像(Surface)和大小位置(Rect)的对象。
5* pygame.sprite.Sprite是pygame精灵的基类,一般来说,需要写一个自己的精灵类继承一下它然后加入自己的代码。
6
7classBaseItem(pygame.sprite.Sprite):
8def__init__(self):
9super().__init__()
4. 定义bullet类
1classBullet(BaseItem):
2# 参数初始化
3def__init__(self, tank, window):
4super().__init__()
5self.direction = tank.direction
6self.speed = tank.speed *3
7self.img = load_img( bullet )
8self.rect = self.img.get_rect()
9self.window = window
10self.live =True
11ifself.direction == U:
12self.rect.left = tank.rect.left + tank.rect.width /2- self.rect.width /2
13self.rect.top = tank.rect.top - self.rect.height
14elifself.direction == D:
15self.rect.left = tank.rect.left + tank.rect.width /2- self.rect.width /2
16self.rect.top = tank.rect.top + tank.rect.height
17elifself.direction == L:
18self.rect.left = tank.rect.left - self.rect.width /2- self.rect.width /2
19self.rect.top = tank.rect.top + tank.rect.height /2- self.rect.height /2
20else:
21self.rect.left = tank.rect.left + tank.rect.width
22self.rect.top = tank.rect.top + tank.rect.height /2- self.rect.height /2
23
24# 子弹显示
25defdisplay_bullet(self):
26self.window.blit(self.img, self.rect)
27
28# 通过按键控制子弹移动
29defbullet_move(self):
30ifself.direction == U:
31ifself.rect.top >0:
32self.rect.top -= self.speed
33return
34elifself.direction == D:
35ifself.rect.top < SCREEN_HEIGHT:
36self.rect.top += self.speed
37return
38elifself.direction == L:
39ifself.rect.left >0:
40self.rect.left -= self.speed
41return
42else:
43ifself.rect.left < SCREEN_WIDTH:
44self.rect.left += self.speed
45return
46self.live =False
47
48# 我方坦克子弹击中对方坦克
49defhit_enemy_tank(self):
50forenemyinTankGame.enemy_tank_list:
51hit = pygame.sprite.collide_rect(self, enemy)
52ifhit:
53self.live =False
54ifenemy.click_count ==1:
55enemy.live =False
56returnNone
57enemy.click_count -=1
58ifenemy.click_count ==2:
59enemy.load_image = enemy.img32
60ifenemy.click_count ==1:
61enemy.load_image = enemy.img31
62load_music( hit )
63
64# 对方坦克子弹击中我方坦克
65defhit_my_tank(self, tank):
66hit = pygame.sprite.collide_rect(self, tank)
67ifhit:
68self.live =False
69tank.live =False
70
71# 子弹击中围墙
72defbullet_collide_wall(self):
73forwallinTankGame.wall_list:
74result = pygame.sprite.collide_rect(self, wall)
75ifresult:
76self.live =False
77ifwall.count ==1:
78wall.live =False
79else:
80load_music( hit )
81
82# 子弹击中子弹
83defbullet_collide_bullet(self):
84forbulletinTankGame.enemy_bullet_list:
85ifpygame.sprite.collide_rect(bullet, self):
86bullet.live =False
87self.live =False
5. 定义tank类
1classTank(BaseItem):
2# 参数初始化
3def__init__(self, left, top, window, image, direction, speed):
4super().__init__()
5self.window = window
6self.load_image = image
7self.direction = direction
8self.img = self.load_image[self.direction]
9self.rect = self.img.get_rect()
10self.rect.left = left
11self.rect.top = top
12self.speed = speed
13self.tank_width = self.rect.width
14self.tank_height = self.rect.height
15self.wall_switch =False
16self.move_stop =True
17self.live =True
18self.old_left =0
19self.old_top =0
20
21# 开火
22deffire(self):
23returnBullet(self, self.window)
24
25# 显示
26defdisplay(self):
27self.img = self.load_image[self.direction]
28self.window.blit(self.img, self.rect)
29
30defwall_not(self, direction):
31ifdirection == U:
32returnself.rect.top >0
33elifdirection == D:
34returnself.rect.top <= SCREEN_HEIGHT - self.tank_height
35elifdirection == L:
36returnself.rect.left >0
37else:
38returnself.rect.left <= SCREEN_WIDTH - self.tank_width
39
40defwall_yes(self, direction):
41ifdirection == U:
42ifself.rect.top <0:
43self.rect.top = SCREEN_HEIGHT
44elifdirection == D:
45self.rect.top %= SCREEN_HEIGHT
46elifdirection == L:
47ifself.rect.left <0:
48self.rect.left = SCREEN_WIDTH
49else:
50self.rect.left %= SCREEN_WIDTH
51
52defmove(self, direction):
53self.old_left = self.rect.left
54self.old_top = self.rect.top
55ifself.wall_switch:
56self.wall_yes(direction)
57elifnotself.wall_not(direction):
58returnNone
59ifdirection == U:
60self.rect.top -= self.speed
61elifdirection == D:
62self.rect.top += self.speed
63elifdirection == L:
64self.rect.left -= self.speed
65else:
66self.rect.left += self.speed
67
68defstay(self):
69self.rect.left = self.old_left
70self.rect.top = self.old_top
71
72deftank_collide_wall(self):
73forwallinTankGame.wall_list:
74ifpygame.sprite.collide_rect(self, wall):
75self.stay()
76
77deftank_collide_tank(self):
78fortankinTankGame.enemy_tank_list:
79ifpygame.sprite.collide_rect(self, tank):
80self.stay()
6. 定义我方 & 对方tank类
1classMyTank(Tank):
2def__init__(self, left, top, window):
3self.img = dict(U=load_img( p2tankU ), D=load_img( p2tankD ), L=load_img( p2tankL ), R=load_img( p2tankR ))
4self.my_tank_speed =4
5super().__init__(left, top, window, self.img, U, self.my_tank_speed)
6
7
8classEnemyTank(Tank):
9def__init__(self, left, top, window):
10self.img1 = dict(U=load_img( enemy1U ), D=load_img( enemy1D ), L=load_img( enemy1L ), R=load_img( enemy1R ))
11self.img2 = dict(U=load_img( enemy2U ), D=load_img( enemy2D ), L=load_img( enemy2L ), R=load_img( enemy2R ))
12self.img3 = dict(U=load_img( enemy3U ), D=load_img( enemy3D ), L=load_img( enemy3L ), R=load_img( enemy3R ))
13self.img31 = dict(U=load_img( enemy3U_1 ), D=load_img( enemy3D_1 ), L=load_img( enemy3L_1 ),
14R=load_img( enemy3R_1 ))
15self.img32 = dict(U=load_img( enemy3U_2 ), D=load_img( enemy3D_2 ), L=load_img( enemy3L_2 ),
16R=load_img( enemy3R_2 ))
17# 不同的坦克击中的次数不一样
18image, self.click_count, speed = random.choice([(self.img1,1,4), (self.img3,3,3), (self.img2,1,5)])
19super().__init__(left, top, window, image, self.random_direction(), speed)
20self.step =100
21
22@staticmethod
23defrandom_direction():
24n = random.randint(0,3)
25returnDIRECTION[n]
26
27defrandom_move(self):
28ifself.step ==0:
29self.direction = self.random_direction()
30self.step = random.randint(10,100)
31else:
32self.move(self.direction)
33self.step -=1
34
35defrandom_fire(self):
36ifrandom.randint(0,50) ==1andlen(TankGame.enemy_bullet_list) <30:
37enemy_bullet = self.fire()
38TankGame.enemy_bullet_list.append(enemy_bullet)
7. 爆炸动作类
1classExplode(BaseItem):
2def__init__(self, tank, window):
3super().__init__()
4self.img = [load_img( blast0 ), load_img( blast1 ), load_img( blast2 ), load_img( blast3 ), load_img( blast4 ),
5load_img( blast5 ), load_img( blast6 )]
6self.rect = tank.rect
7self.stop =0
8self.window = window
9self.rect.left = tank.rect.left - tank.rect.width /2
10defdisplay_explode(self):
11load_music( blast )
12whileself.stop < len(self.img):
13self.window.blit(self.img[self.stop], self.rect)
14self.stop +=1
8. 定义wall类
1classWall(BaseItem):
2def__init__(self, left, top, window):
3super().__init__()
4self.count = random.randint(0,1)
5self.img = [load_img( steels ), load_img( walls )][self.count]
6self.rect = self.img.get_rect()
7self.rect.left = left
8self.rect.top = top
9self.window = window
10self.live =True
11
12defdisplay_wall(self):
13self.window.blit(self.img, self.rect)
9. 定义坦克大战类
1classTankGame:
2my_bullet_list = list()
3enemy_bullet_list = list()
4enemy_tank_list = list()
5wall_list = list()
6
7def__init__(self):
8ifnotos.path.exists(Tank_IMAGE_POSITION):
9os.makedirs(Tank_IMAGE_POSITION)
10pygame.init()
11pygame.font.init()
12self.display = pygame.display
13self.window = self.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.RESIZABLE,32)
14self.display.set_caption( 坦克世界 )
15self.my_tank = MyTank(MY_BIRTH_LEFT, MY_BIRTH_TOP, self.window)
16self.creat_enemy_number =10
17self.my_tank_lift =3
18self.creat_enemy(self.creat_enemy_number)
19self.creat_walls()
20self.font = pygame.font.SysFont( kai_ti ,18)
21self.number =1
22
23defcreat_enemy(self, number):
24for_inrange(number):
25left = random.randint(0, SCREEN_WIDTH - self.my_tank.tank_width)
26enemy_tank = EnemyTank(left,20, self.window)
27TankGame.enemy_tank_list.append(enemy_tank)
28
29defcreat_walls(self):
30foriinrange(SCREEN_WIDTH //60+1):
31wall_h = random.randint(100,500)
32w = Wall(60* i, wall_h, self.window)
33TankGame.wall_list.append(w)
34
35@staticmethod
36defshow_walls():
37forwinTankGame.wall_list:
38ifw.live:
39w.display_wall()
40else:
41TankGame.wall_list.remove(w)
42
43defstart_game(self):
44load_music( start )
45whileTrue:
46self.window.fill([0,0,0])
47self.get_event()
48len_enemy = len(TankGame.enemy_tank_list)
49self.window.blit(
50self.draw_text( 敌方坦克*{0},我方生命值*{1},当前{2}关 .format(len_enemy, self.my_tank_lift, self.number)), (10,10))
51iflen_enemy ==0:
52self.creat_enemy_number +=10
53self.number +=1
54self.my_tank_lift +=1
55self.creat_enemy(self.creat_enemy_number)
56self.wall_list.clear()
57self.creat_walls()
58self.show_my_tank()
59self.show_enemy_tank()
60self.show_bullet(TankGame.enemy_bullet_list)
61self.show_bullet(TankGame.my_bullet_list)
62self.show_walls()
63self.display.update()
64time.sleep(0.02)
65
66defshow_my_tank(self):
67ifself.my_tank.live:
68self.my_tank.display()
69self.my_tank.tank_collide_tank()
70self.my_tank.tank_collide_wall()
71else:
72Explode(self.my_tank, self.window).display_explode()
73delself.my_tank
74ifself.my_tank_lift ==0:
75self.end_game()
76self.my_tank_lift -=1
77load_music( add )
78self.my_tank = MyTank(MY_BIRTH_LEFT, MY_BIRTH_TOP, self.window)
79ifnotself.my_tank.move_stop:
80self.my_tank.move(self.my_tank.direction)
81
82defshow_enemy_tank(self):
83foreinTankGame.enemy_tank_list:
84e.random_move()
85e.tank_collide_wall()
86ife.live:
87e.display()
88else:
89TankGame.enemy_tank_list.remove(e)
90Explode(e, self.window).display_explode()
91e.random_fire()
92
93defshow_bullet(self, ls):
94forbinls:
95b.bullet_move()
96b.bullet_collide_wall()
97iflsisTankGame.my_bullet_list:
98b.hit_enemy_tank()
99b.bullet_collide_bullet()
100else:
101b.hit_my_tank(self.my_tank)
102ifb.live:
103b.display_bullet()
104else:
105ls.remove(b)
106
107defget_event(self):
108globalSCREEN_WIDTH, SCREEN_HEIGHT
109event_list = pygame.event.get()
110foreventinevent_list:
111ifevent.type == pygame.VIDEORESIZE:
112SCREEN_WIDTH, SCREEN_HEIGHT = event.size
113self.window = self.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.RESIZABLE,32)
114
115ifevent.type == pygame.QUIT:
116self.end_game()
117ifevent.type == pygame.KEYDOWN:
118ifevent.key == pygame.K_w:
119self.my_tank.direction = U
120elifevent.key == pygame.K_s:
121self.my_tank.direction = D
122elifevent.key == pygame.K_a:
123self.my_tank.direction = L
124elifevent.key == pygame.K_d:
125self.my_tank.direction = R
126else:
127returnNone
128self.my_tank.move_stop =False
129elifevent.type == pygame.MOUSEBUTTONDOWN:
130iflen(TankGame.my_bullet_list) <3:
131bullet = self.my_tank.fire()
132load_music( fire )
133TankGame.my_bullet_list.append(bullet)
134elifevent.type == pygame.KEYUP:
135self.my_tank.move_stop =True
136
137defend_game(self):
138self.display.quit()
139sys.exit()
140
141defdraw_text(self, content):
142text_sf = self.font.render(content,True, [255,0,0])
143returntext_sf
10. 入口
1if__name__ == __main__ :
2g = TankGame()
3g.start_game()
执行界面