You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pygame中实现计时器,添加飞船被击中后10秒禁移功能?

问题描述

我是Pygame编程新手,跟着教程做完了一款太空侵略者游戏,现在想给游戏加新功能:当敌人发射的激光(已有对应图片)击中飞船时,飞船10秒内无法移动。同时想搞懂Pygame里怎么用时间和做计时器。

游戏概述

这款太空侵略者游戏的核心逻辑:

  • 敌人沿X轴移动并缓慢下落
  • 底部飞船可沿X轴移动,能射击子弹消灭敌人
  • 敌人被消灭后会重生,敌人抵达底部则游戏结束

现有代码

# importing modules
import pygame
import random
import math
from pygame import mixer

# initialize pygame
pygame.init()

# creating a window
screen = pygame.display.set_mode((800, 600))

# Background Music
mixer.music.load('background.wav')
mixer.music.play(-1)

# Background

bg_img = pygame.image.load("background3.png")
bg = pygame.transform.scale(bg_img, (800, 600))

# Title and Icon
pygame.display.set_caption("Space Shooters")
icon = pygame.image.load('spaceship.png')
pygame.display.set_icon(icon)

# Player
player = pygame.image.load('spaceship2.png')
playerX = 370
playerY = 500
playerX_change = 0

# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6

for i in range(num_of_enemies):
    enemyImg.append(pygame.image.load('enemy.png'))
    enemyX.append(random.randint(6, 730))
    enemyY.append(random.randint(45, 150))
    enemyX_change.append(0.3)
    enemyY_change.append(40)

# Bullet
# Ready - The bullet can't be seen
# Fire - The bullet has been shot
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 1.5
bullet_state = "Ready"

# Score

score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)

textX = 10
textY = 10

# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)


# Function for displaying text
def show_score(x, y):
    score = font.render("Score : " + str(score_value), True, (255, 255, 255))
    screen.blit(score, (x, y))


def game_over_text():
    over_text = over_font.render("GAME OVER", True, (255, 255, 255))
    screen.blit(over_text, (200, 250))


# Defining and drawing spaceship
def spaceship(x, y):
    screen.blit(player, (x, y))


# Defining and drawing enemy
def enemy(x, y, i):
    screen.blit(enemyImg[i], (x, y))


def fire_bullet(x, y):
    global bullet_state
    bullet_state = "Fire"
    screen.blit(bulletImg, (x + 16, y + 10))


def Iscollision(enemyX, enemyY, bulletX, bulletY):
    distance = math.sqrt((math.pow(enemyX - bulletX, 2)) + (math.pow(enemyY - bulletY, 2)))
    if distance < 27:
        return True
    else:
        return False


# making the game window run endlessly and game loop
running = True

while running:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # Keystroke check (right, left)
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            playerX_change = -0.3
        if event.key == pygame.K_RIGHT:
            playerX_change = 0.3
        if event.key == pygame.K_SPACE:
            # Checking whether bullet is there on screen, if not making it ready, if yes disabling spacebar
            if bullet_state == "Ready":
                # Get the current X cordinate of spaceship
                bulletX = playerX
                fire_bullet(bulletX, bulletY)
                bullet_sound = mixer.Sound('laser.wav')
                bullet_sound.play()
    if event.type == pygame.KEYUP:
        if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
            playerX_change = 0

# Changing X coordinates to move spaceship
playerX += playerX_change

if playerX <= 6:
    playerX = 6

elif playerX >= 730:
    playerX = 730

screen.fill(0)

screen.blit(bg, (0, 0))

# Enemy Movement

for i in range(num_of_enemies):

    # Game Over
    if enemyY[i] > 440:
        for j in range(num_of_enemies):
            enemyY[j] = 2000
        game_over_text()
        break

for i in range(num_of_enemies):
    enemyX[i] += enemyX_change[i]

    if enemyX[i] <= 6:
        enemyX_change[i] = 0.3
        enemyY[i] += enemyY_change[i]

    elif enemyX[i] >= 730:
        enemyX_change[i] = -0.3
        enemyY[i] += enemyY_change[i]

    # Collision
    collision = Iscollision(enemyX[i], enemyY[i], bulletX, bulletY)
    # if collision and if collision is true are both the same

    if collision:
        collision_sound = mixer.Sound('explosion.wav')
        collision_sound.play()
        bulletY = 480
        bullet_state = "Ready"
        score_value += 1
        enemyX[i] = random.randint(6, 730)
        enemyY[i] = random.randint(45, 150)

    enemy(enemyX[i], enemyY[i], i)

# Deleting each frame of enemy moving so that it runs smoothly

# Bullet Movement

if bulletY <= 0:
    bulletY = 480
    bullet_state = "Ready"

if bullet_state == "Fire":
    fire_bullet(bulletX, bulletY)
    bulletY -= bulletY_change

spaceship(playerX, playerY)

show_score(textX, textY)

# updating display
pygame.display.update()

需求说明

  1. 添加敌人激光系统:敌人随机发射激光(已有激光图片)
  2. 激光击中飞船后,飞船10秒内无法移动
  3. 理解Pygame中时间管理和计时器的实现方式

解决方案

一、Pygame时间与计时器基础

Pygame中常用pygame.time.get_ticks()获取从初始化到当前的毫秒数(1秒=1000毫秒),通过记录两个时间点的差值来计算时间间隔,这是实现计时器的核心方法。

二、分步实现功能

1. 添加敌人激光的相关变量

在敌人变量定义后,添加激光的全局变量:

# Enemy Laser
enemy_laserImg = pygame.image.load('enemy_laser.png')  # 替换成你的激光图片路径
enemy_lasers = []  # 存储所有活跃的敌人激光,每个元素是(x, y)坐标和移动速度
enemy_laser_speed = 0.8  # 敌人激光下落速度
laser_cooldown = 2000  # 敌人发射激光的冷却时间(毫秒)
last_laser_time = 0  # 记录上次发射激光的时间

2. 添加敌人发射激光的逻辑

在游戏循环里,每次循环检查是否到了发射激光的时间:

# 敌人随机发射激光
current_time = pygame.time.get_ticks()
if current_time - last_laser_time > laser_cooldown:
    # 随机选一个敌人发射激光
    random_enemy = random.randint(0, num_of_enemies - 1)
    enemy_x = enemyX[random_enemy]
    enemy_y = enemyY[random_enemy]
    enemy_lasers.append([enemy_x + 16, enemy_y + 32])  # 调整坐标让激光从敌人中心发出
    last_laser_time = current_time
    # 可以添加发射激光的音效
    # enemy_laser_sound = mixer.Sound('enemy_laser.wav')
    # enemy_laser_sound.play()

3. 添加激光移动和碰撞检测逻辑

在子弹移动逻辑后添加:

# 敌人激光移动与碰撞检测
for laser in enemy_lasers[:]:  # 用[:]复制列表,避免循环中修改列表出错
    laser[1] += enemy_laser_speed
    # 绘制激光
    screen.blit(enemy_laserImg, (laser[0], laser[1]))
    # 激光超出屏幕则移除
    if laser[1] > 600:
        enemy_lasers.remove(laser)
    # 检测激光是否击中飞船
    distance = math.sqrt((math.pow(laser[0] - playerX, 2)) + (math.pow(laser[1] - playerY, 2)))
    if distance < 27:
        enemy_lasers.remove(laser)
        # 触发飞船无法移动的状态
        player_stunned = True
        stunned_start_time = current_time  # 记录被击中的时间
        # 可以添加被击中的音效
        # hit_sound = mixer.Sound('hit.wav')
        # hit_sound.play()

4. 添加飞船被眩晕的状态管理

首先在玩家变量定义处添加状态变量:

# Player
player = pygame.image.load('spaceship2.png')
playerX = 370
playerY = 500
playerX_change = 0
player_stunned = False  # 标记是否被眩晕
stunned_duration = 10000  # 眩晕时长10秒(10000毫秒)
stunned_start_time = 0  # 记录开始眩晕的时间

然后修改玩家移动的按键逻辑,只有在未被眩晕时才响应移动:

# Keystroke check (right, left)
if event.type == pygame.KEYDOWN:
    if not player_stunned:  # 未被眩晕时才允许移动
        if event.key == pygame.K_LEFT:
            playerX_change = -0.3
        if event.key == pygame.K_RIGHT:
            playerX_change = 0.3
    if event.key == pygame.K_SPACE:
        if bullet_state == "Ready":
            bulletX = playerX
            fire_bullet(bulletX, bulletY)
            bullet_sound = mixer.Sound('laser.wav')
            bullet_sound.play()
if event.type == pygame.KEYUP:
    if not player_stunned:
        if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
            playerX_change = 0

最后在游戏循环里检查眩晕是否结束:

# 检查眩晕状态是否结束
current_time = pygame.time.get_ticks()
if player_stunned and current_time - stunned_start_time > stunned_duration:
    player_stunned = False

5. 修复原代码的缩进问题

原代码中playerX += playerX_change、边界判断、screen.fill(0)等代码都在while running循环外面,这会导致逻辑错误,需要把这些代码缩进,放到循环内部。

三、完整修改后的代码

# importing modules
import pygame
import random
import math
from pygame import mixer

# initialize pygame
pygame.init()

# creating a window
screen = pygame.display.set_mode((800, 600))

# Background Music
mixer.music.load('background.wav')
mixer.music.play(-1)

# Background
bg_img = pygame.image.load("background3.png")
bg = pygame.transform.scale(bg_img, (800, 600))

# Title and Icon
pygame.display.set_caption("Space Shooters")
icon = pygame.image.load('spaceship.png')
pygame.display.set_icon(icon)

# Player
player = pygame.image.load('spaceship2.png')
playerX = 370
playerY = 500
playerX_change = 0
player_stunned = False
stunned_duration = 10000
stunned_start_time = 0

# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6

for i in range(num_of_enemies):
    enemyImg.append(pygame.image.load('enemy.png'))
    enemyX.append(random.randint(6, 730))
    enemyY.append(random.randint(45, 150))
    enemyX_change.append(0.3)
    enemyY_change.append(40)

# Enemy Laser
enemy_laserImg = pygame.image.load('enemy_laser.png')  # 替换为你的激光图片路径
enemy_lasers = []
enemy_laser_speed = 0.8
laser_cooldown = 2000
last_laser_time = 0

# Bullet
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 1.5
bullet_state = "Ready"

# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10

# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)


def show_score(x, y):
    score = font.render("Score : " + str(score_value), True, (255, 255, 255))
    screen.blit(score, (x, y))


def game_over_text():
    over_text = over_font.render("GAME OVER", True, (255, 255, 255))
    screen.blit(over_text, (200, 250))


def spaceship(x, y):
    screen.blit(player, (x, y))


def enemy(x, y, i):
    screen.blit(enemyImg[i], (x, y))


def fire_bullet(x, y):
    global bullet_state
    bullet_state = "Fire"
    screen.blit(bulletImg, (x + 16, y + 10))


def Iscollision(enemyX, enemyY, bulletX, bulletY):
    distance = math.sqrt((math.pow(enemyX - bulletX, 2)) + (math.pow(enemyY - bulletY, 2)))
    return distance < 27


running = True

while running:
    current_time = pygame.time.get_ticks()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # Keystroke check (right, left)
        if event.type == pygame.KEYDOWN:
            if not player_stunned:
                if event.key == pygame.K_LEFT:
                    playerX_change = -0.3
                if event.key == pygame.K_RIGHT:
                    playerX_change = 0.3
            if event.key == pygame.K_SPACE:
                if bullet_state == "Ready":
                    bulletX = playerX
                    fire_bullet(bulletX, bulletY)
                    bullet_sound = mixer.Sound('laser.wav')
                    bullet_sound.play()
        if event.type == pygame.KEYUP:
            if not player_stunned:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                    playerX_change = 0

    # Check if stunned state is over
    if player_stunned and current_time - stunned_start_time > stunned_duration:
        player_stunned = False

    # Enemy laser spawn logic
    if current_time - last_laser_time > laser_cooldown:
        random_enemy_idx = random.randint(0, num_of_enemies - 1)
        laser_x = enemyX[random_enemy_idx] + 16
        laser_y = enemyY[random_enemy_idx] + 32
        enemy_lasers.append([laser_x, laser_y])
        last_laser_time = current_time

    # Player movement
    if not player_stunned:
        playerX += playerX_change
    # Player boundary check
    if playerX <= 6:
        playerX = 6
    elif playerX >= 730:
        playerX = 730

    screen.fill(0)
    screen.blit(bg, (0, 0))

    # Enemy Movement and collision
    game_over = False
    for i in range(num_of_enemies):
        if enemyY[i] > 440:
            game_over = True
            break

        enemyX[i] += enemyX_change[i]
        if enemyX[i] <= 6:
            enemyX_change[i] = 0.3
            enemyY[i] += enemyY_change[i]
        elif enemyX[i] >= 730:
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:40:19