使用python + pygame 编写小游戏:炮兵训练

使用python + pygame 编写小游戏:炮兵训练

关于Python中的pygame游戏模块的介绍,可参见 https://blog.youkuaiyun.com/cnds123/article/details/119514520

先看运行界面(其部分源码参考自网络):

源码如下:

import pygame
import sys
import math
import random
import time
 
# 初始化 Pygame
pygame.init()
 
# 设置窗口大小
WIDTH, HEIGHT = 800, 600
win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("炮兵训练游戏")
 
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
GRAY = (100, 100, 100)
DARK_GRAY = (50, 50, 50)
YELLOW = (255, 255, 0)
ORANGE = (255, 165, 0)
BLUE = (0, 0, 255)

tree_x, tree_y = 50, HEIGHT - 200
tree_destroyed = False

# 树的大小变量
tree_scale = 1.0
 
cannon_x, cannon_y = WIDTH - 150, HEIGHT - 100
cannon_angle = math.pi * 3 / 4
cannon_angle_step = math.pi / 36
 
cannonball_radius = 5
cannonball_speed = 10
cannonball_fired = False
cannonball_hit_tree = False
 
# 爆炸效果相关变量
explosion_active = False
explosion_x, explosion_y = 0, 0
explosion_radius = 0
explosion_max_radius = 50
explosion_duration = 0
explosion_max_duration = 20
explosion_particles = []

random.seed(time.time())
tree_x = random.randint(40, round(WIDTH/3))
score = 0
gravity = 1
 
run = True
font = pygame.font.Font("c:/windows/fonts/simsun.ttc", 20)

# 爆炸粒子类
class Particle:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.vx = random.uniform(-3, 3)
        self.vy = random.uniform(-3, 3)
        self.radius = random.randint(2, 6)
        self.color = random.choice([YELLOW, ORANGE, RED])
        self.lifetime = random.randint(10, 30)
    
    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.lifetime -= 1
        self.radius = max(0, self.radius - 0.1)
    
    def draw(self, surface):
        pygame.draw.circle(surface, self.color, (int(self.x), int(self.y)), int(self.radius))

def point_in_triangle(px, py, x1, y1, x2, y2, x3, y3):
    def sign(x1, y1, x2, y2, x3, y3):
        return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3)
    
    d1 = sign(px, py, x1, y1, x2, y2)
    d2 = sign(px, py, x2, y2, x3, y3)
    d3 = sign(px, py, x3, y3, x1, y1)

    has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
    has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)

    return not (has_neg and has_pos)

while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                if not cannonball_fired:
                    cannonball_fired = True
                    cannonball_x = cannon_x + 100
                    cannonball_y = cannon_y + 10
                    cannonball_velocity_x = cannonball_speed * math.cos(cannon_angle)
                    cannonball_velocity_y = -cannonball_speed * math.sin(cannon_angle)
            elif event.key == pygame.K_UP:
                cannon_angle -= cannon_angle_step
            elif event.key == pygame.K_DOWN:
                cannon_angle += cannon_angle_step
            elif event.key == pygame.K_LEFT:
                gravity -= 1
                if gravity < 1:
                    gravity = 1
            elif event.key == pygame.K_RIGHT:
                gravity += 1
                if gravity > 5:
                    gravity = 5
 
    if cannonball_fired and not cannonball_hit_tree:
        cannonball_x += cannonball_velocity_x
        cannonball_velocity_y += 0.2 - (gravity * 0.01) 
        cannonball_y += cannonball_velocity_y
        if cannonball_y > HEIGHT:
            # 炮弹落地爆炸
            explosion_active = True
            explosion_x, explosion_y = cannonball_x, HEIGHT
            explosion_radius = 0
            explosion_duration = 0
            # 创建爆炸粒子
            explosion_particles = [Particle(explosion_x, explosion_y) for _ in range(30)]
            cannonball_fired = False
 
    win.fill(WHITE)
 
    # 绘制地面
    pygame.draw.rect(win, GREEN, (0, HEIGHT - 50, WIDTH, 50))
    
    if not tree_destroyed:
        if cannonball_hit_tree:
            # 使用tree_scale缩放树的大小
            tree_top_x = tree_x + 50 * tree_scale
            tree_left_x = tree_x
            tree_right_x = tree_x + 100 * tree_scale
            tree_top_y = tree_y
            tree_bottom_y = tree_y + 150 * tree_scale
            
            pygame.draw.polygon(win, RED, [(tree_top_x, tree_top_y), 
                                          (tree_left_x, tree_bottom_y), 
                                          (tree_right_x, tree_bottom_y)]) 
        else:
            # 使用tree_scale缩放树的大小
            tree_top_x = tree_x + 50 * tree_scale
            tree_left_x = tree_x
            tree_right_x = tree_x + 100 * tree_scale
            tree_top_y = tree_y
            tree_bottom_y = tree_y + 150 * tree_scale
            
            pygame.draw.polygon(win, BLUE, [(tree_top_x, tree_top_y), 
                                            (tree_left_x, tree_bottom_y), 
                                            (tree_right_x, tree_bottom_y)])
             
        # 树干也要相应缩放
        trunk_width = 10 * tree_scale
        trunk_height = 50 * tree_scale
        trunk_x = tree_x + 45 * tree_scale
        pygame.draw.rect(win, BLACK, (trunk_x, tree_bottom_y, trunk_width, trunk_height))
    
    cannonball_hit_tree = False
 
    # 绘制更像真实的炮
    # 炮架 - 尺寸减半
    pygame.draw.rect(win, DARK_GRAY, (cannon_x + 85, cannon_y + 5, 30, 20))
    pygame.draw.rect(win, GRAY, (cannon_x + 75, cannon_y + 20, 50, 10))
    # 炮筒 - 长度和宽度减半
    cannon_end_x = cannon_x + 100 + 35 * math.cos(cannon_angle)
    cannon_end_y = cannon_y + 5 - 35 * math.sin(cannon_angle)
    pygame.draw.line(win, DARK_GRAY, (cannon_x + 100, cannon_y + 5),
                     (cannon_end_x, cannon_end_y), 10)
    # 炮口 - 尺寸减半
    pygame.draw.circle(win, BLACK, (int(cannon_end_x), int(cannon_end_y)), 5)
    # 炮轮 - 尺寸减半
    pygame.draw.circle(win, BLACK, (cannon_x + 85, cannon_y + 25), 10)
    pygame.draw.circle(win, BLACK, (cannon_x + 115, cannon_y + 25), 10)
 
    # 绘制炮弹
    if cannonball_fired:
        pygame.draw.circle(win, BLACK, (int(cannonball_x), int(cannonball_y)), cannonball_radius)
    
    # 处理爆炸效果
    if explosion_active:
        explosion_duration += 1
        explosion_radius = min(explosion_max_radius, explosion_radius + 3)
        
        # 更新和绘制爆炸粒子
        for particle in explosion_particles[:]:
            particle.update()
            if particle.lifetime <= 0:
                explosion_particles.remove(particle)
            else:
                particle.draw(win)
        
        if explosion_duration >= explosion_max_duration:
            explosion_active = False
            explosion_particles = []
 
    if not tree_destroyed and cannonball_fired:
        # 使用tree_scale调整树的顶点
        tree_top_x = tree_x + 50 * tree_scale
        tree_left_x = tree_x
        tree_right_x = tree_x + 100 * tree_scale
        tree_top_y = tree_y
        tree_bottom_y = tree_y + 150 * tree_scale

        # 检查炮弹是否在树的三角形内
        if point_in_triangle(cannonball_x, cannonball_y, 
                             tree_top_x, tree_top_y, 
                             tree_left_x, tree_bottom_y, 
                             tree_right_x, tree_bottom_y):
            # 击中树木,触发爆炸
            explosion_active = True
            explosion_x, explosion_y = cannonball_x, cannonball_y
            explosion_radius = 0
            explosion_duration = 0
            # 创建爆炸粒子
            explosion_particles = [Particle(explosion_x, explosion_y) for _ in range(50)]
            
            cannonball_fired = False
            score += 1
            cannonball_hit_tree = True
            
            # 生成新树,位置和大小都随机变化
            tree_x = random.randint(40, round(WIDTH/3))
            # 随机生成新的树大小比例,范围在0.7到1.5之间
            tree_scale = random.uniform(0.7, 1.5)
 
    score_text = font.render("得分: " + str(score), True, BLACK)
    win.blit(score_text, (10, 10))
    # 调整提示文字位置,确保不被炮遮挡
    gravity_text = font.render("当前火力: " + str(gravity), True, BLACK)
    win.blit(gravity_text, (WIDTH - 130, HEIGHT - 40))
    controls_text = font.render("空格 开炮,↑ ↓炮口角度,← →火力", True, BLACK)
    win.blit(controls_text, (WIDTH - 360, HEIGHT - 20))
 
    pygame.display.update()
    pygame.time.Clock().tick(30)
 
pygame.quit()
sys.exit()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值