"""坦克大战游戏(加深对面向对象编程的理解,此程序为作者初学pygame的练习作业,请多多指教。)
简介:《坦克大战》是由日本南梦宫Namco游戏公司开发的一款平面射击游戏,于1985年发售。游戏以坦克战斗及保卫基地为主题,属于策略型联机类。
同时也是FC平台上少有的内建关卡编辑器的几个游戏之一,玩家可自己创建独特的关卡,并通过获取一些道具使坦克和基地得到强化。"""
import pygame
import time
from datetime import datetime
from icecream import ic
import random
def time_format():
return f'{datetime.now()}|> '
screen_width = 800
screen_height = 600
bg_color = pygame.Color(0, 0, 0)
color_red = pygame.Color(255, 0, 0)
key_dict = {
pygame.K_UP: 'U', pygame.K_DOWN: 'D', pygame.K_LEFT: 'L', pygame.K_RIGHT: 'R'}
enemy_tank_count = 6
enemy_tank_list = []
my_bullet_list = []
enemy_bullet_list = []
my_bullet_image = pygame.image.load('坦克大战素材/my_bullet.png')
ic.configureOutput(prefix=time_format, includeContext=True)
ic(my_bullet_image)
enemy_bullet_image = pygame.image.load('坦克大战素材/enemy_bullet.png')
my_tank_images = {
'U': pygame.image.load('坦克大战素材/wu.gif'),
'D': pygame.image.load('坦克大战素材/wd.gif'),
'L': pygame.image.load('坦克大战素材/wl.gif'),
'R': pygame.image.load('坦克大战素材/wr.gif')
}
enemy_tank_images = {
'U': pygame.image.load('坦克大战素材/eu.gif'),
'D': pygame.image.load('坦克大战素材/ed.gif'),
'L': pygame.image.load('坦克大战素材/el.gif'),
'R': pygame.image.load('坦克大战素材/er.gif')
}
background_image = pygame.image.load('坦克大战素材/grass.png')
ic(background_image.get_rect())
explode_list = []
wall_list = []
wall_image = pygame.image.load('坦克大战素材/wall.gif')
my_tank_bullet_count = 5
wall_count = 6
"""主类:开始游戏、结束游戏"""
class MainGame:
window = None
my_tank = None
def __init__(self):
pass
def start_game(self):
pygame.display.init()
MainGame.window = pygame.display.set_mode((screen_width, screen_height), 0, 32)
pygame.display.set_caption('Battle City(坦克大战)version1.0')
self.create_my_tank()
self.create_enemy_tank()
self.create_wall()
while True:
MainGame.window.blit(background_image, (0, 0))
MainGame.window.blit(self.get_text_surface(f'敌方坦克数量:{len(enemy_tank_list)}台'), (10, 10))
self.get_event()
self.show_enemy_tank()
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.display_tank()
if MainGame.my_tank.switch:
MainGame.my_tank.tank_move()
MainGame.my_tank.tank_hit_wall()
MainGame.my_tank.my_tank_hit_enemy_tank()
else:
del MainGame.my_tank
MainGame.my_tank = None
self.show_wall()
self.show_my_bullet()
self.show_enemy_bullet()
self.show_explode()
time.sleep(0.02)
pygame.display.update()
def create_my_tank(self):
MainGame.my_tank = MyTank(screen_width / 2, screen_height / 2, 5, my_tank_images)
music = Music('坦克大战素材/start.wav')
music.play_music()
def create_enemy_tank(self):
top = 100
enemy_image = pygame.image.load('坦克大战素材/ed.gif')
enemy_image_width = enemy_image.get_rect().width
ic(enemy_image.get_rect())
ic(enemy_image.get_rect().width)
ic(list(enemy_image.get_rect())[3])
ic(enemy_image.get_width())
for i in range(enemy_tank_count):
left = random.randint(0, screen_width-enemy_image_width)
tolerance = random.randint(1, 3)
enemy_tank = EnemyTank(left, top, tolerance, enemy_tank_images)
enemy_tank_list.append(enemy_tank)
def create_wall(self):
for i in range(wall_count):
wall_left = random.randint(0, screen_width - wall_image.get_width())
wall_top = random.randint(0, screen_height - wall_image.get_height())
wall = Wall(wall_left, wall_top, wall_image)
wall_list.append(wall)
def get_text_surface(self, text):
pygame.font.init()
font = pygame.font.SysFont('kaiti', 18)
text_surface = font.render(text, True, color_red)
return text_surface
def get_event(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
print('welcome back next time!')
exit()
elif event.type == pygame.KEYDOWN:
if not MainGame.my_tank and event.key == pygame.K_z:
self.create_my_tank()
if MainGame.my_tank and MainGame.my_tank.live:
for pygamekey, direction in key_dict.items():
if event.key == pygamekey:
ic(event)
ic(event.key)
MainGame.my_tank.direction = direction
MainGame.my_tank.switch = True
ic(f'{MainGame.my_tank.direction},move up')
if event.key == pygame.K_SPACE:
ic('we fire bullets')
if len(my_bullet_list) < my_tank_bullet_count:
my_bullet = Bullet(MainGame.my_tank, my_bullet_image)
my_bullet_list.append(my_bullet)
music = Music('坦克大战素材/fire.wav')
music.play_music()
else:
ic('The bullet is insufficient, no more bullets')
elif event.type == pygame.KEYUP and event.key in key_dict.keys():
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.switch = False
def show_enemy_tank(self):
for enemy_tank in enemy_tank_list:
if enemy_tank.live:
enemy_tank.display_tank()
enemy_tank.rand_move()
enemy_tank.tank_hit_wall()
enemy_tank.enemy_tank_hit_my_tank()
num = random.randint(1, 1000)
if num <= 20:
enemy_bullet = Bullet(enemy_tank, enemy_bullet_image)
enemy_bullet_list.append(enemy_bullet)
else:
enemy_tank_list.remove(enemy_tank)
def show_my_bullet(self):
for my_bullet in my_bullet_list:
if my_bullet.live:
my_bullet.display_bullet()
my_bullet.bullet_move()
Bullet.my_bullet_hit_enemy_tank(my_bullet)
Bullet.bullet_hit_wall(my_bullet)
else:
my_bullet_list.remove(my_bullet)
def show_enemy_bullet(self):
for enemy_bullet in enemy_bullet_list:
if enemy_bullet.live:
enemy_bullet.display_bullet()
enemy_bullet.bullet_move()
Bullet.bullet_hit_wall(enemy_bullet)
if MainGame.my_tank and MainGame.my_tank.live:
Bullet.enemy_bullet_hit_my_tank(enemy_bullet)
else:
enemy_bullet_list.remove(enemy_bullet)
def show_explode(self):
for explode in explode_list:
if explode.live:
explode.display_explode()
else:
explode_list.remove(explode)
def show_wall(self):
for wall in wall_list:
if wall.live:
wall.display_wall()
else:
wall_list.remove(wall)
class BaseItem(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
"""坦克类:显示坦克、移动。(坦克射击的效果由子弹类生成)"""
class Tank(BaseItem):
def __init__(self, left, top, tolerance, images):
self.images = images
self.direction = random.choice(list(key_dict.values()))
self.image = self.images[self.direction]
ic(self.image.get_rect())
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
self.tolerance = tolerance
self.switch = False
self.live = True
self.preleft = self.rect.left
self.pretop = self.rect.top
def display_tank(self):
self.image = self.images[self.direction]
MainGame.window.blit(self.image, self.rect)
def tank_move(self):
self.preleft = self.rect.left
self.pretop = self.rect.top
if self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.tolerance
elif self.direction == 'R':
if self.rect.left+self.rect.height < screen_width:
self.rect.left += self.tolerance
elif self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.tolerance
elif self.direction == 'D':
if self.rect.top+self.rect.height < screen_height:
self.rect.top += self.tolerance
def restore(self):
self.rect.left = self.preleft
self.rect.top = self.pretop
def tank_hit_wall(self):
for wall in wall_list:
if pygame.sprite.collide_rect(self, wall):
self.restore()
"""敌方坦克类"""
class EnemyTank(Tank):
def __init__(self, left, top, tolerance, images):
super(EnemyTank, self).__init__(left, top, tolerance, images)
self.step = 60
def rand_move(self):
if self.step <= 0:
self.direction = random.choice(list(key_dict.values()))
self.step = 60
else:
self.tank_move()
self.step -= 1
def enemy_tank_hit_my_tank(self):
if MainGame.my_tank and MainGame.my_tank.live:
if pygame.sprite.collide_rect(self, MainGame.my_tank):
self.restore()
"""我方坦克类"""
class MyTank(Tank):
def __init__(self, left, top, tolerance, images):
super(MyTank, self).__init__(left, top, tolerance, images)
def my_tank_hit_enemy_tank(self):
for enemy_tank in enemy_tank_list:
if pygame.sprite.collide_rect(self, enemy_tank):
self.restore()
"""子弹类:显示、移动"""
class Bullet(BaseItem):
def __init__(self, tank, image):
self.image = image
self.direction = tank.direction
self.rect = self.image.get_rect()
if self.direction == 'U':
self.rect.left = tank.rect.left+tank.rect.width/2-self.rect.width/2
self.rect.top = tank.rect.top-self.rect.height
if self.direction == 'D':
self.rect.left = tank.rect.left+tank.rect.width/2-self.rect.width/2
self.rect.top = tank.rect.top+tank.rect.height
if self.direction == 'L':
self.rect.left = tank.rect.left-self.rect.width
self.rect.top = tank.rect.top+tank.rect.width/2-self.rect.width/2
if self.direction == 'R':
self.rect.left = tank.rect.left+tank.rect.height
self.rect.top = tank.rect.top+tank.rect.width/2-self.rect.width/2
self.tolerance = 6
self.live = True
def display_bullet(self):
MainGame.window.blit(self.image, self.rect)
def bullet_move(self):
if self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.tolerance
else:
self.live = False
elif self.direction == 'D':
if self.rect.top + self.rect.height < screen_height:
self.rect.top += self.tolerance
else:
self.live = False
elif self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.tolerance
else:
self.live = False
elif self.direction == 'R':
if self.rect.left + self.rect.width < screen_width:
self.rect.left += self.tolerance
else:
self.live = False
def my_bullet_hit_enemy_tank(self):
for enemy_tank in enemy_tank_list:
if pygame.sprite.collide_rect(enemy_tank, self):
music = Music('坦克大战素材/hit.wav')
music.play_music()
enemy_tank.live = False
self.live = False
explode = Explode(enemy_tank)
explode_list.append(explode)
def enemy_bullet_hit_my_tank(self):
if pygame.sprite.collide_rect(MainGame.my_tank, self):
explode = Explode(MainGame.my_tank)
music = Music('坦克大战素材/hit.wav')
music.play_music()
explode_list.append(explode)
self.live = False
MainGame.my_tank.live = False
def bullet_hit_wall(self):
for wall in wall_list:
if pygame.sprite.collide_rect(wall, self):
music = Music('坦克大战素材/hit.wav')
music.play_music()
self.live = False
wall.hp -= 1
if wall.hp < 0:
wall.live = False
"""爆炸效果类:展示爆炸"""
class Explode:
def __init__(self, tank):
self.rect = tank.rect
self.images = [
pygame.image.load('坦克大战素材/blast0.gif'),
pygame.image.load('坦克大战素材/blast1.gif'),
pygame.image.load('坦克大战素材/blast2.gif'),
pygame.image.load('坦克大战素材/blast3.gif'),
pygame.image.load('坦克大战素材/blast4.gif')
]
self.step = 0
self.image = self.images[self.step]
self.live = True
def display_explode(self):
if self.step < len(self.images):
self.image = self.images[self.step]
MainGame.window.blit(self.image, self.rect)
self.step += 1
else:
self.live = False
self.step = 0
"""墙壁类:是否通过墙壁"""
class Wall:
def __init__(self, left, top, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
self.live = True
self.hp = 3
def display_wall(self):
MainGame.window.blit(self.image, self.rect)
"""音效类:播放音乐"""
class Music:
def __init__(self, filename):
self.filename = filename
pygame.mixer.init()
pygame.mixer.music.load(self.filename)
def play_music(self):
pygame.mixer.music.play(loop
[video(video-NsuU6cVA-1612278054153)(type-undefined)(url-undefined)(image-https://img-blog.csdnimg.cn/editor-video.png)(title-undefined)]
s=1)
if __name__ == '__main__':
MainGame().start_game()