Perceba a função:
1: O avanço contínuo do inimigo, segurando uma variedade de armas (garfos, machados, espadas), balançando as armas para atacar nosso castelo, causando danos ao nosso castelo!
2: Se nosso castelo encontrar o inimigo, podemos clicar manualmente com o botão esquerdo do mouse para lançar um ataque de bala, causando danos fatais aos japoneses e fazendo-os morrer!
3: Exibição de dados completa, atacando o inimigo para obter moedas de ouro, pontos acumulados, nível atual do cartão de gerenciamento, exibição do valor de saúde do nosso castelo, etc., as moedas de ouro obtidas ao matar o inimigo podem ser trocadas por atributos adicionais para equipar e restaurar e fortalecer nossa fortaleza!
4: A interface de layout do projeto é bonita e limpa, combinada com o fundo do jogo de música pura adicionado e efeitos sonoros de ataque e exibição de animação em tempo real (por exemplo, a aparência do nosso castelo mudará à medida que o valor de saúde do nosso castelo diminuir , ou seja, ficará quebrado, etc.) para tornar o projeto mais jogável!
5: Levar este projeto para a prática ou como um simples design de curso de python também é uma escolha possível!
6: O código total do projeto é de cerca de 700 linhas
Conhecimento de programação utilizado:
Noções básicas de Python, leitura e escrita de arquivos, módulo pygame e pensamento orientado a objetos!
código mostra como abaixo:
arquivo de classe inimigo.py (cerca de 100 linhas de código)
import pygame class Enemy(pygame.sprite.Sprite): def __init__(self, health, animation_list, x, y, speed): pygame.sprite.Sprite.__init__(self) self.alive = Verdadeiro self.speed = velocidade self. health = saúde self.last_attack = pygame.time.get_ticks() self.attack_cooldown = 1000 self.animation_list = animation_list self.frame_index = 0 self.action = 0#0: caminhada, 1: ataque, 2: morte self.update_time = pygame.time.get_ticks() #selecione a imagem inicial self.image = self.animation_list[self.action][self.frame_index] self.rect = pygame.Rect(0, 0, 25, 40) self.rect.center = (x, y) def update(self, surface, target, bullet_group): if self.alive: #verifica colisões com marcadores if pygame.sprite.spritecollide(self, bullet_group, True): #lower saúde do inimigo self.health -= 25 #verifica se o inimigo alcançou o castelo if self.rect.right > target.rect.left: self.update_action(1) #move o inimigo if self.action == 0: #atualiza a posição do retângulo self.rect.x += self.speed #attack if self.action == 1: #verifica se já passou tempo suficiente desde o último ataque if pygame.time.get_ticks() - self.last_attack > self.attack_cooldown: target.health -= 25 if target.health < 0: target.health = 0 self.last_attack = pygame.time.get_ticks() #verifica se a saúde caiu para zero se self.health <= 0: target.money += 100 target.score += 100 self.update_action(2)#death self.alive = False self.update_animation() #desenhar imagem na superfície da tela.blit (self.image, (self.rect.x - 10, self.rect.y - 15)) def update_animation(self): #define o tempo de espera da animação ANIMATION_COOLDOWN = 50 #atualiza a imagem dependendo da ação atual self.image = self.animation_list[self.action][self.frame_index] #verifica se já passou tempo suficiente desde a última atualização if pygame.time.get_ticks () - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 #se a animação acabou, redefina de volta ao início if self.frame_index >= len(self.animation_list [self.action]): se self.action == 2: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): #verifica se a nova ação é diferente da anterior if new_action != self.action: self.action = new_action #atualiza as configurações de animação self.frame_index = 0 self.update_date = pygame.time.get_ticks( )
arquivo de classe Castle.py (cerca de 500 linhas de código)
# Import library import pygame import math import os import sys import random import button from pygame import mixer # Initialize pygame pygame.init() # Define altura e largura da janela do jogo SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 # Carrega música de fundo pygame.mixer.music. load("sound/bjmusic.WAV") pygame.mixer.music.set_volume(0.3) jump_fx = pygame.mixer.Sound("sound/bullet.wav") jump_fx.set_volume(0.5) # cria tela da janela do jogo = pygame. display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("Castle Defense") clock = pygame.time.Clock() FPS = 60 # Defina a variável do jogo = 1 high_score = 0 Level_difficulty = 0 Target_difficulty = 1000 dificuldades_multiplier = 1.1 game_over = false next_level = false inimy_timer = 1000 last_enemy = pygame.Time.TET_TICKS () inimies_alive = 0 max_towers = 4 Tower_Cost = 5000 # # 定义 定义 定义 定义 定义 定义 定义 定义 定义 定义 定义 定义 # # # # # # # # # # # # # # # #ests = . SCREEN_HEIGHT - 200], [SCREEN_WIDTH - 200, SCREEN_HEIGHT - 150], [SCREEN_WIDTH - 150, SCREEN_HEIGHT - 150], [SCREEN_WIDTH - 100, SCREEN_HEIGHT - 150] ] # 加载最高分 if os.path.exists('socre.txt '): with open('socre.txt', 'r') as file: high_score = int(file.read()) # Defina a cor BRANCO = (255, 255, 255) CINZENTO = (100, 100, 100) # Defina a fonte font = pygame.font.SysFont('Nuvens coloridas chinesas', 30) font_60 = pygame.font.SysFont( 'Chinese Xingkai ', 60) # carregar imagem bg = pygame.image.load('img/bg.png').convert_alpha() # castelo castle_img_100 = pygame.image.load('img/castle/castle_100.png') .convert_alpha( ) castle_img_50 = pygame.image.load('img/castle/castle_50.png').convert_alpha() castle_img_25 = pygame.image.load('img/castle/castle_25.png').convert_alpha() # torre tower_img_100 = pygame .image.load('img/tower/tower_100.png').convert_alpha() tower_img_50 = pygame.image.load('img/tower/tower_50.png').convert_alpha() tower_img_25 = pygame.image.load('img/tower/tower_25.png').convert_alpha() # bullet image bullet_img = pygame.image.load('img/bullet.png').convert_alpha() b_w = bullet_img.get_width() b_h = bullet_img.get_height() bullet_img = pygame.transform.scale(bullet_img, (int(b_w * 0.075), int(b_h * 0.075))) # 创建敌人类 class Enemy(pygame.sprite.Sprite): def __init__(self , saúde, lista_animação, x, y, velocidade): super().__init__() self.alive = True self.speed = velocidade self.health = saúde self.last_attack = pygame.time.get_ticks() self.attack_cooldown = 1000 self.animation_list = animation_list self.frame_index = 0 self.action = 0 self.rect.x += 1 self.update_time = pygame.time.get_ticks() # fotos de fotos self.image = self.animation_list[self.action][self.frame_index] self.rect = pygame.Rect(0, 0, 25, 40) self.rect.center = (x, y) def update(self, surface , target, bullet_group): if self.alive: # Verifica se o inimigo colidiu com a bala if pygame.sprite.spritecollide(self, bullet_group, True): # Reduz a saúde self.health -= 25 # Verifica se o inimigo colidiu alcançou o castelo se self.rect.right > target.rect.left: self.update_action(1) # move o inimigo se self.action == 0: # ataca o castelo if self.action == 1: # detecta cooldown if pygame.time.get_ticks() - self.last_attack > self.attack_cooldown: target.health -= 25 if target.health < 0: target.health = 0 self.last_attack = pygame.time.get_ticks() # Verifica o sangue inimigo Se a barra é 0 se self.health <= 0: target.money += 100 target.score += 100 self.update_action(2) self.alive = False # chama a animação de atualização self.update_animation() inimiga def update_animation(self): # pygame. draw. rect(surface, (255, 255, 255), self. rect, 1) surface.blit(self.image, (self.rect.x - 10, self.rect.y - 15)) # Define o tempo de resfriamento da animação ANIMATION_COOLDOWN = 50 # Atualiza o quadro de acordo com o melão de inverno selecionado self.image = self .animation_list[self .action][self.frame_index] # Determina com que frequência atualizar o quadro if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index + = 1 # Verifique o número do quadro Não pode exceder o número máximo de quadros if self.frame_index >= len(self.animation_list[self.action]): if self.action == 2: self.frame_index = len(self.animation_list[self .action]) - 1 outro: self.frame_index = 0 def update_action(self, new_action): num_of_frames = 20 # Verifique se a nova ação é o mesmo que o anterior if new_action != self.action: self.action = new_action # atualiza a animação redefinir self.frame_index = 0 self.update_time = pygame.time.get_ticks() # carrega a lista de inimigos inimigos_animações = [] inimigo_tpyes = ['cavaleiro', ' goblin ', 'purple_goblin', 'red_goblin'] inimigo_saúde = [75, 100, 125, 150] animation_types = ['andar', 'ataque', 'morte'] para inimigo em inimigo_tpyes: # carregar lista de animação animation_list = [] para animation in animation_types: # Crie uma lista temporária temp_list = [] # Defina o número de frames para i in range(num_of_frames): img = pygame.image.load(f'img/enemies/{enemy}/{animation}/{i}.png').convert_alpha() e_w = img.get_width() e_h = img.get_height() img = pygame.transform.scale(img, (int(e_w * 0.2), int(e_h * 0.2))) temp_list.append(img) animation_list.append(temp_list) inimigo_animations.append(animation_list) # Repair_img = pygame.image.load('img/repair.png').convert_alpha() armour_img = pygame.image.load('img/armour.png').convert_alpha() # 在屏幕上输出文本信息 def draw_text(texto, fonte, cor_texto, x, y): img = fonte.render(texto, True, cor_texto) screen.blit(img, (x, y)) # Defina uma função para exibir o status def show_info(): draw_text('钱数:' + str(castle.money), font, GREY, 10, 10) draw_text('分数:' + str(castle.score), font, GREY, 180, 10) draw_text('最分数:' + str(high_score), fonte, GREY, 180, 50) draw_text('级别:' + str(level), fonte, GREY, SCREEN_WIDTH // 2, 10) draw_text('健康:' + str(castle. saúde) + "/" + str(castle.max_health), fonte, GREY, SCREEN_WIDTH - 230, SCREEN_HEIGHT - 50) draw_text('1000', fonte, GREY, SCREEN_WIDTH - 250, 70) draw_text(str(TOWER_COST), fonte , GREY, SCREEN_WIDTH - 150, 70) draw_text('500', font, GREY, SCREEN_WIDTH - 70, 70) # 城堡类 class Castle(): self.max_health = self.saúde self.fired = Falso def __init__(self, imagem100, imagem50, imagem25,x, y, escala): self.health = 1000 self.money = 0 self.score = 0 width = image100.get_width() height = image100.get_height() self.image100 = pygame.transform.scale(image100, (int(width * scale), int (altura * escala))) self.image50 = pygame.transform.scale(image50, (int(largura * escala), int(altura * escala))) self.image25 = pygame.transform.scale(image25, (int( largura * escala), int(altura * escala))) self.rect = self.image100.get_rect() self.rect.x = x self.rect.y = y def shoot(self): pos = pygame.mouse. get_pos() x_dist = pos[0] - self.rect.midleft[0] y_dist = -(pos[1] - self.rect.midleft[1]) elif self.health <= 500: self.angle = math.degrees(math.atan2(y_dist, x_dist)) # Clique com o mouse nesta posição if pygame.mouse.get_pressed()[0] e self.fired == False and pos[1] > 70: self .fired = True bullet = Bullet(bullet_img, self.rect.midleft[0], self.rect.midleft[1], self.angle) bullet_group.add(bullet) jump_fx.play() # reinicia o clique do mouse se pygame .mouse.get_pressed()[0] == False: self.fired = False def draw(self): # Determina qual imagem carregar com base no volume de sangue se self.health <= 250: self.image = self.image25 self . image = self. image50 else: self.image = self.image100 screen.blit(self.image, self.rect) def repair(self): if self.money >= 1000 e self.health < self.max_health: self.health += 500 self.money -= 1000 if Castle.health > Castle.max_health: Castle.health = Castle.max_health def armour(self): if self.money >= 500: self.max_health += 250 self.money -= 500 # 炮塔类 class Tower (pygame.sprite.Sprite): def __init__(self, image100, image50, image25, x, y, scale): self.angle = 0 super().__init__() self.got_target = False self.last_shot = pygame.time.get_ticks() largura = image100.get_width() altura = image100.get_height() self.image100 = pygame.transform.scale(image100, (int(largura * escala), int(altura * escala))) self.image50 = pygame.transform.scale(image50, (int(largura * escala), int(altura * escala))) self.image25 = pygame.transform.scale(image25, (int (largura * escala), int(altura * escala))) self.image = self.image100 self.rect = self.image100.get_rect() self.rect.x = x self.rect.y = y def update(self , grupo_inimigo): self.got_target = Falso para e no grupo_inimigo: if e.alive: target_x, target_y = e.rect.midbottom self.got_target = True break if self.got_target: x_dist = target_x - self.rect.midleft[0] y_dist = -(target_y - self.rect.midleft[1 ]) self.angle = math.degrees(math.atan2(y_dist, x_dist)) # pygame.draw.line(screen, WHITE, (self.rect.midleft[0], self.rect.midleft[1]), (target_x, target_y)) shot_cooldown = 1000 # 开火 if pygame.time.get_ticks() - self.last_shot > shot_cooldown: self.last_shot = pygame.time.get_ticks() bullet = Bullet(bullet_img, self.rect.midleft[0], self.rect.midleft[1], self.angle) bullet_group.add(bullet) # Carregue a imagem de acordo com o volume de sangue do castelo if castle.health <= 250: self.image = self.image25 elif castle.health <= 500: self.image = self.image50 else: self.image = self.image100 # Crie uma classe de marcadores Bullet(pygame.sprite.Sprite): def __init__( self, imagem, x, y, ângulo): super().__init__() self.image = imagem self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.angle = math.radians(angle) # Converte ângulos em radianos self.speed = 10 # Calcula as velocidades horizontal e vertical com base nos ângulos self.dx = math.cos(self.angle) * self.speed self.dy = -(math.sin(self.angle) * self.speed) def update(self): # Verifique se o marcador excedeu a janela if self .rect.right < 0 ou self.rect.left > SCREEN_WIDTH ou self.rect.bottom < 0 ou self.rect.top > SCREEN_HEIGHT: self.kill() # move o marcador self.rect.x += self .dx self .rect.y += self.dy # Cria uma classe de mira Crosshair(): def __init__(self, scale): image = pygame.image.load("img/crosshair.png").convert_alpha() width = imagem .get_width() altura = image.get_height() self.image = pygame.transform.scale(imagem, (int(largura * escala), int(altura * escala))) self.rect = self.image.get_rect() # esconde o ponteiro do mouse pygame.mouse.set_visible(False ) def draw(self): mx, my = pygame.mouse.get_pos() self.rect.center = (mx, my) screen.blit(self.image, self.rect) # cria castelo Castle = Castle(castle_img_100, Castle_img_50, Castle_img_25, SCREEN_WIDTH - 250, SCREEN_HEIGHT - 300, 0.2) # Instanciar crosshair crosshair = Crosshair(0.025) # Criar botão repair_button = button.Button(SCREEN_WIDTH - 240, 10, repair_button.button.5) tower_ (SCREEN_WIDTH - 130, 10, torre_img_100, 0.1) armour_button = button.Button(SCREEN_WIDTH - 75, 10, armour_img, 1.5) # Cria um grupo bullet_group = pygame.sprite.Group() inimigo_groupprite = pygame.sprite. .Grupo() tower_group = pygame.sprite.Group() # Usa uma torre temporária # tower = Tower(tower_img_100, tower_img_50, tower_img_25, SCREEN_WIDTH - 350, 200 , 0.2) # tower_group.add(tower) # Janela de exibição do ciclo do jogo pygame.mixer.music.unpause() pygame.mixer.music.play(-1) run = True while run: clock.tick(FPS) if game_over = = False: screen.blit(bg, (0, 0)) # mostra o castelo castle.draw() castle.shoot() # mostra a torre tower_group.draw(screen) tower_group.update(enemy_group) # mostra a mira crosshair.draw() # Desenha balas na tela bullet_group.update() bullet_group.draw(screen) # desenha inimigo inimigo_group.update(tela, castelo, bullet_group) # mostra informações detalhadas show_info() # mostra botão de reparo e botão de armadura if repair_button.draw(screen): Castle.repair( ) if tower_button.draw(screen): # Verifica se há dinheiro suficiente para construir a torre if castle.money >= TOWER_COST e len(tower_group) < max_towers: tower = Tower(tower_img_100, tower_img_50, tower_img_25, tower_positions[len(tower_group ) ][0], tower_positions[len(tower_group)][1], last_enemy = pygame.time.get_ticks() 0,2) tower_group.add(tower) # Subtrai o dinheiro gasto castle.money -= TOWER_COST if armor_button.draw(screen): Castle.armour() # Cria inimigos diferentes if level_difficulty < target_difficulty: if pygame.time.get_ticks() - last_enemy > ENEMY_TIMER: # cria uma instância de inimigo e = random.randint(0, len(enemy_tpyes) - 1) inimigo = Enemy(enemy_health[e], inimigo_animações[e], -100, SCREEN_HEIGHT - 100, 1) inimigo_grupo.add (inimigo ) level_difficulty += inimigo_health[e] # A detecção é que todos os inimigos aparecem se level_difficulty >= target_difficulty: # Verifique quantos inimigos ainda estão vivos inimigos_alive = 0 para e em inimigo_grupo: if e.alive == Verdadeiro: inimigos_alive += 1 # Verifique se os inimigos vivos foram todos mortos e o nível atual está completo if inimigos_alive == 0 e próximo_nível == False: next_level = True level_reset_time = pygame.time.get_ticks() # Determine se deve entrar no próximo nível if next_level == True: draw_text('The level has been complete', font_60, WHITE, 200, 300) # Atualize o mais alto Sub se Castle.score > high_score: file.write(str(high_score)) high_score = Castle.score com open('socre.txt', 'w') como arquivo: key = pygame.key.get_pressed() if pygame.time.get_ticks() - level_reset_time > 1500: next_level = False level += 1 last_enemy = pygame.time.get_ticks() target_difficulty *= DIFFICULTY_MULTIPLIER level_difficulty = 0 inimigo_group.empty() # verifique se o jogo acabou if < = 0: game_over = True else: draw_text('O jogo acabou!', font, GREY, 300, 300) draw_text('Pressione "A" para entrar novamente no jogo', font, GREY, 250, 350) pygame .mouse. set_visible(True) if key[pygame.K_a]: # reinicie o jogo game_over = False level = 1 target_difficulty = 1000 level_difficulty = 0 last_enemy = pygame.time.get_ticks() inimigo_group.empty() tower_group.empty() Castle.score = 0 Castle.health = 1000 Castle.max_health = Castle.Health Castle.money = 0 pygame.mouse.set_visible(False) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.quit() sys.exit() pygame.display.update()
arquivo de classe button.py (cerca de 50 linhas de código)
import pygame # Button class class Button(): def __init__(self, x, y, image, scale): width = image.get_width() height = image.get_height() self.image = pygame.transform.scale(image, (int(largura * escala), int(altura * escala))) self.rect = self.image.get_rect() self.rect.topleft = (x, y) self.clicked = False def draw(self, surface) : action = False # Obtém a posição do mouse pos = pygame.mouse.get_pos() # Detecta a colisão do ponteiro do mouse if self.rect.collidepoint(pos): if pygame.mouse.get_pressed()[0] = = 1 e self.clicked == False: self.clicked = True action = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False # desenha o botão na superfície da tela.blit(self.image, (self.rect.x, self.rect.y)) return ação
Captura de tela parcial da execução: