Realiza la función:
1: ¡El avance continuo del enemigo, sosteniendo una variedad de armas (tenedores, hachas, espadas), balanceando armas para atacar nuestro castillo, causando daños a nuestro castillo!
2: Si nuestro castillo encuentra al enemigo, podemos hacer clic manualmente con el botón izquierdo del mouse para lanzar un ataque de bala, causando daños fatales a los japoneses y ¡causándoles la muerte!
3: Visualización de datos completa, atacando al enemigo para obtener monedas de oro, puntos acumulados, el nivel actual de la tarjeta de gestión, la visualización del valor de salud de nuestro castillo, etc., las monedas de oro obtenidas al matar al enemigo se pueden cambiar por atributos adicionales para equipar y restaurar y fortalecer nuestra fortaleza!
4: La interfaz de diseño del proyecto es hermosa y limpia, combinada con el fondo del juego de música pura agregado y los efectos de sonido de ataque y la visualización de animación en tiempo real (por ejemplo, la apariencia de nuestro castillo cambiará a medida que disminuya el valor de salud de nuestro castillo , es decir, se descompondrá, etc.) para que el proyecto sea más jugable.
5: ¡Llevar este proyecto a la práctica o como un simple diseño de curso de Python también es una opción posible!
6: el código total del proyecto es de aproximadamente 700 líneas
Conocimientos de programación utilizados:
Conceptos básicos de Python, lectura y escritura de archivos OS, módulo pygame y pensamiento orientado a objetos.
el código se muestra a continuación:
archivo de la clase enemigo.py (alrededor de 100 líneas 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 = True self.speed = speed self. salud = salud self.last_attack = pygame.time.get_ticks() self.attack_cooldown = 1000 self.animation_list = animation_list self.frame_index = 0 self.action = 0#0: caminar, 1: atacar, 2: morir self.update_time = pygame.time.get_ticks() #seleccionar imagen inicial self.image = self.animation_list[self.action][self.frame_index] self.rect = pygame.Rect(0, 0, 25, 40) self.rect.center = (x, y) actualización def(self, superficie, objetivo, grupo_balas): if self.alive: #comprobar colisión con balas if pygame.sprite.spritecollide(self, grupo_bullet, True): #reducir la salud del enemigo self.health -= 25 #check if el enemigo ha llegado al castillo si self.rect.right > target.rect.left: self.update_action(1) #mover enemigo if self.action == 0: #actualizar la posición del rectángulo self.rect.x += self.speed # ataque si self.action == 1: #verificar si ha pasado suficiente tiempo desde el ú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() #verificar si la salud ha bajado a cero si self.health <= 0: target.money += 100 target.score += 100 self.update_action(2)#death self.alive = False self.update_animation() #dibujar imagen en la superficie de la pantalla.blit (self.image, (self.rect.x - 10, self.rect.y - 15)) def update_animation(self): #define el enfriamiento de la animación ANIMATION_COOLDOWN = 50 #actualizar la imagen según la acción actual self.image = self.animation_list[self.action][self.frame_index] #verificar si ha pasado suficiente tiempo desde la última actualización if pygame.time.get_ticks() - self.update_time > ANIMACIÓN_ENFRIAMIENTO: self.update_time = pygame.time.get_ticks() self.frame_index += 1 #si la animación se agotó, reinicie de nuevo al inicio if self.frame_index >= len(self.animation_list[self.action]) : if self.action == 2: self.frame_index = len(self.animation_list[self.action]) - 1 def update_action(self, new_action): else: self.frame_index = 0 #verificar si la nueva acción es diferente a la anterior if new_action != self.action: self.action = new_action #actualizar la configuración de animación self.frame_index = 0 self.update_date = pygame.time.get_ticks( )
archivo de clase castle.py (alrededor de 500 líneas de código)
# Importar biblioteca import pygame import math import os import sys import botón de importación aleatoria desde pygame import mixer # Inicializar pygame pygame.init() # Definir la altura y el ancho de la ventana del juego SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 # Cargar música de fondo pygame.mixer.music. load("sonido/bjmusic.WAV") pygame.mixer.music.set_volume(0.3) jump_fx = pygame.mixer.Sound("sonido/bullet.wav") jump_fx.set_volume(0.5) # crear pantalla de ventana de juego = pygame. display.set_mode((PANTALLA_ANCHO, PANTALLA_ALTO)) pygame.display.set_caption("Castle Defense") clock = pygame.time.Clock() FPS = 60 # Define la variable del juego high_score = 0 nivel de la variable del juego = 1 nivel_difficulty = 0 Target_DiffiCulty = 1000 Difmity_Multiplier = 1.1 Game_over = false next_level = false enemy_timer = 1000 last_enemy = pygame.time.get_ticks () enemies_alive = 0 max_towers = 4 tower_cost = 5000 # 炮塔 位置 位置 位置 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的- 250, SCREEN_HEIGHT - 200], [SCREEN_WIDTH - 200, SCREEN_HEIGHT - 150], [SCREEN_WIDTH - 150, SCREEN_HEIGHT - 150], [SCREEN_WIDTH - 100, SCREEN_HEIGHT - 150] ] # 加载最高分 si os'path.exists socre.txt'): con open('socre.txt', 'r') como archivo: high_score = int(file.read()) # Definir el color tower_img_50 = pygame.image.load('img/tower/tower_50.png').convert_alpha() BLANCO = (255, 255, 255) GRIS = (100, 100, 100) # Definir la fuente fuente = pygame.font.SysFont('Nubes coloridas chinas', 30) font_60 = pygame.font.SysFont('Xingkai chino' , 60 ) # cargar imagen bg = pygame.image.load('img/bg.png').convert_alpha() # castillo 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() # torreta torre_img_100 = pygame. image.load('img/tower/tower_100.png').convert_alpha() tower_img_25 = pygame.image.load('img/tower/tower_25.png').convert_alpha() # imagen de viñeta 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 ) _ _ _ _ _ = True self.speed = velocidad self.health = salud self.last_attack = pygame.time.get_ticks() self.attack_cooldown = 1000 self.animation_list = animation_list self.frame_index = 0 self.action = 0 self.update_time = pygame.time.get_ticks() #选择动画开始的图片 self.imagen = self.animation_list[self.action][self.frame_index] self.rect = pygame.Rect(0, 0, 25, 40) self.rect.center = (x, y) def update(self, superficie , target, bullet_group): if self.alive: # Comprobar si el enemigo ha chocado con la bala if pygame.sprite.spritecollide(self, bullet_group, True): # Reducir la salud self.health -= 25 # Comprobar si el enemigo ha alcanzado el castillo si self .rect.right > target.rect.left: self.update_action(1) # mover al enemigo if self.action == 0: self.rect.x += 1 # atacar el castillo if self.action == 1: # detectar enfriamiento 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() # Comprobar la sangre del enemigo Si la barra es 0 si self.health <= 0: target.money += 100 target.score += 100 self.update_action(2) self.alive = False # llamar a actualizar la animación self.update_animation() # dibujar la # pygame. dibujar. rect(superficie, (255, 255, 255), self. rect, 1) superficie enemiga. blit (self. image, (self. rect. x - 10, self. rect. y - 15)) def update_animation(self): # Definir el tiempo de enfriamiento de la animación ANIMATION_COOLDOWN = 50 # Actualizar el marco de acuerdo con la calabaza de cera seleccionada self.image = self.animation_list[self.action][self.frame_index] # Determinar con qué frecuencia actualizar el marco si pygame.time.get_ticks () - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 # Compruebe que el número de fotogramas no puede exceder el número máximo de fotogramas si self.frame_index >= len(self. animation_list[self.action]): if self.action == 2: self.frame_index = len(self.animation_list[self.action]) - 1 else: # Comprobar si la nueva acción es igual que el anterior self.frame_index = 0 def update_action(self, new_action): if new_action != self.action: self.action = new_action # actualizar animación reset self.frame_index = 0 self.update_time = pygame.time.get_ticks() # cargar lista de enemigos enemigos_animaciones = [] enemigos_tpyes = ['knight', 'goblin', 'purple_goblin', 'red_goblin'] enemiga_salud = [75, 100, 125, 150] animation_types = ['caminar', 'atacar', 'muerte'] para el enemigo en enemigos_tpyes: # Cargue la lista de animaciones animation_list = [] para animaciones en animation_types: # Crear una lista temporal temp_list = [] # Definir el número de fotogramas num_of_frames = 20 para i en el rango (num_of_frames): img = pygame.image.load(f'img/enemigos/{enemigo}/{animación}/{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) enemiga_animaciones.append(animation_list) # cargar imagen de botón repair_img = pygame.image .load('img/repair.png').convert_alpha() armour_img = pygame.image.load('img/armour.png').convert_alpha() # Mostrar información de texto en la pantalla def draw_text(text, font, text_color , x, y): # Definir una función para mostrar el estado def show_info(): img = fuente.render(texto, True, color_texto) screen.blit(img, (x, y)) draw_text('钱数:' + str(castle.money), font, GREY, 10, 10) draw_text('分数:' + str(castle.score), font , GREY, 180, 10) draw_text('最分数:' + str(high_score), fuente, GREY, 180, 50) draw_text('级别:' + str(level), font, GREY, SCREEN_WIDTH // 2, 10 ) draw_text('健康:' + str(castillo.salud) + "/" + str(castillo.max_salud), fuente, GRIS, ANCHO_PANTALLA - 230, ALTURA_PANTALLA - 50) draw_text('1000', fuente, GRIS, ANCHO_PANTALLA - 250, 70) draw_text(str(TOWER_COST), font, GREY, SCREEN_WIDTH - 150, 70) draw_text('500', font, GREY, SCREEN_WIDTH - 70, 70) # 城堡类 class Castle(): def __init__(self, imagen100, imagen50, imagen25,x, y, escala): self.health = 1000 self.max_health = self.salud self.fired = Falso self.money = 0 self.score = 0 ancho = imagen100.get_width() altura = imagen100.get_altura() self.imagen100 = pygame.transform.scale(imagen100, (int(ancho * escala), int(altura * escala) )) self.image50 = pygame.transform.scale(image50, (int(ancho * escala), int(altura * escala))) self.image25 = pygame.transform.scale(imagen25, (int(ancho * 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]) self.angle = math.degrees(math.atan2(y_dist, x_dist)) # Haga clic con el mouse en esta posición si pygame.mouse.get_pressed()[0] y 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() # restablecer clic del mouse si pygame .mouse.get_pressed()[0] == False: self.fired = False def draw(self): # Determina qué imagen cargar según el volumen de sangre si self.health <= 250: self.image = self.image25 elif self.health <= 500: self .imagen = self.imagen50 más: self.image = self.image100 screen.blit(self.image, self.rect) def repair(self): if self.money >= 1000 and self.health < self.max_health: self.health += 500 self.money -= 1000 if castillo.salud > castillo.max_salud: castillo.salud = castillo.max_salud def armadura(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): super().__init__() self.got_target = False self.angle = 0 self.last_shot = pygame.time.get_ticks() ancho = imagen100.get_width() altura = imagen100.get_height() self.image100 = pygame.transform.scale(image100, (int(ancho * escala), int(altura * escala ))) self.image50 = pygame.transform.scale(image50, (int(ancho * escala), int(altura * escala))) self.image25 = pygame.transform.scale(imagen25, (int(ancho * escala) , int(altura * escala))) self.imagen = self.imagen100 self.rect = self.imagen100.get_rect() self.rect.x = x self.rect.y = y def update(self, grupo_enemigo): self .got_target = Falso para e en grupo_enemigo: si e.alive: target_x, target_y = e.rect.midbottom self.got_target = Corte verdadero si self.got_target: x_dist = target_x - self.rect.midleft[0] y_dist = -(target_y - self.rect.midleft[1]) self.angle = matemáticas.grados(matemáticas.atan2(y_dist, x_dist)) # pygame.draw.line(pantalla, BLANCO, (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: bullet = Bullet(bullet_img, self.rect.midleft[0], self.rect.midleft[1], self.angle) self.last_shot = pygame.time.get_ticks() bullet_group.add(bullet) # Carga esa imagen según el volumen de sangre del castillo if castle.health <= 250: self.image = self.image25 elif castle.health <= 500: self.image = self.image50 else: self. image = self.image100 # Crear clase de viñeta class Bullet(pygame.sprite.Sprite): def __init__(self, image, x, y, angle): super().__init__() self.image = image self.rect = self .image.get_rect() self.rect.x = x self.rect.y = y self.angle = math.radianes(ángulo) # Convertir ángulos a radianes self.speed = 10 # Calcular velocidades horizontales y verticales basadas en ángulos self.dx = math.cos(self.angle) * self.speed self.dy = -(math.sin(self.angle) * self.speed) def update(self): # Comprobar si la bala ha superado la ventana if self .rect.right < 0 o self.rect.left > SCREEN_WIDTH o self.rect.bottom < 0 o self.rect.top > SCREEN_HEIGHT: self.kill() # mover la viñeta self.rect.x += self .dx self .rect.y += self.dy # Crear una clase de punto de mira Crosshair(): def __init__(self, scale): image = pygame.image.load("img/crosshair.png").convert_alpha() ancho = imagen .get_width() altura = imagen.get_height() self.imagen = pygame.transform.scale(imagen, (int(ancho * escala), int(altura * escala))) self.rect = self.image.get_rect() # ocultar el puntero del mouse pygame.mouse.set_visible(False ) def dibujar(self): mx, my = pygame.mouse.get_pos() self.rect.center = (mx, my) screen.blit(self.image, self.rect) # crear castillo castillo = Castillo(castillo_img_100, castle_img_50, castle_img_25, SCREEN_WIDTH - 250, SCREEN_HEIGHT - 300, 0.2) # Crear una instancia de crosshair crosshair = Crosshair(0.025) # Create button repair_button = button.Button(SCREEN_WIDTH - 240, 10, repair_button.button.5) tower_ (SCREEN_WIDTH - 130, 10, torre_img_100, 0.1) botón_armadura = botón.Botón(ANCHO_PANTALLA - 75, 10, armadura_img, 1.5) # crear grupo bullet_group = pygame.sprite.Group() grupo_enemigoprite = pygame.sprite. .Grupo() tower_group = pygame.sprite.Group() # Usar una torre temporal # tower = Tower(tower_img_100, tower_img_50, tower_img_25, SCREEN_WIDTH - 350, 200 , 0.2) # tower_group.add(tower) # Ventana de visualización del ciclo del juego pygame.mixer.music.unpause() pygame.mixer.music.play(-1) run = True while run: clock.tick(FPS) if game_over = = Falso: pantalla.blit(bg, (0, 0)) # mostrar castillo castillo.dibujar () castillo.disparar() # mostrar torreta grupo_torre.dibujar(pantalla) grupo_torre.update(grupo_enemigo) # mostrar punto de mira crosshair.draw() # Dibujar balas en la pantalla bullet_group.update() bullet_group.draw(screen) # dibujar enemigo enemigo_group.update(screen, castle, bullet_group) # mostrar información detallada show_info() # mostrar botón de reparación y botón de armadura if repair_button.draw(screen): castle.repair( ) if tower_button.draw(screen): # Comprobar si hay suficiente dinero para construir la torre if castle.money >= TOWER_COST and len(tower_group) < max_towers: tower = Tower(tower_img_100, tower_img_50, tower_img_25, tower_positions[len(tower_group) ) ][0], posiciones_de_torre[len(grupo_de_torre)][1], último_enemigo = pygame.time.get_ticks() 0.2) grupo_torre.add(torre) # Resta el dinero gastado castillo.dinero -= COSTE_TORRE si botón_armadura.dibujar(pantalla): castillo.armadura() # Crear diferentes enemigos si nivel_dificultad < dificultad_objetivo: si pygame.time.get_ticks() - último_enemigo > ENEMY_TIMER: # crear una instancia de enemigo e = random.randint(0, len(enemy_tpyes) - 1) enemigo = Enemigo(enemy_health[e], enemigos_animaciones[e], -100, SCREEN_HEIGHT - 100, 1) enemigo_grupo.add (enemigo ) nivel_dificultad += salud_enemiga[e] # La detección es que todos los enemigos aparecen si nivel_dificultad >= dificultad_objetivo: # Comprueba cuántos enemigos siguen vivos . False: next_level = True level_reset_time = pygame.time.get_ticks() # Determinar si ingresar al siguiente nivel si next_level == True: draw_text('El nivel ha sido completado', font_60, WHITE, 200, 300) # Actualizar el más alto Sub si castle.score > high_score: with open('socre.txt', 'w') as file: file.write(str(high_score)) high_score = castle.score if pygame.time.get_ticks() - level_reset_time > 1500: next_level = False level += 1 last_enemy = pygame.time.get_ticks() target_difficulty *= DIFICULTAD_MULTIPLIER level_difficulty = 0 grupo_enemigo.empty() # comprobar si el juego ha terminado if < pygame _ _ _ _ _ .mouse.set_visible(True) key = pygame.key.obtener_presionado() if key[pygame.K_a]: # restablecer el juego game_over = False nivel = 1 target_difficulty = 1000 level_difficulty = 0 last_enemy = pygame.time.get_ticks() grupo_enemigo.vacío() grupo_torre.vacío() castillo.puntuación = 0 castillo.salud = 1000 castillo.max_salud = castillo.salud castillo.dinero = 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()
archivo de clase button.py (alrededor de 50 líneas de código)
import pygame # Clase de botón clase Botón(): def __init__(self, x, y, image, scale): ancho = image.get_width() height = image.get_height() self.image = pygame.transform.scale(image, (int(ancho * escala), int(altura * escala))) self.rect = self.image.get_rect() self.rect.topleft = (x, y) self.clicked = False def dibujar(self, superficie) : action = False # Obtener la posición del mouse pos = pygame.mouse.get_pos() # Detectar la colisión del puntero del mouse if self.rect.collidepoint(pos): if pygame.mouse.get_pressed()[0] = = 1 y self.clicked == False: self.clicked = True action = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False # dibujar el botón en la superficie de la pantalla.blit (self.image, (self.rect.x, self.rect.y ) ) acción de retorno
Captura de pantalla de ejecución parcial: