第一次使用CSDN,记录我的第一个500多行的代码, 本次创作使用python3中pygame模块,采用面向对象编程, 语法内容参照pygame官网中的使用文档, 创作对象是坦克大战小游戏2.0 。
简单的功能描述:
运行后进入游戏开始菜单界面
如上图,该游戏有三个菜单,分别为开始游戏、游戏结束和帮助按钮。
点击开始游戏,直接进入游戏画面,准备play,含有进入音效和发射子弹的音效
点击游戏结束,关闭游戏窗口,进程结束
点击帮助,进入帮助界面,内含作者信息和游戏的玩法介绍,在帮助界面下方还有一个返回按钮,用于返回上图开始菜单界面
附图如下:
由于没有合适的图片进行插入,画面不能做的更加美观,游戏没有添加结束画面,不够完善,将在下次3.0版本中进行更新与修改。
附上代码如下:
import pygame
import time
import random
from pygame.sprite import Sprite
screen_width = 750
screen_height = 500
bg_color = pygame.Color(0, 0, 0)
text_color = pygame.Color(255, 0, 0)
class BaseItem(Sprite):
def __init__(self, color, width, height):
pygame.sprite.Sprite.__init__(self)
class MainGame():
window = None
my_tank = None
enemyTankList = [] # 存储敌方坦克的列表
enemyTankCount = 5 # 定义敌方坦克数量
myBulletList = [] # 存储我方子弹的列表
enemyBulletList = [] # 存储敌方子弹的列表
explodeList = [] # 存储爆炸效果的列表
wallList = [] # 存储墙壁的列表
s1 = "img/startgame01.gif"
e1 = "img/endgame01.gif"
h1 = "img/help01.gif"
ba = "img/back.gif"
def __init__(self):
pass
def startSurface(self):
button1 = Button(260, 80, MainGame.s1)
button2 = Button(260, 180, MainGame.e1)
button3 = Button(320, 280, MainGame.h1)
var = pygame.display.init # 初始化主窗口
MainGame.window = pygame.display.set_mode([screen_width, screen_height]) # 设置主窗口的大小并显示
pygame.display.set_caption("坦克大战2.0") # 设置窗口的标题
while True:
MainGame.window.fill(bg_color) # 设置主窗口的填充色
button1.displayButton()
button2.displayButton()
button3.displayButton()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if button1.isOver() == True: # 如果按下的是button1,即开始游戏
self.startGame()
elif button2.isOver() == True: # 如果按下的是button2,即游戏结束
self.endGame()
elif button3.isOver() == True: # 如果按下的是button3,即游戏帮助
self.helpGame()
if event.type == pygame.QUIT: # 关闭键
self.endGame()
pygame.display.update()
def startGame(self):
var = pygame.display.init # 初始化主窗口
MainGame.window = pygame.display.set_mode([screen_width, screen_height]) # 设置主窗口的大小并显示
pygame.display.set_caption("坦克大战2.0") # 设置窗口的标题
self.createMyTank() # 初始化我方坦克
self.createEnemyTank() # 初始化敌方坦克
self.createWall() # 初始化墙壁
while True:
time.sleep(0.02) # 循环变慢
MainGame.window.fill(bg_color) # 设置主窗口的填充色
self.getEvent() # 获取事件
MainGame.window.blit(self.getTextSurface("敌方坦克剩余数量:%d" % len(MainGame.enemyTankList)), (10, 10)) # 绘制文字
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.displayTank() # 调用我方坦克显示方法,只需要初始化一次,一直显示即可
else:
del MainGame.my_tank # 删除我方坦克
MainGame.my_tank = None
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() # 检测我方坦克是否与敌方坦克发生碰撞
self.blitEnemyTank() # 调用敌方坦克显示方法
self.blitMyBullet() # 调用我方坦克子弹显示方法
self.blitEnemyBullet() # 调用敌方坦克子弹显示方法
self.blitExplode() # 调用爆炸效果的显示方法
self.blitWall() # 调用墙壁的显示方法
pygame.display.update() # 主窗口的更新,用于一直存在
def endGame(self):
print("游戏结束")
exit()
def helpGame(self):
var = pygame.display.init # 初始化主窗口
MainGame.window = pygame.display.set_mode([screen_width, screen_height]) # 设置主窗口的大小并显示
pygame.display.set_caption("坦克大战2.0") # 设置窗口的标题
button_back = Button(320, 350, MainGame.ba)
while True:
MainGame.window.fill(bg_color) # 设置主窗口的填充色
for event in pygame.event.get():
if event.type == pygame.QUIT: # 关闭键
self.endGame()
elif event.type == pygame.MOUSEBUTTONDOWN:
if button_back.isOver() == True:
self.startSurface()
button_back.displayButton()
MainGame.window.blit(self.getTextSurface("玩法介绍"), (350, 100))
MainGame.window.blit(self.getTextSurface("本游戏为模拟儿时经典的坦克大战游戏2.0版本,作者:A good boy"), (200, 150))
MainGame.window.blit(self.getTextSurface("按下键盘的上、下、左、右键来移动我方坦克,按下键盘的空格键进行射击。"), (170, 200))
pygame.display.update()
def getTextSurface(self, text):
pygame.font.init() # 初始化字体模块
font = pygame.font.SysFont("SimHei", 12) # 获取系统字体对象并设置字体和大小
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 not MainGame.my_tank:
if event.key == pygame.K_r:
self.createMyTank()
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
print("按下左键,坦克向左移动")
elif event.key == pygame.K_RIGHT:
MainGame.my_tank.direction = 'R' # 切换方向
MainGame.my_tank.stop = False
print("按下右键,坦克向右移动")
elif event.key == pygame.K_UP:
MainGame.my_tank.direction = 'U' # 切换方向
MainGame.my_tank.stop = False
print("按下上键,坦克向上移动")
elif event.key == pygame.K_DOWN:
MainGame.my_tank.direction = 'D' # 切换方向
MainGame.my_tank.stop = False
print("按下下键,坦克向下移动")
elif event.key == pygame.K_SPACE:
if len(MainGame.myBulletList) < 3:
myBullet = Bullet(MainGame.my_tank)
MainGame.myBulletList.append(myBullet)
print('发射子弹')
music = Music('img/hit.wav')
music.play()
if event.type == pygame.KEYUP:
# 判断松开的键是上、下、左、右键时候才停止坦克移动
if event.key == pygame.K_UP \
or event.key == pygame.K_DOWN \
or event.key == pygame.K_LEFT \
or event.key == pygame.K_RIGHT:
if MainGame.my_tank and MainGame.my_tank.live:
MainGame.my_tank.stop = True
def createMyTank(self): # 初始化我方坦克
MainGame.my_tank = MyTank(350, 300)
music = Music('img/start.wav')
music.play()
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 blitEnemyTank(self): # 遍历敌方坦克,显示列表中敌方坦克
for enemyTank in MainGame.enemyTankList:
if enemyTank.live:
enemyTank.displayTank()
enemyTank.randMove()
enemyTank.hitWall()
enemyBullet = enemyTank.shoot()
if MainGame.my_tank and MainGame.my_tank.live:
enemyTank.enemyTank_hit_myTank() # 检测敌方坦克是否与我方坦克发生碰撞
if enemyBullet: # 敌方子弹是否是None,如果不为None则添加到敌方子弹列表中
MainGame.enemyBulletList.append(enemyBullet)
else:
MainGame.enemyTankList.remove(enemyTank)
def blitMyBullet(self): # 遍历我方子弹,显示列表中我方子弹
for myBullet in MainGame.myBulletList:
if myBullet.live:
myBullet.displayBullet()
myBullet.move()
myBullet.myBullet_hit_enemyTank()
myBullet.hitWall()
else:
MainGame.myBulletList.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 blitExplode(self):
for explode in MainGame.explodeList:
if explode.live:
explode.displayExplode()
else:
MainGame.explodeList.remove(explode)
def createWall(self):
for i in range(6):
wall = Wall(i * 130, 220)
MainGame.wallList.append(wall)
def blitWall(self):
for wall in MainGame.wallList:
if wall.live:
wall.displayWall()
else:
MainGame.wallList.remove(wall)
class Button(): # 此类用于游戏中出现的各种按钮
def __init__(self, left, top, filename): # 初始化该按钮,包括加载图片,初始位置,按钮大小
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect() # 获取图片的区域
self.rect.left = left
self.rect.top = top
def isOver(self): # 判断鼠标是否放在该按钮上
point_x, point_y = pygame.mouse.get_pos()
x = self.rect.left
y = self.rect.top
w, h = self.image.get_size()
in_x = x < point_x < x + w
in_y = y < point_y < y + h
return in_x and in_y
def displayButton(self):
MainGame.window.blit(self.image, self.rect)
class Tank(BaseItem):
def __init__(self, left, top):
self.images = {
"U": pygame.image.load("img/p1tankU.gif"),
"D": pygame.image.load("img/p1tankD.gif"),
"L": pygame.image.load("img/p1tankL.gif"),
"R": pygame.image.load("img/p1tankR.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 == '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 == 'R':
if self.rect.left + self.rect.height < screen_width:
self.rect.left += self.speed
def shoot(self):
return Bullet(self)
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 displayTank(self):
self.image = self.images[self.direction] # 获取要显示的坦克对象
MainGame.window.blit(self.image, self.rect) # 调用bilt方法进行显示
class MyTank(Tank):
def __init__(self, left, top):
super(MyTank, self).__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(EnemyTank, self).__init__(left, top)
self.images = {
'U': pygame.image.load('img/enemy1U.gif'),
'D': pygame.image.load('img/enemy1D.gif'),
'L': pygame.image.load('img/enemy1L.gif'),
'R': pygame.image.load('img/enemy1R.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.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.direction = self.randDirection()
self.step = 60 # 步数复位
else:
self.move()
self.step -= 1
def shoot(self):
num = random.randint(1, 50) # 随机生成50以内的数
if num < 3:
return Bullet(self)
class Bullet(BaseItem):
def __init__(self, tank):
self.image = pygame.image.load("img/enemymissile.gif")
self.direction = tank.direction # 坦克的方向决定子弹的方向
self.rect = self.image.get_rect()
# 子弹的left和top
if self.direction == 'U':
self.rect.left = int(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 = int(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 = int(tank.rect.left - self.rect.width / 2 - self.rect.width / 2)
self.rect.top = int(tank.rect.top + tank.rect.width / 2 - self.rect.width / 2)
elif self.direction == 'R':
self.rect.left = tank.rect.left + tank.rect.width
self.rect.top = int(tank.rect.top + tank.rect.width / 2 - self.rect.width / 2)
self.speed = 6
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 == 'R':
if self.rect.left + self.rect.width < screen_width:
self.rect.left += self.speed
else:
self.live = False
elif self.direction == 'D':
if self.rect.top + self.rect.height < screen_height:
self.rect.top += self.speed
else:
self.live = False
elif self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.live = False
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 displayBullet(self):
MainGame.window.blit(self.image, self.rect)
def myBullet_hit_enemyTank(self): # 我方子弹与敌方坦克发生碰撞
# 循环遍历敌方坦克列表,判断是否发生碰撞
for enemyTank in MainGame.enemyTankList:
if pygame.sprite.collide_rect(enemyTank, self):
self.live = False # 修改敌方坦克和我方子弹的状态
enemyTank.live = False
explode = Explode(enemyTank) # 创建爆炸对象
MainGame.explodeList.append(explode)
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)
class Explode():
def __init__(self, tank):
self.rect = tank.rect # 爆炸的位置由当前子弹打中的坦克位置决定
self.images = [
pygame.image.load('img/blast0.gif'),
pygame.image.load('img/blast1.gif'),
pygame.image.load('img/blast2.gif'),
pygame.image.load('img/blast3.gif'),
pygame.image.load('img/blast4.gif'),
]
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 Wall():
def __init__(self, left, top):
self.image = pygame.image.load('img/steels.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()
if __name__ == "__main__":
MainGame().startSurface()
本程序的所有图片皆为自己用画图软件制作或网上寻找。
转载:https://blog.csdn.net/weixin_47232941/article/details/107722189
查看评论