【python游戏】这年头塔除了拆还能干什么?这款好玩上瘾的塔防游戏,了解一下嘛

news2025/3/3 18:37:32

目录标题

      • 前言
      • 制作准备
      • 敲代码
        • 1)游戏运行主程序
        • 2)游戏开始界面
        • 3)游戏进行中界面
        • 4)游戏暂停界面
        • 5)炮塔类
      • 效果展示
      • 尾语

前言

嗨喽~大家好呀,这里是魔王呐 ❤ ~!

炮塔防御(Tower Defence),简称塔防,一种游戏类型。

炮塔防御游戏起源于最早的一款Desktop Tower Defence游戏。

塔防受众很广,游戏模式简单而可玩性强,且乐趣无穷,是智力和策略的比拼。

现在除了单纯的建造炮塔防御怪物,更产生了像《植物大战僵尸》这样的新型衍生类塔防游戏。

关于植物大战僵尸python制作源码也可以看看我之前的一篇文章:

【python游戏制作】僵尸来袭 ~ 快来一起创造植物叭~

而今天制作的塔防游戏,完整的项目源码 点击此处跳转文末名片免费获取

制作准备

图片素材(仅部分)

图片素材还有很多就不展示了哈,完整的素材包+源码自己 点击此处跳转文末名片免费获取

字体素材

音乐素材

敲代码

代码比较多的哈,如果文章懒得看,可以直接找我拿完整的项目自己慢慢研究也可。

完整代码 点击此处跳转文末名片免费获取噢~

1)游戏运行主程序

import pygame
from interface import END
from interface import START
from interface import GAMING
from interface import CHOICE
WIDTH = 800
HEIGHT = 600


'''主函数'''
def main():
	pygame.init()
	pygame.mixer.init()
	pygame.mixer.music.load('resource/audios/1.mp3')
	pygame.mixer.music.play(-1, 0.0)
	pygame.mixer.music.set_volume(0.25)
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption("塔防游戏")
	clock = pygame.time.Clock()
	# 调用游戏开始界面
	start_interface = START.START(WIDTH, HEIGHT)
	is_play = start_interface.update(screen)
	if not is_play:
		return
	# 调用游戏界面
	while True:
		choice_interface = CHOICE.CHOICE(WIDTH, HEIGHT)
		map_choice, difficulty_choice = choice_interface.update(screen)
		game_interface = GAMING.GAMING(WIDTH, HEIGHT)
		game_interface.start(screen, map_path='./maps/%s.map' % map_choice, difficulty_path='./difficulty/%s.json' % difficulty_choice)
		end_interface = END.END(WIDTH, HEIGHT)
		end_interface.update(screen)


'''run'''
if __name__ == '__main__':
	main()

2)游戏开始界面

import sys
import pygame


'''游戏开始界面'''
class StartInterface(pygame.sprite.Sprite):
	def __init__(self, WIDTH, HEIGHT):
		pygame.sprite.Sprite.__init__(self)
		self.imgs = ['./resource/imgs/start/start_interface.png']
		self.image = pygame.image.load(self.imgs[0]).convert()
		self.rect = self.image.get_rect()
		self.rect.center = WIDTH/2, HEIGHT/2
	'''just pass'''
	def update(self):
		pass


'''开始游戏按钮'''
class PlayButton(pygame.sprite.Sprite):
	def __init__(self, position=(220, 415)):
		pygame.sprite.Sprite.__init__(self)
		self.imgs = ['./resource/imgs/start/play_black.png', './resource/imgs/start/play_red.png']
		self.img_1 = pygame.image.load(self.imgs[0]).convert()
		self.img_2 = pygame.image.load(self.imgs[1]).convert()
		self.image = self.img_1
		self.rect = self.image.get_rect()
		self.rect.center = position
	'''不断地更新检测鼠标是否在按钮上'''
	def update(self):
		mouse_pos = pygame.mouse.get_pos()
		if self.rect.collidepoint(mouse_pos):
			self.image = self.img_2
		else:
			self.image = self.img_1


'''结束游戏按钮'''
class QuitButton(pygame.sprite.Sprite):
	def __init__(self, position=(580, 415)):
		pygame.sprite.Sprite.__init__(self)
		self.imgs = ['./resource/imgs/start/quit_black.png', './resource/imgs/start/quit_red.png']
		self.img_1 = pygame.image.load(self.imgs[0]).convert()
		self.img_2 = pygame.image.load(self.imgs[1]).convert()
		self.image = self.img_1
		self.rect = self.image.get_rect()
		self.rect.center = position
	'''不断地更新检测鼠标是否在按钮上'''
	def update(self):
		mouse_pos = pygame.mouse.get_pos()
		if self.rect.collidepoint(mouse_pos):
			self.image = self.img_2
		else:
			self.image = self.img_1


'''游戏开始类'''
class START():
	def __init__(self, WIDTH, HEIGHT):
		self.SI = StartInterface(WIDTH, HEIGHT)
		self.PB = PlayButton()
		self.QB = QuitButton()
		self.components = pygame.sprite.LayeredUpdates(self.SI, self.PB, self.QB)
	'''外部调用'''
	def update(self, screen):
		clock = pygame.time.Clock()
		while True:
			clock.tick(60)
			self.components.update()
			self.components.draw(screen)
			pygame.display.flip()
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					sys.exit(0)
					pygame.quit()
				elif event.type == pygame.MOUSEBUTTONDOWN:
					if event.button == 1:
						mouse_pos = pygame.mouse.get_pos()
						if self.PB.rect.collidepoint(mouse_pos):
							return True
						elif self.QB.rect.collidepoint(mouse_pos):
							return False

完整代码 点击此处跳转文末名片免费获取噢~

3)游戏进行中界面

import sys
import json
import math
import random
import pygame
sys.path.append('..')
from sprites import Enemy
from sprites import Turret
from interface import PAUSE
from pygame.locals import *
from collections import namedtuple


# 按钮类: 位置、文本、点击触发的事件
Button = namedtuple('Button', ['rect', 'text', 'onClick'])
# 定义一些颜色
info_color = (120, 20, 50)
red = (255, 0, 0)
green = (0, 255, 0)
black = (0, 0, 0)
white = (255, 255, 255)
grey = (127, 127, 127)
button_color1 = (0, 200, 0)
button_color2 = (0, 100, 0)


'''游戏进行中界面'''
class GAMING():
	def __init__(self, WIDTH=800, HEIGHT=600):
		self.WIDTH = WIDTH
		self.HEIGHT = HEIGHT
		# 游戏地图大小
		map_w = WIDTH
		map_h = 500
		# 按钮大小和位置
		button_w = 60
		button_h = 60
		button_y = 520
		# 间隙
		gap = 20
		# 按钮放在工具栏, 工具栏两端各有一个信息显示框
		toolbar_w = gap * 7 + button_w * 6
		info_w = (WIDTH - toolbar_w) // 2
		info_h = HEIGHT - map_h
		toolbar_h = HEIGHT - map_h
		# 界面布置
		self.map_rect = pygame.Rect(0, 0, map_w, map_h)
		self.map_surface = pygame.Surface((map_w, map_h))
		self.leftinfo_rect = pygame.Rect(0, map_h, info_w, info_h)
		self.rightinfo_rect = pygame.Rect(WIDTH-info_w, map_h, info_w, info_h)
		self.toolbar_rect = pygame.Rect(info_w, map_h, toolbar_w, toolbar_h)
		# 草
		self.grass = pygame.image.load("./resource/imgs/game/grass.png")
		# 岩石(铺路用的)
		self.rock = pygame.image.load("./resource/imgs/game/rock.png")
		# 污垢
		self.dirt = pygame.image.load("./resource/imgs/game/dirt.png")
		# 水
		self.water = pygame.image.load("./resource/imgs/game/water.png")
		# 灌木
		self.bush = pygame.image.load("./resource/imgs/game/bush.png")
		# 纽带
		self.nexus = pygame.image.load("./resource/imgs/game/nexus.png")
		# 洞穴
		self.cave = pygame.image.load("./resource/imgs/game/cave.png")
		# 获取地图元素的大小,请保证素材库里组成地图的元素图大小一致
		self.elementSize = int(self.grass.get_rect().width)
		# 一些字体
		self.info_font = pygame.font.Font('./resource/fonts/Calibri.ttf', 14)
		self.button_font = pygame.font.Font('./resource/fonts/Calibri.ttf', 20)
		# 可以放炮塔的地方
		self.placeable = {0: self.grass}
		# 地图元素字典(数字对应.map文件中的数字)
		self.map_elements = {
								0: self.grass,
								1: self.rock,
								2: self.dirt,
								3: self.water,
								4: self.bush,
								5: self.nexus,
								6: self.cave
							}
		# 用于记录地图中的道路
		self.path_list = []
		# 当前的地图,将地图导入到这里面
		self.currentMap = dict()
		# 当前鼠标携带的图标(即选中道具) -> [道具名, 道具]
		self.mouseCarried = []
		# 在地图上建造好了的炮塔
		self.builtTurretGroup = pygame.sprite.Group()
		# 所有的敌人
		self.EnemiesGroup = pygame.sprite.Group()
		# 所有射出的箭
		self.arrowsGroup = pygame.sprite.Group()
		# 玩家操作用的按钮
		self.buttons = [
							Button(pygame.Rect((info_w+gap), button_y, button_w, button_h), 'T1', self.takeT1),
							Button(pygame.Rect((info_w+gap*2+button_w), button_y, button_w, button_h), 'T2', self.takeT2),
							Button(pygame.Rect((info_w+gap*3+button_w*2), button_y, button_w, button_h), 'T3', self.takeT3),
							Button(pygame.Rect((info_w+gap*4+button_w*3), button_y, button_w, button_h), 'XXX', self.takeXXX),
							Button(pygame.Rect((info_w+gap*5+button_w*4), button_y, button_w, button_h), 'Pause', self.pauseGame),
							Button(pygame.Rect((info_w+gap*6+button_w*5), button_y, button_w, button_h), 'Quit', self.quitGame)
						]
	'''开始游戏'''
	def start(self, screen, map_path=None, difficulty_path=None):
		# 读取游戏难度对应的参数
		with open(difficulty_path, 'r') as f:
			difficulty_dict = json.load(f)
		self.money = difficulty_dict.get('money')
		self.health = difficulty_dict.get('health')
		self.max_health = difficulty_dict.get('health')
		difficulty_dict = difficulty_dict.get('enemy')
		# 每60s生成一波敌人
		GenEnemiesEvent = pygame.constants.USEREVENT + 0
		pygame.time.set_timer(GenEnemiesEvent, 60000)
		# 生成敌人的flag和当前已生成敌人的总次数
		genEnemiesFlag = False
		genEnemiesNum = 0
		# 每0.5秒出一个敌人
		GenEnemyEvent = pygame.constants.USEREVENT + 1
		pygame.time.set_timer(GenEnemyEvent, 500)
		genEnemyFlag = False
		# 防止变量未定义
		enemyRange = None
		numEnemy = None
		# 是否手动操作箭塔射击
		Manualshot = False
		has_control = False
		while True:
			if self.health <= 0:
				return
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					pygame.quit()
					sys.exit()
				if event.type == pygame.MOUSEBUTTONUP:
					# 左键选物品
					if event.button == 1:
						# 鼠标点击在地图上
						if self.map_rect.collidepoint(event.pos):
							if self.mouseCarried:
								if self.mouseCarried[0] == 'turret':
									self.buildTurret(event.pos)
								elif self.mouseCarried[0] == 'XXX':
									self.sellTurret(event.pos)
						# 鼠标点击在工具栏
						elif self.toolbar_rect.collidepoint(event.pos):
							for button in self.buttons:
								if button.rect.collidepoint(event.pos):
									if button.text == 'T1':
										button.onClick()
									elif button.text == 'T2':
										button.onClick()
									elif button.text == 'T3':
										button.onClick()
									elif button.text == 'XXX':
										button.onClick()
									elif button.text == 'Pause':
										button.onClick(screen)
									elif button.text == 'Quit':
										button.onClick()
									# 显然只能有一个按钮被点击
									break
					# 右键释放物品
					if event.button == 3:
						self.mouseCarried = []
					# 按中间键手动控制炮塔射箭方向一次,否则自由射箭
					if event.button == 2:
						Manualshot = True
				if event.type == GenEnemiesEvent:
					genEnemiesFlag = True
				if event.type == GenEnemyEvent:
					genEnemyFlag = True
			# 生成敌人
			# 生成的敌人随当前已生成敌人的总次数的增加而变强变多
			if genEnemiesFlag:
				genEnemiesFlag = False
				genEnemiesNum += 1
				idx = 0
				for key, value in difficulty_dict.items():
					idx += 1
					if idx == len(difficulty_dict.keys()):
						enemyRange = value['enemyRange']
						numEnemy = value['numEnemy']
						break
					if genEnemiesNum <= int(key):
						enemyRange = value['enemyRange']
						numEnemy = value['numEnemy']
						break
			if genEnemyFlag and numEnemy:
				genEnemyFlag = False
				numEnemy -= 1
				enemy = Enemy.Enemy(random.choice(range(enemyRange)))
				self.EnemiesGroup.add(enemy)
			# 射箭
			for turret in self.builtTurretGroup:
				if not Manualshot:
					position = turret.position[0] + self.elementSize // 2, turret.position[1]
					arrow = turret.shot(position)
				else:
					position = turret.position[0] + self.elementSize // 2, turret.position[1]
					mouse_pos = pygame.mouse.get_pos()
					angle = math.atan((mouse_pos[1]-position[1])/(mouse_pos[0]-position[0]+1e-6))
					arrow = turret.shot(position, angle)
					has_control = True
				if arrow:
					self.arrowsGroup.add(arrow)
				else:
					has_control = False
			if has_control:
				has_control = False
				Manualshot = False
			# 移动箭和碰撞检测
			for arrow in self.arrowsGroup:
				arrow.move()
				points = [(arrow.rect.left, arrow.rect.top), (arrow.rect.left, arrow.rect.bottom), (arrow.rect.right, arrow.rect.top), (arrow.rect.right, arrow.rect.bottom)]
				if (not self.map_rect.collidepoint(points[0])) and (not self.map_rect.collidepoint(points[1])) and \
					(not self.map_rect.collidepoint(points[2])) and (not self.map_rect.collidepoint(points[3])):
					self.arrowsGroup.remove(arrow)
					del arrow
					continue
				for enemy in self.EnemiesGroup:
					if pygame.sprite.collide_rect(arrow, enemy):
						enemy.life_value -= arrow.attack_power
						self.arrowsGroup.remove(arrow)
						del arrow
						break
			self.draw(screen, map_path)
	'''将场景画到游戏界面上'''
	def draw(self, screen, map_path):
		self.drawToolbar(screen)
		self.loadMap(screen, map_path)
		self.drawMouseCarried(screen)
		self.drawBuiltTurret(screen)
		self.drawEnemies(screen)
		self.drawArrows(screen)
		pygame.display.flip()
	'''画出所有射出的箭'''
	def drawArrows(self, screen):
		for arrow in self.arrowsGroup:
			screen.blit(arrow.image, arrow.rect)
	'''画敌人'''
	def drawEnemies(self, screen):
		for enemy in self.EnemiesGroup:
			if enemy.life_value <= 0:
				self.money += enemy.reward
				self.EnemiesGroup.remove(enemy)
				del enemy
				continue
			res = enemy.move(self.elementSize)
			if res:
				coord = self.find_next_path(enemy)
				if coord:
					enemy.reached_path.append(enemy.coord)
					enemy.coord = coord
					enemy.position = self.coord2pos(coord)
					enemy.rect.left, enemy.rect.top = enemy.position
				else:
					self.health -= enemy.damage
					self.EnemiesGroup.remove(enemy)
					del enemy
					continue
			# 画血条
			greenLen = max(0, enemy.life_value / enemy.max_life_value) * self.elementSize
			if greenLen > 0:
				pygame.draw.line(screen, green, (enemy.position), (enemy.position[0]+greenLen, enemy.position[1]), 1)
			if greenLen < self.elementSize:
				pygame.draw.line(screen, red, (enemy.position[0]+greenLen, enemy.position[1]), (enemy.position[0]+self.elementSize, enemy.position[1]), 1)
			screen.blit(enemy.image, enemy.rect)
	'''画已经建造好的炮塔'''
	def drawBuiltTurret(self, screen):
		for turret in self.builtTurretGroup:
			screen.blit(turret.image, turret.rect)
	'''画鼠标携带物'''
	def drawMouseCarried(self, screen):
		if self.mouseCarried:
			position = pygame.mouse.get_pos()
			coord = self.pos2coord(position)
			position = self.coord2pos(coord)
			# 在地图里再画
			if self.map_rect.collidepoint(position):
				if self.mouseCarried[0] == 'turret':
					screen.blit(self.mouseCarried[1].image, position)
					self.mouseCarried[1].coord = coord
					self.mouseCarried[1].position = position
					self.mouseCarried[1].rect.left, self.mouseCarried[1].rect.top = position
				else:
					screen.blit(self.mouseCarried[1], position)
	'''画工具栏'''
	def drawToolbar(self, screen):
		# 信息显示框
		# 	左
		pygame.draw.rect(screen, info_color, self.leftinfo_rect)
		leftTitle = self.info_font.render('Player info:', True, white)
		moneyInfo = self.info_font.render('Money: ' + str(self.money), True, white)
		healthInfo = self.info_font.render('Health: ' + str(self.health), True, white)
		screen.blit(leftTitle, (self.leftinfo_rect.left+5, self.leftinfo_rect.top+5))
		screen.blit(moneyInfo, (self.leftinfo_rect.left+5, self.leftinfo_rect.top+35))
		screen.blit(healthInfo, (self.leftinfo_rect.left+5, self.leftinfo_rect.top+55))
		# 	右
		pygame.draw.rect(screen, info_color, self.rightinfo_rect)
		rightTitle = self.info_font.render('Selected info:', True, white)
		screen.blit(rightTitle, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+5))
		# 中间部分
		pygame.draw.rect(screen, grey, self.toolbar_rect)
		for button in self.buttons:
			mouse_pos = pygame.mouse.get_pos()
			if button.rect.collidepoint(mouse_pos):
				self.showSelectedInfo(screen, button)
				button_color = button_color1
			else:
				button_color = button_color2
			pygame.draw.rect(screen, button_color, button.rect)
			buttonText = self.button_font.render(button.text, True, white)
			buttonText_rect = buttonText.get_rect()
			buttonText_rect.center = (button.rect.centerx, button.rect.centery)
			screen.blit(buttonText, buttonText_rect)
	'''显示被鼠标选中按钮的作用信息'''
	def showSelectedInfo(self, screen, button):
		if button.text == 'T1':
			T1 = Turret.Turret(0)
			selectedInfo1 = self.info_font.render('Cost: '+str(T1.price), True, white)
			selectedInfo2 = self.info_font.render('Damage: '+str(T1.arrow.attack_power), True, white)
			selectedInfo3 = self.info_font.render('Affordable: '+str(self.money>=T1.price), True, white)
			screen.blit(selectedInfo1, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
			screen.blit(selectedInfo2, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+55))
			screen.blit(selectedInfo3, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+75))
		elif button.text == 'T2':
			T2 = Turret.Turret(1)
			selectedInfo1 = self.info_font.render('Cost: '+str(T2.price), True, white)
			selectedInfo2 = self.info_font.render('Damage: '+str(T2.arrow.attack_power), True, white)
			selectedInfo3 = self.info_font.render('Affordable: '+str(self.money>=T2.price), True, white)
			screen.blit(selectedInfo1, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
			screen.blit(selectedInfo2, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+55))
			screen.blit(selectedInfo3, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+75))
		elif button.text == 'T3':
			T3 = Turret.Turret(2)
			selectedInfo1 = self.info_font.render('Cost: '+str(T3.price), True, white)
			selectedInfo2 = self.info_font.render('Damage: '+str(T3.arrow.attack_power), True, white)
			selectedInfo3 = self.info_font.render('Affordable: '+str(self.money>=T3.price), True, white)
			screen.blit(selectedInfo1, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
			screen.blit(selectedInfo2, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+55))
			screen.blit(selectedInfo3, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+75))
		elif button.text == 'XXX':
			selectedInfo = self.info_font.render('Sell a turret', True, white)
			screen.blit(selectedInfo, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
		elif button.text == 'Pause':
			selectedInfo = self.info_font.render('Pause game', True, white)
			screen.blit(selectedInfo, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
		elif button.text == 'Quit':
			selectedInfo = self.info_font.render('Quit game', True, white)
			screen.blit(selectedInfo, (self.rightinfo_rect.left+5, self.rightinfo_rect.top+35))
	'''出售炮塔(半价)'''
	def sellTurret(self, position):
		coord = self.pos2coord(position)
		for turret in self.builtTurretGroup:
			if coord == turret.coord:
				self.builtTurretGroup.remove(turret)
				self.money += int(turret.price * 0.5)
				del turret
				break
	'''建造炮塔'''
	def buildTurret(self, position):
		turret = self.mouseCarried[1]
		coord = self.pos2coord(position)
		position = self.coord2pos(coord)
		turret.position = position
		turret.coord = coord
		turret.rect.left, turret.rect.top = position
		if self.money - turret.price >= 0:
			if self.currentMap.get(turret.coord) in self.placeable.keys():
				self.money -= turret.price
				self.builtTurretGroup.add(turret)
				if self.mouseCarried[1].turret_type == 0:
					self.mouseCarried = []
					self.takeT1()
				elif self.mouseCarried[1].turret_type == 1:
					self.mouseCarried = []
					self.takeT2()
				elif self.mouseCarried[1].turret_type == 2:
					self.mouseCarried = []
					self.takeT3()
	'''拿炮塔1'''
	def takeT1(self):
		T1 = Turret.Turret(0)
		if self.money >= T1.price:
			self.mouseCarried = ['turret', T1]
	'''拿炮塔2'''
	def takeT2(self):
		T2 = Turret.Turret(1)
		if self.money >= T2.price:
			self.mouseCarried = ['turret', T2]
	'''拿炮塔3'''
	def takeT3(self):
		T3 = Turret.Turret(2)
		if self.money >= T3.price:
			self.mouseCarried = ['turret', T3]
	'''出售炮塔'''
	def takeXXX(self):
		XXX = pygame.image.load('./resource/imgs/game/x.png')
		self.mouseCarried = ['XXX', XXX]
	'''找下一个路径单元'''
	def find_next_path(self, enemy):
		x, y = enemy.coord
		# 优先级: 下右左上
		neighbours = [(x, y+1), (x+1, y), (x-1, y), (x, y-1)]
		for neighbour in neighbours:
			if (neighbour in self.path_list) and (neighbour not in enemy.reached_path):
				return neighbour
		return None
	'''将真实坐标转为地图坐标, 20个单位长度的真实坐标=地图坐标'''
	def pos2coord(self, position):
		return (position[0]//self.elementSize, position[1]//self.elementSize)
	'''将地图坐标转为真实坐标, 20个单位长度的真实坐标=地图坐标'''
	def coord2pos(self, coord):
		return (coord[0]*self.elementSize, coord[1]*self.elementSize)
	'''导入地图'''
	def loadMap(self, screen, map_path):
		map_file = open(map_path, 'r')
		idx_j = -1
		for line in map_file.readlines():
			line = line.strip()
			if not line:
				continue
			idx_j += 1
			idx_i = -1
			for col in line:
				try:
					element_type = int(col)
					element_img = self.map_elements.get(element_type)
					element_rect = element_img.get_rect()
					idx_i += 1
					element_rect.left, element_rect.top = self.elementSize * idx_i, self.elementSize * idx_j
					self.map_surface.blit(element_img, element_rect)
					self.currentMap[idx_i, idx_j] = element_type
					# 把道路记下来
					if element_type == 1:
						self.path_list.append((idx_i, idx_j))
				except:
					continue
		# 放洞穴和大本营
		self.map_surface.blit(self.cave, (0, 0))
		self.map_surface.blit(self.nexus, (740, 400))
		# 大本营的血条
		nexus_width = self.nexus.get_rect().width
		greenLen = max(0, self.health / self.max_health) * nexus_width
		if greenLen > 0:
			pygame.draw.line(self.map_surface, green, (740, 400), (740+greenLen, 400), 3)
		if greenLen < nexus_width:
			pygame.draw.line(self.map_surface, red, (740+greenLen, 400), (740+nexus_width, 400), 3)
		screen.blit(self.map_surface, (0, 0))
		map_file.close()
	'''暂停游戏'''
	def pauseGame(self, screen):
		pause_interface = PAUSE.PAUSE(self.WIDTH, self.HEIGHT)
		pause_interface.update(screen)
	'''退出游戏'''
	def quitGame(self):
		sys.exit(0)
		pygame.quit()

4)游戏暂停界面

import sys
import pygame


'''游戏暂停界面'''
class PauseInterface(pygame.sprite.Sprite):
	def __init__(self, WIDTH, HEIGHT):
		pygame.sprite.Sprite.__init__(self)
		self.imgs = ['./resource/imgs/pause/gamepaused.png']
		self.image = pygame.image.load(self.imgs[0]).convert()
		self.rect = self.image.get_rect()
		self.rect.center = (WIDTH/2, HEIGHT/2)
	'''just pass'''
	def update(self):
		pass


'''恢复游戏按钮'''
class ResumeButton(pygame.sprite.Sprite):
	def __init__(self, position=(391, 380)):
		pygame.sprite.Sprite.__init__(self)
		self.imgs = ['./resource/imgs/pause/resume_black.png', './resource/imgs/pause/resume_red.png']
		self.img_1 = pygame.image.load(self.imgs[0]).convert()
		self.img_2 = pygame.image.load(self.imgs[1]).convert()
		self.image = self.img_1
		self.rect = self.image.get_rect()
		self.rect.center = position
	def update(self):
		mouse_pos = pygame.mouse.get_pos()
		if self.rect.collidepoint(mouse_pos):
			self.image = self.img_2
		else:
			self.image = self.img_1


'''游戏暂停类'''
class PAUSE():
	def __init__(self, WIDTH, HEIGHT):
		self.PI = PauseInterface(WIDTH, HEIGHT)
		self.RB = ResumeButton()
		self.components = pygame.sprite.LayeredUpdates(self.PI, self.RB)
	'''外部调用'''
	def update(self, screen):
		clock = pygame.time.Clock()
		background = pygame.Surface(screen.get_size())
		count = 0
		flag = True
		while True:
			count += 1
			clock.tick(60)
			self.components.clear(screen, background)
			self.components.update()
			if count % 10 == 0:
				count = 0
				flag = not flag
			if flag:
				self.components.draw(screen)
			else:
				screen.blit(self.PI.image, self.PI.rect)
			pygame.display.flip()
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					sys.exit(0)
					pygame.quit()
				elif event.type == pygame.MOUSEBUTTONDOWN:
					if event.button == 1:
						mouse_pos = pygame.mouse.get_pos()
						if self.RB.rect.collidepoint(mouse_pos):
							return True

5)炮塔类

'''
Function:
	炮塔类
'''
import pygame
from sprites import Arrow


'''炮塔类'''
class Turret(pygame.sprite.Sprite):
	def __init__(self, turret_type):
		assert turret_type in range(3)
		pygame.sprite.Sprite.__init__(self)
		self.turret_type = turret_type
		self.imgs = ['./resource/imgs/game/basic_tower.png', './resource/imgs/game/med_tower.png', './resource/imgs/game/heavy_tower.png']
		self.image = pygame.image.load(self.imgs[turret_type])
		self.rect = self.image.get_rect()
		# 箭
		self.arrow = Arrow.Arrow(turret_type)
		# 当前的位置
		self.coord = 0, 0
		self.position = 0, 0
		self.rect.left, self.rect.top = self.position
		self.reset()
	'''射击'''
	def shot(self, position, angle=None):
		arrow = None
		if not self.is_cooling:
			arrow = Arrow.Arrow(self.turret_type)
			arrow.reset(position, angle)
			self.is_cooling = True
		if self.is_cooling:
			self.coolTime -= 1
			if self.coolTime == 0:
				self.reset()
		return arrow
	'''重置'''
	def reset(self):
		if self.turret_type == 0:
			# 价格
			self.price = 500
			# 射箭的冷却时间
			self.coolTime = 30
			# 是否在冷却期
			self.is_cooling = False
		elif self.turret_type == 1:
			self.price = 1000
			self.coolTime = 50
			self.is_cooling = False
		elif self.turret_type == 2:
			self.price = 1500
			self.coolTime = 100
			self.is_cooling = False

完整代码 点击此处跳转文末名片免费获取噢~

效果展示

截图效果展示——

游戏界面——

​关卡——

困难模式选择——

游戏界面——

尾语

感谢你观看我的文章呐~本次航班到这里就结束啦 🛬

希望本篇文章有对你带来帮助 🎉,有学习到一点知识~

躲起来的星星🍥也在努力发光,你也要努力加油(让我们一起努力叭)。

最后,宣传一下呀~👇👇👇更多源码、资料、素材、解答、交流皆点击下方名片获取呀👇👇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/895119.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小技巧:一键套用模板制作家具电子图册

​制作家具电子图册没有设计灵感怎么办&#xff1f; 可以看看小编分享的小技巧&#xff1a;一键套用模板的网站--------FLBOOK,轻轻松松制作一本别具一格的家具电子图册,操作方法非常简单 1.我们点击模板&#xff0c;在搜索框中搜索家具图册&#xff0c;选择自己喜欢的家具图册…

Vue3 setup新特性简单应用

去官网学习→组合式 API&#xff1a;setup() | Vue.js 运行示例&#xff1a; 代码&#xff1a;App.vue <template><div class"home"><img alt"Vue logo" src"../assets/logo.png"><!-- msg 组件传递数据 --><Hell…

团团代码生成器V2.0:一键生成完整的CRUD功能(重磅来袭!)

前言&#xff1a;考虑到在之前的V1.0版本只支持MySQL数据库&#xff0c;有点局限&#xff0c;因为在实际的项目开发中还会用到一个主流的Oracle数据库&#xff0c;所以我在V1.0的版本上进行了增强&#xff0c;新增了对Oracle数据库CRUD功能的生成&#xff0c;使用过程还是和V1.…

【Rust】Rust学习 第十五章智能指针

指针 &#xff08;pointer&#xff09;是一个包含内存地址的变量的通用概念。这个地址引用&#xff0c;或 “指向”&#xff08;points at&#xff09;一些其他数据。Rust 中最常见的指针是第四章介绍的 引用&#xff08;reference&#xff09;。引用以 & 符号为标志并借用…

外网远程连接Linux服务器

文章目录 视频教程1. Linux CentOS安装cpolar2. 创建TCP隧道3. 随机地址公网远程连接4. 固定TCP地址5. 使用固定公网TCP地址SSH远程 转发内网穿透文章. 本次教程我们来实现如何在外公网环境下&#xff0c;SSH远程连接家里/公司的Linux CentOS服务器&#xff0c;无需公网IP&…

【推荐】深入浅出benan的生命周期

目录 1.spring 管理JavaBean的过程&#xff08;生命周期&#xff09; 2.spring的JavaBean管理中单例模式及原型&#xff08;多例&#xff09;模式 2.1 . 默认为单例&#xff0c;但是可以配置多例 2.2.举例论证 2.2.1 默认单例 2.2.2 设置多例 2.2.3单例与多例的初始化的时…

【数学】CF1242 A

Problem - 1242A - Codeforces 题意&#xff1a; 思路&#xff1a; Code&#xff1a; #include <bits/stdc.h>#define int long longusing i64 long long;constexpr int N 2e3 10; constexpr int M 2e3 10; constexpr int mod 998244353; constexpr int Inf 1e1…

Java中级部分

以下内容来源自Java 面试指南 | JavaGuide(Java面试 学习指南)和自己的学习笔记整理&#xff0c;这里我整理了自己比较感兴趣的点&#xff0c;也有助于我自己理解~ 异常 Exception 和 Error 有什么区别&#xff1f; 在 Java 中&#xff0c;所有的异常都有一个共同的祖先 jav…

【学习笔记之vue】 Cannot find module ‘node-sass‘

Cannot find module node-sass方案一&#xff08;不通&#xff09; 下载node-sass组件 >> npm install -g cnpm>>cnpm install node-sass下载时报错 方案二 使用npm下载node-sass组件 >>npm install node-sassok

Oracle字段长度不足位数补零

Oracle字段长度不足位数补零 有时候从数据库中取出的月份值是1&#xff0c;而不是01&#xff0c;该怎么办呢 SELECTLPAD( CODE_MONTH, 2, 0 ) FROMtb_cube_TY001 WHERECODE_BM_MEATYPE TY20 AND code_measure MYLX01 AND code_month <> ~ AND CODE_ENTITY 01A AND…

Linux 进程间通信——信号量

一、信号量描述 信号量是一个特殊的变量&#xff0c;一般取正数值。它的值代表允许访问的资源数目。 获取资源时&#xff0c;需要对信号量的值进行原子减一&#xff0c;该操作被称为P操作&#xff0c;当信号量值为0时&#xff0c;代表没有资源可用&#xff0c;P操作会阻塞。释…

2023一建案例100题

一、某施工单位承接了两栋住宅楼&#xff0c;总建筑面积 65000m&#xff0c;均为筱板基础(上翻梁结构)&#xff0c;地下 2层&#xff0c;地上30 层&#xff0c;地下结构连通&#xff0c;上部为两个独立单体一字设置&#xff0c;设计形式一致&#xff0c;地下室外墙南北向距离 4…

008永磁电机FOC控制:磁场定向控制不就两个变换就搞定啦

在现代工业中&#xff0c;电机广泛应用于各类设备和机械系统中。为了提高电机性能并降低能量损耗&#xff0c;电机控制技术得到了不断的发展和创新。其中&#xff0c;磁场定向控制&#xff08;Field-Oriented Control&#xff0c;简称FOC&#xff09;作为一种先进的电机控制策略…

在 IDEA 中使用 Git开发 图文教程

在 IDEA 中使用 Git开发 图文教程 一、连接远程仓库二、IDEA利用Git进行开发操作三、分支操作3.1 新建分支3.2 切换分支3.3 删除分支3.4 比较分支3.5 合并分支 四、常用快捷键 一、连接远程仓库 一、打开IDEA&#xff0c;进入目录&#xff1a;File ->New ->Project from…

PHP之Base64+php://filter绕过、disabled_function绕过

目录 一、Base64php://filter绕过 1.思路分析 2.实践验证 二、disabled_function绕过 一、Base64php://filter绕过 上课讲了这样一道题&#xff0c;一起来看下(以下代码适用于PHP7.x及以上&#xff0c;5的版本会报错) <?php function fun($var): bool{$blacklist …

STM32 中断复习

中断 打断CPU执行正常的程序&#xff0c;转而处理紧急程序&#xff0c;然后返回原暂停的程序继续运行&#xff0c;就叫中断。 在确定时间内对相应事件作出响应&#xff0c;如&#xff1a;温度监控&#xff08;定时器中断&#xff09;。故障处理&#xff0c;检测到故障&#x…

详细讲解什么是SpringMVC 映射请求数据

&#x1f600;前言 本文详细讲解什么是SpringMVC 映射请求数据 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&#x1f609;&#x1f609; …

2023年03月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:数字字符求和 请编写一个程序实现以下功能:从一个字符串中,提取出所有的数字字符即0-9,并作为数求和。 时间限制:1000 内存限制:65536 输入 一行字符串,长度不超过100,字符串中不含空格。 输出 字符串中所有数字字符作为数的和 样例输入 Lsd2f02k3ja3sdf223 样例…

辅助笔记-安装Ubantu虚拟机

安装Ubantu虚拟机 文章目录 安装Ubantu虚拟机步骤一&#xff1a;检查BIOS虚拟化支持步骤二&#xff1a;VMware17安装虚拟机步骤1&#xff1a;新建虚拟机步骤2&#xff1a;验证虚拟机能否上网 步骤3&#xff1a;设置Ubantu语言为中文 本文主要参考B站视频“P108_ 韩顺平Linux_ u…

测评类软文怎么写?教你几招

测评类种草软文&#xff0c;是当下非常热门的一种文章类型。这类文章以其独特的魅力&#xff0c;吸引着大量的用户&#xff0c;同时也让许多商家看到了商机。然而&#xff0c;如何写好一篇测评类种草软文&#xff0c;却是许多企业和品牌面临的难题。接下来伯乐网络传媒就给大家…