最近在学习python,跟着视频完整的码了《坦克大战》这个小游戏,切身体会了面向对象分析编程的过程,逻辑清晰,不像我学之前面对整个问题无从下手,总之是很有逻辑和条理一步步写代码,这种码代码方式是比较快乐的。我也整理了思维导图和相关代码、图片、音频资源附在最后,供有需要的朋友取用。第一次成功完成游戏制作,挺有意义,记录一下。
"""
v2.0 小游戏初步完成
"""
import pygame, time,random
COLOR_RED = pygame.Color(255, 0, 0)
COLOR_BLACK = pygame.Color(0, 0, 0)
version = 'v2.0'
class MainGame():
# 游戏主窗口
window = None
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 500
Tank_My = None
EnemyTank_list = []
EnemyTank_num = 5
Enemy_bullet_list=[]
Explode_list=[]
Bullet_list=[]
Wall_list=[]
def __init__(self):
pass
def startgame(self):
pygame.display.init()
MainGame.window = pygame.display.set_mode([MainGame.SCREEN_WIDTH, MainGame.SCREEN_HEIGHT])
pygame.display.set_caption("坦克大战" + version)
self.creatMyTank()
self.creatEnemyTank()
self.creatWalls()
# 让窗口持续刷新
while True:
MainGame.window.fill(COLOR_BLACK)
# self.getTextSurface()
# 在循环中持续获取事件
self.getevent()
# 将绘制得到的小画布,黏贴到窗口中
MainGame.window.blit(self.getTextSurface("剩余敌方坦克%d辆" % len(MainGame.EnemyTank_list)), (5, 10))
self.blitWalls()
self.blitEnemyTank()
if MainGame.Tank_My and not MainGame.Tank_My.stop:
MainGame.Tank_My.move()
MainGame.Tank_My.hitWalls()
MainGame.Tank_My.hitEnemyTank()
self.blitBullet()
self.blitEnemyBullet()
self.displayExplodes()
if MainGame.Tank_My and MainGame.Tank_My.live:
MainGame.Tank_My.display()
else:
del MainGame.Tank_My
MainGame.Tank_My=None
time.sleep(0.02)
pygame.display.update()
def getevent(self):
# 1.获取所有事件
eventlist = pygame.event.get()
for event in eventlist:
# 判断事件类型event.type是否为退出QUIT,如果是退出的话,直接调用程序结束方法
if event.type == pygame.QUIT:
self.endgame()
if MainGame.Tank_My and MainGame.Tank_My.live:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("坦克向左移动")
MainGame.Tank_My.direction = 'L'
MainGame.Tank_My.stop = False
elif event.key == pygame.K_RIGHT:
print("坦克向右移动")
MainGame.Tank_My.direction = 'R'
MainGame.Tank_My.stop = False
elif event.key == pygame.K_DOWN:
print("坦克向下移动")
MainGame.Tank_My.direction = 'D'
MainGame.Tank_My.stop = False
elif event.key == pygame.K_UP:
print("坦克向上移动")
MainGame.Tank_My.direction = 'U'
MainGame.Tank_My.stop = False
elif event.key == pygame.K_SPACE:
print("坦克发射子弹")
MainGame.Tank_My.stop = True
if len(self.Bullet_list)<3:
# 产生一颗子弹
m = Bullet(MainGame.Tank_My)
# 将子弹加入列表
self.Bullet_list.append(m)
music=Music('musics/fire.wav')
music.play()
elif event.type == pygame.KEYUP:
# 松开如果是方向键才处理
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN or event.key == pygame.K_UP:
MainGame.Tank_My.stop = True
if event.key == pygame.K_SPACE:
MainGame.Tank_My.stop = True
elif event.type==pygame.KEYDOWN and event.key==pygame.K_ESCAPE:
self.creatMyTank()
#创建敌方坦克
def creatWalls(self):
for i in range(1,4):
wall=Wall(180*i,250)
MainGame.Wall_list.append(wall)
def creatEnemyTank(self):
top=100
speed=2
for i in range(MainGame.EnemyTank_num):
left = random.randint(1, 5)
eTank=enemyTank(100*left,top,speed*left)
MainGame.EnemyTank_list.append(eTank)
def creatMyTank(self):
MainGame.Tank_My = myTank(400, 400)
music=Music('musics/start.wav')
music.play()
def blitWalls(self):
for wall in MainGame.Wall_list:
if wall.live:
wall.displayWall()
else:
MainGame.Wall_list.remove(wall)
#将坦克加入到窗口中
def blitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if eTank.live:
eTank.display()
eTank.randMove()
eTank.hitWalls()
if MainGame.Tank_My and MainGame.Tank_My.live:
eTank.hitMyTank()
eBullet=eTank.shot()
if eBullet:
MainGame.Enemy_bullet_list.append(eBullet)
else:
MainGame.EnemyTank_list.remove(eTank)
def blitMyTank(self):
if self.Tank_My and self.Tank_My.live:
myTank.display(self)
def blitBullet(self):
#将子弹加入到窗口中
for bullet in MainGame.Bullet_list:
if bullet.live:
Bullet.displayBullet(bullet)
Bullet.move(bullet)
bullet.hitEnemyTank()
bullet.hitWalls()
else:
MainGame.Bullet_list.remove(bullet)
def blitEnemyBullet(self):
for eBullet in MainGame.Enemy_bullet_list:
if eBullet.live:
Bullet.displayBullet(eBullet)
Bullet.move(eBullet)
if MainGame.Tank_My and MainGame.Tank_My.live:
eBullet.hitMyTank()
eBullet.hitWalls()
else:
MainGame.Enemy_bullet_list.remove(eBullet)
def displayExplodes(self):
for explode in MainGame.Explode_list:
if explode.live:
explode.displayExplode()
music=Music('musics/bang.wav')
music.play()
else:
MainGame.Explode_list.remove(explode)
def getTextSurface(self, text):
pygame.font.init()
font = pygame.font.SysFont('kaiti', 18)
surface = font.render(text, True, COLOR_RED)
return surface
def endgame(self):
print("谢谢使用")
exit()
class BaseItem(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Tank(BaseItem):
def __init__(self, left, top):
self.images = {
'U': pygame.image.load("images/WU.gif"),
'D': pygame.image.load("images/WD.gif"),
'L': pygame.image.load("images/WL.gif"),
'R': pygame.image.load("images/WR.gif"),
}
self.direction = 'U'
self.image = self.images[self.direction]
# 获取坦克的大小
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
# 速度属性
self.speed = 5
# 新增属性:坦克的移动开关
self.stop = True
self.live=True
#新增属性:用来记录移动之前的坐标
self.oldLeft=self.rect.left
self.oldTop=self.rect.top
def move(self):
self.oldLeft = self.rect.left
self.oldTop = self.rect.top
if self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'R':
if self.rect.left + self.rect.width < MainGame.SCREEN_WIDTH:
self.rect.left += self.speed
elif self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == 'D':
if self.rect.top + self.rect.height < MainGame.SCREEN_HEIGHT:
self.rect.top += self.speed
def shot(self):
return Bullet(self)
def stay(self):
self.rect.left=self.oldLeft
self.rect.top=self.oldTop
def hitWalls(self):
for wall in MainGame.Wall_list:
if pygame.sprite.collide_rect(self,wall):
self.stay()
def display(self):
# 1.重新设置坦克的图片
self.image = self.images[self.direction]
# 2.将坦克加入到窗口中
MainGame.window.blit(self.image, self.rect)
class myTank(Tank):
def __init__(self,left,top):
super(myTank,self).__init__(left,top)
def hitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if pygame.sprite.collide_rect(self,eTank):
self.stay()
class enemyTank(Tank):
def __init__(self, left, top,speed):
# 图片集
self.images = {
'U': pygame.image.load("images/EU.gif"),
'D': pygame.image.load("images/ED.gif"),
'L': pygame.image.load("images/EL.gif"),
'R': pygame.image.load("images/ER.gif"),
}
self.direction = self.randDirection()
self.image = self.images[self.direction]
# 获取坦克的大小
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
# 速度属性
self.speed = speed
#新增步数属性,控制敌方坦克移动
self.step=20
self.live=True
def randDirection(self):
num=random.randint(1,4)
if num==1 :
return 'U'
elif num==2:
return 'D'
elif num==3:
return 'R'
elif num==4:
return 'L'
def randMove(self):
if self.step<=0:
self.direction=self.randDirection()
self.step=30
else:
self.move()
self.step -=1
def shot(self):
if random.randint(1,50)==1:
return Bullet(self)
def hitMyTank(self):
if pygame.sprite.collide_rect(self,MainGame.Tank_My):
self.stay()
class Bullet(BaseItem):
def __init__(self,tank):
# 方向(坦克方向)
self.direction=tank.direction
#图片
self.images={
'U':pygame.image.load("images/MU.gif"),
'D': pygame.image.load("images/MD.gif"),
'R': pygame.image.load("images/MR.gif"),
'L': pygame.image.load("images/ML.gif"),
}
self.image=self.images[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
elif 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
elif self.direction == 'R':
self.rect.left = tank.rect.left + tank.rect.width
self.rect.top += tank.rect.top + tank.rect.height/2-self.rect.height/2
elif self.direction == 'L':
self.rect.left = tank.rect.left - self.rect.width
self.rect.top += tank.rect.top + tank.rect.height/2-self.rect.height/2
#速度
self.speed=7
self.live=True
def move(self):
if self.direction=='U':
if self.rect.top>0:
self.rect.top-=self.speed
else:
self.live=False
elif self.direction=='D':
if self.rect.top+self.rect.height<MainGame.SCREEN_HEIGHT:
self.rect.top+=self.speed
else:
self.live=False
elif self.direction=='R':
if self.rect.left+self.rect.width<MainGame.SCREEN_WIDTH:
self.rect.left+=self.speed
else:
self.live=False
elif self.direction=='L':
if self.rect.left-self.rect.width>0:
self.rect.left-=self.speed
else:
self.live=False
def displayBullet(self):
MainGame.window.blit(self.image,self.rect)
def hitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if pygame.sprite.collide_rect(eTank,self):
explode=Explode(eTank)
MainGame.Explode_list.append(explode)
self.live=False
eTank.live=False
Explode.displayExplode(eTank)
def hitMyTank(self):
if pygame.sprite.collide_rect(MainGame.Tank_My,self):
explode=Explode(MainGame.Tank_My)
MainGame.Explode_list.append(explode)
MainGame.Tank_My.live=False
self.live=False
def hitWalls(self):
for wall in MainGame.Wall_list:
if pygame.sprite.collide_rect(wall,self):
self.live=False
if wall.hp>0:
wall.hp-=1
else:
wall.live=False
class Explode():
def __init__(self,tank):
self.rect=tank.rect
self.step=0
self.images=[
pygame.image.load('images/0.gif'),
pygame.image.load('images/1.gif'),
pygame.image.load('images/2.gif'),
pygame.image.load('images/3.gif'),
pygame.image.load('images/4.gif'),
pygame.image.load('images/5.gif'),
pygame.image.load('images/6.gif'),
pygame.image.load('images/7.gif')
]
self.live=True
self.image=self.images[self.step ]
def displayExplode(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.step=0
self.live=False
class Wall():
def __init__(self,left,top):
self.image=pygame.image.load('images/wall.gif')
self.rect=self.image.get_rect()
self.rect.left=left
self.rect.top=top
self.live=True
self.hp=3
def displayWall(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(self):
pygame.mixer.music.play()
MainGame().startgame()
思维导图(自己制作,存在漏写和不规范问题):
需要更多格式图片(.svg/.jpg/.xmind)以及代码、游戏所需图片和音频的朋友,可以通过百度网盘自行下载:链接:https://pan.baidu.com/s/1W9yAfdmIDubvv2wO60HXeg
提取码:0226
#如有侵权立马删除