手把手教你用Python实现“坦克大战”,附详细代码!

小时候玩的“坦克大战”,你还记得吗?

满满的回忆

今天,我们使用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()

执行界面

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容