'''尚学堂学习笔记,用于复习'''
一.下载pygame,在cmd输入命令pip install pygame(也可以直接在pycharm中import pygame, 提示你没有pygame,然后直接安装即可)
二.分析项目需求:
坦克大战游戏的基本需求:
1).项目中需要定义的类
2).每个类对应的方法
1.坦克类
显示坦克
移动
射击
2.子弹
显示子弹
移动
击中敌方坦克时产生的影响
3.墙壁类
显示墙壁(是否可以通过)
4.击中地方坦克爆炸效果
展示爆炸效果
5.音效
播放音乐
6.主类(采用面向对象的方法进行开发)
开始游戏
结束游戏
三.根据项目需求搭建项目框架:
# 主类
class MainGame():
def __init(self):
pass
# 开始游戏
def startGame(self):
pass
# 结束游戏
def endGame(self):
pass
# 坦克类
class Tank():
def __init(self):
pass
# 展示坦克
def dispalyTank(self):
pass
# 移动坦克
def move(self):
pass
# 射击
def shot(self):
pass
# 我方坦克
class MyTank(Tank):
def __init__(self):
pass
# 敌方坦克
class EnemyTank(Tank):
def __init__(self):
pass
# 子弹类
class Bullet():
def __init__(self):
pass
# 移动
def move(self):
pass
# 展示子弹
def displayBullet(self):
pass
# 墙壁类
class Wall():
def __init__(self):
pass
# 展示墙壁
def dispalyWall(self):
pass
# 爆炸类
class Explode():
def __init__(self):
pass
# 展示爆炸效果
def displayExplode(self):
pass
# 音乐类
class Music():
def __init(self):
pass
# 播放音乐
def play(self):
pass
之后要开发各项功能需要调用pygame的内容,可以在pygame官网查询相关功能的调用方法,多用几次就熟悉了
1.在chrome网址栏搜索www.pygame.org进入,并打开chrome自带的翻译功能(英语大佬忽略)
2.点击文档进入后即可根据需要找到需要的函数方法进行使用
加一点点细节
#coding=utf-8
import pygame
import time
import random
# 设定窗口的大小
SCREEN_WIDTH = 800; SCREEN_HEIGHT = 600
# 设定窗口背景色
# BG_COLOR = "#ff0000"
# BG_COLOR = pygame.Color(0, 0, 0)
BG_COLOR = "white"
# 设定左上角文本颜色
TEXT_COLOR = pygame.Color(255, 0, 0)
# 定义精灵类的基类
class BaseItem(pygame.sprite.Sprite):
def __init__(self, color, width, height):
pygame.sprite.Sprite.__init__(self)
# 主类
class MainGame():
window = None
my_tank = None
# 存储敌方坦克的列表
enemyTankList = []
enemyTankCount = 5
# 存储我方子弹的列表
my_BulletList = []
# 存储敌方子弹的列表
enemyBulletList = []
# 存储爆炸对象的列表
explodeList = []
# 存储墙壁的列表
wallList = []
def __init(self):
pass
# 开始游戏
def startGame(self):
# 初始化显示模块
pygame.display.init()
# 初始化显示窗口
MainGame.window = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
# 初始化我方坦克
self.create_my_tank()
# 初始化敌方坦克并将敌方坦克添加到列表中
self.createEnemyTank()
# 初始化墙壁
self.createWall()
# 设置当前窗口标题
pygame.display.set_caption("坦克大战1")
# 更新软件显示的屏幕部分
while True:
# 使坦克移动的速度慢一点
time.sleep(0.02)
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 获取事件
self.getEvent()
# 绘制左上角文字
MainGame.window.blit(self.getTextSurface("敌方坦克数量:{0}".format(len(MainGame.enemyTankList))), (10, 10))
# 调用坦克显示的方法
# MainGame.my_tank.dispalyTank()
# 如果我方坦克存活才进行调用
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.dispalyTank()
else:
del MainGame.my_tank
MainGame.my_tank = None
# 循环遍历爆炸列表,展示爆炸效果
self.blitWall()
# 循环遍历敌方坦克,展示敌方坦克
self.blitEnemyTank()
# 循环遍历显示我方子弹
self.blitMyBullet()
# 循环遍历敌方子弹列表
self.blitEnemyBullet()
# 循环遍历爆炸列表
self.blitExplode()
# 坦克移动开关
if MainGame.my_tank and MainGame.my_tank.live:
if not MainGame.my_tank.stop:
MainGame.my_tank.move()
MainGame.my_tank.hitWall()
MainGame.my_tank.myTank_hit_enemyTank()
# 窗口持续更新
pygame.display.update()
# 创建墙壁的方法
def createWall(self):
for i in range(4):
# 初始化墙壁
wall = Wall(i * 220, 220)
# 将墙壁添加到列表中
MainGame.wallList.append(wall)
# 创建我方坦克的方法
def create_my_tank(self):
MainGame.my_tank = MyTank(350, 400)
# 创建music对象
music = Music("img/start.wav")
# 播放音乐
music.play()
def blitWall(self):
for wall in MainGame.wallList:
if wall.live:
wall.dispalyWall()
else:
MainGame.wallList.remove(wall)
def createEnemyTank(self):
top = 100
for i in range(MainGame.enemyTankCount):
left = random.randint(0, 600)
speed = random.randint(1, 4)
enemy = EnemyTank(left, top, speed)
MainGame.enemyTankList.append(enemy)
def blitExplode(self):
for explode in MainGame.explodeList:
if explode.live:
explode.displayExplode()
else:
MainGame.explodeList.remove(explode)
def blitEnemyTank(self):
for enemyTank in MainGame.enemyTankList:
if enemyTank.live:
enemyTank.dispalyTank()
enemyTank.randMove()
# 发射子弹
enemyBullet = enemyTank.shot()
if enemyBullet:
# 将敌方子弹存储到敌方子弹列表中
MainGame.enemyBulletList.append(enemyBullet)
else:
MainGame.enemyTankList.remove(enemyTank)
def blitMyBullet(self):
for myBullet in MainGame.my_BulletList:
if myBullet.live:
myBullet.displayBullet()
myBullet.move()
myBullet.myBullet_hit_enemyTank()
myBullet.hitWall()
else:
MainGame.my_BulletList.remove(myBullet)
def blitEnemyBullet(self):
for enemyBullet in MainGame.enemyBulletList:
if enemyBullet.live:
enemyBullet.displayBullet()
enemyBullet.move()
# 展现敌方子弹后,调用敌方子弹与我方坦克碰撞的方法
enemyBullet.enemyBullet_hit_myTank()
enemyBullet.hitWall()
else:
MainGame.enemyBulletList.remove(enemyBullet)
# 结束游戏
def endGame(self):
print("感谢您的使用!")
exit()
# 设计左上角文本
def getTextSurface(self, text):
# 初始化字体模块
pygame.font.init()
# 获取字体对象
font = pygame.font.SysFont("kaiti", 18)
# 绘制文字信息
textSurface = font.render(text, True, TEXT_COLOR)
return textSurface
# 获取事件
def getEvent(self):
# 获取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
self.endGame()
if event.type == pygame.KEYDOWN:
# 当敌方坦克被消灭完时
if len(MainGame.enemyTankList) == 0:
if event.key == pygame.K_o:
self.createEnemyTank()
# 当坦克不存在时
if not MainGame.my_tank:
if event.key == pygame.K_f:
self.create_my_tank()
if MainGame.my_tank and MainGame.my_tank.live:
if event.key == pygame.K_LEFT:
MainGame.my_tank.direction = "L"
MainGame.my_tank.stop = False
MainGame.my_tank.move()
print("坦克向左移动")
if event.key == pygame.K_RIGHT:
MainGame.my_tank.direction = "R"
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print("坦克向右移动")
if event.key == pygame.K_UP:
MainGame.my_tank.direction = "U"
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print("坦克向上移动")
if event.key == pygame.K_DOWN:
MainGame.my_tank.direction = "D"
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print("坦克向下移动")
if event.key == pygame.K_SPACE:
print("发射子弹")
if len(MainGame.my_BulletList) < 3:
# 创建子弹
myBullet = Bullet(MainGame.my_tank)
MainGame.my_BulletList.append(myBullet)
music = Music("img/shot.wav")
music.play()
if event.type == pygame.KEYUP:
if not event.key == pygame.K_SPACE:
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.stop = True
# 坦克类
class Tank(BaseItem):
def __init__(self, left, top):
# 保存加载的图片
self.images = \
{
"U" : pygame.image.load("img/my_tank_up.png"),
"D" : pygame.image.load("img/my_tank_down.png"),
"L" : pygame.image.load("img/my_tank_left.png"),
"R" : pygame.image.load("img/my_tank_right.png")
}
# 方向
self.direction = "U"
# 根据方向获取图片
self.image = self.images[self.direction]
self.rect = self.image.get_rect()
#设置区域的left和top
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 dispalyTank(self):
# 获取展示对象
self.image = self.images[self.direction]
# 调用blit方法展示
MainGame.window.blit(self.image, self.rect)
# 碰撞后不进行移动
def stay(self):
self.rect.left = self.oldLeft
self.rect.top = self.oldTop
# 检测坦克是否与墙壁发生碰撞
def hitWall(self):
for wall in MainGame.wallList:
if pygame.sprite.collide_rect(self, wall):
self.stay()
# 移动坦克
def move(self):
# 判断坦克的方向进行移动
# 移动后记录原始坐标
self.oldLeft = self.rect.left
self.oldTop = self.rect.top
if self.direction == "U":
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == "D":
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
self.rect.top += self.speed
elif self.direction == "L":
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == "R":
if self.rect.left + self.rect.height < SCREEN_WIDTH:
self.rect.left += self.speed
# 射击
def shot(self):
return Bullet(self)
# 我方坦克
class MyTank(Tank):
def __init__(self, left, top):
super().__init__(left, top)
def myTank_hit_enemyTank(self):
# 循环遍历敌方坦克列表
for enemyTank in MainGame.enemyTankList:
if pygame.sprite.collide_rect(self, enemyTank):
self.stay()
# 敌方坦克
class EnemyTank(Tank):
def __init__(self, left, top, speed):
super().__init__(left, top)
# 保存加载的图片
self.images = \
{
"U": pygame.image.load("img/my_tank_up.png"),
"D": pygame.image.load("img/my_tank_down.png"),
"L": pygame.image.load("img/my_tank_left.png"),
"R": pygame.image.load("img/my_tank_right.png")
}
# 方向,随机生成坦克方向
self.direction = self.randDirection()
# 根据方向获取图片
self.image = self.images[self.direction]
# 区域
self.rect = self.image.get_rect()
# 对left和top进行赋值
self.rect.left = left
self.rect.top = top
# 对速度speed赋值
self.speed = speed
# 移动开关
self.flag = True
# 步数,用于随机移动
self.step = 60
# 敌方坦克与我方坦克发生碰撞
def enemyTank_hit_myTank(self):
if pygame.sprite.collide_rect(self, MainGame.my_tank):
self.stay()
def randDirection(self):
num = random.randint(1, 4)
if num == 1:
return "U"
elif num == 2:
return "D"
elif num == 3:
return "L"
elif num == 4:
return "R"
def randMove(self):
if self.step <= 0:
# 修改方向
self.step = 60
self.direction = self.randDirection()
else:
self.move()
self.hitWall()
if MainGame.my_tank and MainGame.my_tank.live:
self.enemyTank_hit_myTank()
#让步数递减
self.step -= 1
def shot(self):
num = random.randint(1, 100)
if num == 1:
return Bullet(self)
# 子弹类
class Bullet(BaseItem):
def __init__(self, tank):
# 加载图片
self.image = pygame.image.load("img/bullet.png")
# 坦克的方向决定子弹的方向
self.direction = tank.direction
# 获取区域
self.rect = self.image.get_rect()
# 子弹的left和top与方向有关
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 == "L":
self.rect.left = tank.rect.left
self.rect.top = tank.rect.top + tank.rect.height/2 - self.rect.height/2
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
# 子弹的速度
self.speed = 6
#子弹的状态
self.live = True
# 我方子弹与敌方坦克碰撞
def myBullet_hit_enemyTank(self):
for enemyTank in MainGame.enemyTankList:
if pygame.sprite.collide_rect(enemyTank, self):
# 修改敌方坦克和我方子弹状态
enemyTank.live = False
self.live = False
explode = Explode(enemyTank)
#将爆炸对象添加到爆炸列表中
MainGame.explodeList.append(explode)
# 子弹是否碰撞墙壁
def hitWall(self):
# 循环遍历墙壁列表
for wall in MainGame.wallList:
if pygame.sprite.collide_rect(self, wall):
# 修改子弹的生存状态,让子弹消失
self.live = False
wall.hp -= 1
if wall.hp <= 0:
wall.live = False
# 敌方子弹与我方坦克碰撞
def enemyBullet_hit_myTank(self):
if MainGame.my_tank and MainGame.my_tank.live:
if pygame.sprite.collide_rect(MainGame.my_tank, self):
self.live = False
MainGame.my_tank.live = False
explode = Explode(MainGame.my_tank)
MainGame.explodeList.append(explode)
# 移动
def move(self):
if self.direction == "U":
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.live = False
if self.direction == "D":
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
self.rect.top += self.speed
else:
self.live = False
if self.direction == "L":
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.live = False
if self.direction == "R":
if self.rect.left + self.rect.width < SCREEN_WIDTH:
self.rect.left += self.speed
else:
self.live = False
# 展示子弹
def displayBullet(self):
# 将图片surface加载到窗口
MainGame.window.blit(self.image, self.rect)
# 墙壁类
class Wall():
def __init__(self, left, top):
# 加载墙壁图片
self.image = pygame.image.load("img/wall.png")
# 获取墙壁的区域
self.rect = self.image.get_rect()
# 设置位置
self.rect.left = left
self.rect.top = top
self.live = True
self.hp = 10
# 展示墙壁
def dispalyWall(self):
MainGame.window.blit(self.image, self.rect)
# 爆炸类
class Explode():
def __init__(self, tank):
self.rect = tank.rect
self.images = \
[
pygame.image.load("img/explode1.png"),
pygame.image.load("img/explode2.png"),
pygame.image.load("img/explode3.png"),
pygame.image.load("img/explode4.png"),
]
self.step = 0
self.image = self.images[self.step]
self.live = True
# 展示爆炸效果
def displayExplode(self):
if self.step < len(self.images):
self.image = self.images[self.step]
self.step += 1
MainGame.window.blit(self.image, self.rect)
else:
self.live = False
self.step = 0
# 音乐类
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()
if __name__ == "__main__":
MainGame().startGame()
效果图
代码中插入图像可以自己画,音效可以自己录制也可以上网搜索,这个程序基本实现了坦克大战的功能,按上下左右键可以移动我方坦克,按空格键可以射击,且对子弹对象做了限制,即最多存在三个我方的子弹对象,敌方坦克随机生成,随机移动,随机射击,射击频率可调,按f键可以令我方坦克复活,按o键当敌方坦克全部死亡后可以令敌方坦克复活。
其他功能也可以在已有的框架上进行添加,例如添加一个分数变量,每消灭一辆敌方坦克就让分数加1,也可给己方坦克增加hp属性,最多复活2次等等,并可以设置一些其它音效,也可以增加一些buff对象,如让坦克射击次数得到增加等等,这些功能都可以在已有的框架下进行添加。
|