Python开发之城堡保卫战游戏的实现
目录
- 实现功能
- 用到的编程知识
- 代码如下
- 部分运行截图
实现功能
1:敌人的绵绵不断的前进,拿着各种各样的武器(叉子,斧头,宝剑),挥动武器攻击我方城堡,对我方城堡造成伤害!
2:我方城堡发现敌人可手动点击鼠标左键来发起子弹攻击,对日人造成致命伤害,让其死亡!
3:完备的数据显示,攻击敌人获取金币,累计得分,当前管卡的级别,我方城堡生命值的显示等等,击杀敌人获取的金币可以兑换额外属性来装备回复加强我方堡垒!
4:项目的布局界面优美干净,结合添加的纯音乐游戏背景和攻击音效以及实时的动画显示(如我方城堡的外观会随着我方城堡生命值的降低而发生改变,也就是变得会破败一些等等)以此让项目更加具有可玩性!
5:拿该项目练手或者作为一个python简单的课程设计也是一个可以的选择!
6:项目总代码700行左右
用到的编程知识
python基础,os文件读写,pygame模块以及面向对象思想!
代码如下
enemy.py类文件(100行代码左右)
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.health = health self.last_attack = pygame.time.get_ticks() self.attack_cooldown = 1000 self.animation_list = animation_list self.frame_index = 0 self.action = 0#0: walk, 1: attack, 2: death self.update_time = pygame.time.get_ticks() #select starting image 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: #check for collision with bullets if pygame.sprite.spritecollide(self, bullet_group, True): #lower enemy health self.health -= 25 #check if enemy has reached the castle if self.rect.right > target.rect.left: self.update_action(1) #move enemy if self.action == 0: #update rectangle position self.rect.x += self.speed #attack if self.action == 1: #check if enough time has passed since last attack 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() #check if health has dropped to zero if self.health <= 0: target.money += 100 target.score += 100 self.update_action(2)#death self.alive = False self.update_animation() #draw image on screen surface.blit(self.image, (self.rect.x - 10, self.rect.y - 15)) def update_animation(self): #define animation cooldown ANIMATION_COOLDOWN = 50 #update image depending on current action self.image = self.animation_list[self.action][self.frame_index] #check if enough time has passed since the last update if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 #if the animation has run out then reset back to the start if self.frame_index >= len(self.animation_list[self.action]): if self.action == 2: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): #check if the new action is different to the previous one if new_action != self.action: self.action = new_action #update the animation settings self.frame_index = 0 self.update_date = pygame.time.get_ticks()
castle.py类文件(500行代码左右)
# 导入库 import pygame import math import os import sys import random import button from pygame import mixer # 初始化pygame pygame.init() # 定义游戏窗口高度和宽度 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 # 加载背景音乐 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) # 创建游戏窗口 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("城堡防卫战") clock = pygame.time.Clock() FPS = 60 # 定义游戏变量 level = 1 high_score = 0 level_difficulty = 0 target_difficulty = 1000 DIFFICULTY_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 # 定义炮塔位置的列表 tower_positions = [ [SCREEN_WIDTH - 250, 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()) # 定义颜色 WHITE = (255, 255, 255) GREY = (100, 100, 100) # 定义字体 font = pygame.font.SysFont('华文彩云', 30) font_60 = pygame.font.SysFont('华文行楷', 60) # 加载图片 bg = pygame.image.load('img/bg.png').convert_alpha() # 城堡 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() # 炮塔 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_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, health, animation_list, x, y, speed): super().__init__() self.alive = True self.speed = speed self.health = health 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.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: # 检查敌人与子弹的碰撞 if pygame.sprite.spritecollide(self, bullet_group, True): # 减少健康 self.health -= 25 # 检查敌人是否已经到达城堡 if self.rect.right > target.rect.left: self.update_action(1) # 移动敌人 if self.action == 0: self.rect.x += 1 # 攻击城堡 if self.action == 1: # 检测冷却时间 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() # 检查敌人血条是否为0 if self.health <= 0: target.money += 100 target.score += 100 self.update_action(2) self.alive = False # 调用更新动画 self.update_animation() # 绘制敌人 # pygame.draw.rect(surface, (255, 255, 255), self.rect, 1) surface.blit(self.image, (self.rect.x - 10, self.rect.y - 15)) def update_animation(self): # 定义动画冷却时间 ANIMATION_COOLDOWN = 50 # 根据选择的冬瓜更新帧 self.image = self.animation_list[self.action][self.frame_index] # 判断多久更新一次帧 if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 # 检查帧数不能超过最大帧数 if self.frame_index >= len(self.animation_list[self.action]): if self.action == 2: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): # 检查新动作与上一个动作是否相同 if new_action != self.action: self.action = new_action # 更新动画重置 self.frame_index = 0 self.update_time = pygame.time.get_ticks() # 加载敌人列表 enemy_animations = [] enemy_tpyes = ['knight', 'goblin', 'purple_goblin', 'red_goblin'] enemy_health = [75, 100, 125, 150] animation_types = ['walk', 'attack', 'death'] for enemy in enemy_tpyes: # 加载动画列表 animation_list = [] for animation in animation_types: # 创建临时列表 temp_list = [] # 定义帧数 num_of_frames = 20 for 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) enemy_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(text, font, text_color, x, y): img = font.render(text, True, text_color) screen.blit(img, (x, y)) # 定义一个显示状态的函数 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), font, GREY, 180, 50) draw_text('级别:' + str(level), font, GREY, SCREEN_WIDTH // 2, 10) draw_text('健康:' + str(castle.health) + "/" + str(castle.max_health), font, GREY, SCREEN_WIDTH - 230, SCREEN_HEIGHT - 50) draw_text('1000', font, GREY, SCREEN_WIDTH - 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, image100, image50, image25, x, y, scale): self.health = 1000 self.max_health = self.health self.fired = False self.money = 0 self.score = 0 width = image100.get_width() height = image100.get_height() self.image100 = pygame.transform.scale(image100, (int(width * scale), int(height * scale))) self.image50 = pygame.transform.scale(image50, (int(width * scale), int(height * scale))) self.image25 = pygame.transform.scale(image25, (int(width * scale), int(height * scale))) 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)) # 在该位置点击鼠标 if pygame.mouse.get_pressed()[0] and 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() # 重置鼠标点击 if pygame.mouse.get_pressed()[0] == False: self.fired = False def draw(self): # 根据血量判断加载那张图片 if self.health <= 250: self.image = self.image25 elif self.health <= 500: self.image = self.image50 else: 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 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): super().__init__() self.got_target = False self.angle = 0 self.last_shot = pygame.time.get_ticks() width = image100.get_width() height = image100.get_height() self.image100 = pygame.transform.scale(image100, (int(width * scale), int(height * scale))) self.image50 = pygame.transform.scale(image50, (int(width * scale), int(height * scale))) self.image25 = pygame.transform.scale(image25, (int(width * scale), int(height * scale))) self.image = self.image100 self.rect = self.image100.get_rect() self.rect.x = x self.rect.y = y def update(self, enemy_group): self.got_target = False for e in enemy_group: 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) # 根据城堡血量判断加载那张图片 if castle.health <= 250: self.image = self.image25 elif castle.health <= 500: self.image = self.image50 else: self.image = self.image100 # 创建子弹类 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.radians(angle) # 角度转换为弧度 self.speed = 10 # 根据角度计算水平和垂直的速度 self.dx = math.cos(self.angle) * self.speed self.dy = -(math.sin(self.angle) * self.speed) def update(self): # 检测子弹是否已经超出窗口 if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT: self.kill() # 移动子弹 self.rect.x += self.dx self.rect.y += self.dy # 创建十字准心 class Crosshair(): def __init__(self, scale): image = pygame.image.load("img/crosshair.png").convert_alpha() width = image.get_width() height = image.get_height() self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale))) self.rect = self.image.get_rect() # 隐藏鼠标指针 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) # 创建城堡 castle = Castle(castle_img_100, castle_img_50, castle_img_25, SCREEN_WIDTH - 250, SCREEN_HEIGHT - 300, 0.2) # 实例化十字准心 crosshair = Crosshair(0.025) # 创建按钮 repair_button = button.Button(SCREEN_WIDTH - 240, 10, repair_img, 0.5) tower_button = button.Button(SCREEN_WIDTH - 130, 10, tower_img_100, 0.1) armour_button = button.Button(SCREEN_WIDTH - 75, 10, armour_img, 1.5) # 创建组 bullet_group = pygame.sprite.Group() enemy_group = pygame.sprite.Group() tower_group = pygame.sprite.Group() # 穿件临时塔 # tower = Tower(tower_img_100, tower_img_50, tower_img_25, SCREEN_WIDTH - 350, SCREEN_HEIGHT - 200, 0.2) # tower_group.add(tower) # 游戏循环显示窗口 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)) # 显示城堡 castle.draw() castle.shoot() # 显示炮塔 tower_group.draw(screen) tower_group.update(enemy_group) # 显示十字准心 crosshair.draw() # 绘制子弹到屏幕 bullet_group.update() bullet_group.draw(screen) # 绘制敌人 enemy_group.update(screen, castle, bullet_group) # 显示详细信息 show_info() # 显示按钮 修理和铠甲按钮 if repair_button.draw(screen): castle.repair() if tower_button.draw(screen): # 检查是否有足够的金钱来建造炮塔 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], tower_positions[len(tower_group)][1], 0.2) tower_group.add(tower) # 减去消耗的金钱数 castle.money -= TOWER_COST if armour_button.draw(screen): castle.armour() # 创建不同的敌人 if level_difficulty < target_difficulty: if pygame.time.get_ticks() - last_enemy > ENEMY_TIMER: # 创建敌人实例 e = random.randint(0, len(enemy_tpyes) - 1) enemy = Enemy(enemy_health[e], enemy_animations[e], -100, SCREEN_HEIGHT - 100, 1) enemy_group.add(enemy) last_enemy = pygame.time.get_ticks() level_difficulty += enemy_health[e] # 检测是所有的的敌人都产生了 if level_difficulty >= target_difficulty: # 检查有多少敌人仍然是活着的 enemies_alive = 0 for e in enemy_group: if e.alive == True: enemies_alive += 1 # 检测如果活着的敌人都被消灭了则当前级别就完成了 if enemies_alive == 0 and next_level == False: next_level = True level_reset_time = pygame.time.get_ticks() # 判断是否进入下一关 if next_level == True: draw_text('关卡已完成', font_60, WHITE, 200, 300) # 更新最高分 if castle.score > high_score: high_score = castle.score with open('socre.txt', 'w') as file: file.write(str(high_score)) 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 enemy_group.empty() # 检查游戏是否结束 if castle.health <= 0: game_over = True else: draw_text('游戏结束!', font, GREY, 300, 300) draw_text('按下"A"重新进入游戏', font, GREY, 250, 350) pygame.mouse.set_visible(True) key = pygame.key.get_pressed() if key[pygame.K_a]: # 重置游戏 game_over = False level = 1 target_difficulty = 1000 level_difficulty = 0 last_enemy = pygame.time.get_ticks() enemy_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()
button.py类文件(50行代码左右)
import pygame # 按钮类 class Button(): def __init__(self, x, y, image, scale): width = image.get_width() height = image.get_height() self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale))) self.rect = self.image.get_rect() self.rect.topleft = (x, y) self.clicked = False def draw(self, surface): action = False # 得到鼠标的位置 pos = pygame.mouse.get_pos() # 检测鼠标指针的碰撞 if self.rect.collidepoint(pos): if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False: self.clicked = True action = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False # 画按钮到屏幕上 surface.blit(self.image, (self.rect.x, self.rect.y)) return action
部分运行截图
到此这篇关于Python开发之城堡保卫战游戏的实现的文章就介绍到这了,更多相关Python城堡保卫战游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
赞 (0)