📜  使用 PyGame - Python构建太空入侵者

📅  最后修改于: 2022-05-13 01:54:48.692000             🧑  作者: Mango

使用 PyGame - Python构建太空入侵者

在本文中,我们将使用Python中的 PyGame 构建太空入侵者。

使用的文件可以从这里下载。

方法:

  • 导入所需的模块。
  • 初始化 pygame。
  • 创建三个函数:
    • isCollision():它告诉我们是否发生了碰撞?
    • game_over():根据代码决定游戏是否结束,返回 True 或 False。
    • show_score(x, y):在屏幕上显示分数
  • 创建一个无限循环以连续执行代码。

碰撞():

其实很简单。在解释这一点之前,我们希望您先看看下面游戏循环中代码的碰撞部分:

Python3
# Collision
collision = isCollision(bullet_X, invader_X[i], bullet_Y, invader_Y[i])
if collision:
        score_val += 1
        bullet_Y = 600
        bullet_state = "rest"
        invader_X[i] = random.randint(64, 736)
        invader_Y[i] = random.randint(30, 200)
        invader_Xchange[i] *= -1


Python3
def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2, 2)) + (math.pow(y1 - y2, 2)))
    if distance <= 50:
        return True
    else:
        return False


Python3
# movement of the invader
for i in range(no_of_invaders):
 
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break


Python3
# y-coordinate of invader more than 450
if invader_Y[i] >= 450:
   
        # distance between the x-coordinate of invader
        # and spaceship
        if abs(player_X-invader_X[i]) < 80:
            #....... rest code .....#


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


Python3
import pygame
import random
import math
from pygame import mixer
 
# initializing pygame
pygame.init()
 
# creating screen
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width,
                                  screen_height))
 
# caption and icon
pygame.display.set_caption("Welcome to Space\
Invaders Game by:- styles")
 
 
# Score
score_val = 0
scoreX = 5
scoreY = 5
font = pygame.font.Font('freesansbold.ttf', 20)
 
# Game Over
game_over_font = pygame.font.Font('freesansbold.ttf', 64)
 
 
def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255,255,255))
    screen.blit(score, (x , y ))
 
def game_over():
    game_over_text = game_over_font.render("GAME OVER",
                                           True, (255,255,255))
    screen.blit(game_over_text, (190, 250))
 
# Background Sound
mixer.music.load('data/background.wav')
mixer.music.play(-1)
 
# player
playerImage = pygame.image.load('data/spaceship.png')
player_X = 370
player_Y = 523
player_Xchange = 0
 
# Invader
invaderImage = []
invader_X = []
invader_Y = []
invader_Xchange = []
invader_Ychange = []
no_of_invaders = 8
 
for num in range(no_of_invaders):
    invaderImage.append(pygame.image.load('data/alien.png'))
    invader_X.append(random.randint(64, 737))
    invader_Y.append(random.randint(30, 180))
    invader_Xchange.append(1.2)
    invader_Ychange.append(50)
 
# Bullet
# rest - bullet is not moving
# fire - bullet is moving
bulletImage = pygame.image.load('data/bullet.png')
bullet_X = 0
bullet_Y = 500
bullet_Xchange = 0
bullet_Ychange = 3
bullet_state = "rest"
 
# Collision Concept
def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2,2)) +
                         (math.pow(y1 - y2,2)))
    if distance <= 50:
        return True
    else:
        return False
 
def player(x, y):
    screen.blit(playerImage, (x - 16, y + 10))
 
def invader(x, y, i):
    screen.blit(invaderImage[i], (x, y))
 
def bullet(x, y):
    global bullet_state
    screen.blit(bulletImage, (x, y))
    bullet_state = "fire"
 
# game loop
running = True
while running:
 
    # RGB
    screen.fill((0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
 
        # Controlling the player movement
        # from the arrow keys
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player_Xchange = -1.7
            if event.key == pygame.K_RIGHT:
                player_Xchange = 1.7
            if event.key == pygame.K_SPACE:
               
                # Fixing the change of direction of bullet
                if bullet_state is "rest":
                    bullet_X = player_X
                    bullet(bullet_X, bullet_Y)
                    bullet_sound = mixer.Sound('data/bullet.wav')
                    bullet_sound.play()
        if event.type == pygame.KEYUP:
            player_Xchange = 0
 
    # adding the change in the player position
    player_X += player_Xchange
    for i in range(no_of_invaders):
        invader_X[i] += invader_Xchange[i]
 
    # bullet movement
    if bullet_Y <= 0:
        bullet_Y = 600
        bullet_state = "rest"
    if bullet_state is "fire":
        bullet(bullet_X, bullet_Y)
        bullet_Y -= bullet_Ychange
 
    # movement of the invader
    for i in range(no_of_invaders):
         
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break
 
        if invader_X[i] >= 735 or invader_X[i] <= 0:
            invader_Xchange[i] *= -1
            invader_Y[i] += invader_Ychange[i]
        # Collision
        collision = isCollision(bullet_X, invader_X[i],
                                bullet_Y, invader_Y[i])
        if collision:
            score_val += 1
            bullet_Y = 600
            bullet_state = "rest"
            invader_X[i] = random.randint(64, 736)
            invader_Y[i] = random.randint(30, 200)
            invader_Xchange[i] *= -1
 
        invader(invader_X[i], invader_Y[i], i)
 
 
    # restricting the spaceship so that
    # it doesn't go out of screen
    if player_X <= 16:
        player_X = 16;
    elif player_X >= 750:
        player_X = 750
 
 
    player(player_X, player_Y)
    show_score(scoreX, scoreY)
    pygame.display.update()


“isCollision()”函数返回的值存储在“collision”变量中。函数返回的值是 True 或 False,取决于函数内部为碰撞设置的标准。让我们看一下 isCollision()函数内部的内容:

Python3

def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2, 2)) + (math.pow(y1 - y2, 2)))
    if distance <= 50:
        return True
    else:
        return False

函数内部设置的碰撞标准是最简单的,即子弹与入侵者(我们的敌人)之间的距离。如您所见,用于计算距离的公式是每个学生在高中数学课上学习的东西。它是坐标为 (x1, y1) 和 (x2, y2) 的两点之间的距离公式,它们作为 isCollision()函数的参数传递。

在这里,我们设置了一个标准,如果距离的值小于或等于 50,则表示发生了碰撞。该值是根据用于子弹和入侵者的 png 图像的高度和宽度来选择的。可以使用试错法根据您自己的要求调整该值。

因此,每当子弹和入侵者的位置发生变化时,isCollision()函数就会检查是否发生了碰撞。这就是在游戏循环中调用它的原因。

游戏结束():

根据代码决定游戏是否结束,哪个返回 True 或 False。为了理解 game_over()函数,让我们看一下游戏循环中存在的以下代码片段:

Python3

# movement of the invader
for i in range(no_of_invaders):
 
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break

在进入代码解释之前,建议先了解一下pygame中遵循的坐标系。看看下面的图片:

所以,游戏结束的标准也是碰撞。当入侵者的y坐标大于飞船即450(飞船的y坐标),并且入侵者与飞船的距离小于80时发生碰撞,调用game_over()函数紧接着是爆炸声。

以下几行将使其更加清晰:

Python3

# y-coordinate of invader more than 450
if invader_Y[i] >= 450:
   
        # distance between the x-coordinate of invader
        # and spaceship
        if abs(player_X-invader_X[i]) < 80:
            #....... rest code .....#

上面检查了游戏中存在的所有入侵者,这是由开始时的 for 循环确保的。

显示分数(x,y):

它在屏幕上显示分数。

Python3

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

show_score()函数所做的唯一事情是以用户选择的正确字体在屏幕上显示分数。

每次子弹与入侵者发生碰撞时,都会增加一个变量“ score_val ”。然后这个变量通过 show_score()函数显示在屏幕上,如上面的代码片段所示。

下面是实现:

Python3

import pygame
import random
import math
from pygame import mixer
 
# initializing pygame
pygame.init()
 
# creating screen
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width,
                                  screen_height))
 
# caption and icon
pygame.display.set_caption("Welcome to Space\
Invaders Game by:- styles")
 
 
# Score
score_val = 0
scoreX = 5
scoreY = 5
font = pygame.font.Font('freesansbold.ttf', 20)
 
# Game Over
game_over_font = pygame.font.Font('freesansbold.ttf', 64)
 
 
def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255,255,255))
    screen.blit(score, (x , y ))
 
def game_over():
    game_over_text = game_over_font.render("GAME OVER",
                                           True, (255,255,255))
    screen.blit(game_over_text, (190, 250))
 
# Background Sound
mixer.music.load('data/background.wav')
mixer.music.play(-1)
 
# player
playerImage = pygame.image.load('data/spaceship.png')
player_X = 370
player_Y = 523
player_Xchange = 0
 
# Invader
invaderImage = []
invader_X = []
invader_Y = []
invader_Xchange = []
invader_Ychange = []
no_of_invaders = 8
 
for num in range(no_of_invaders):
    invaderImage.append(pygame.image.load('data/alien.png'))
    invader_X.append(random.randint(64, 737))
    invader_Y.append(random.randint(30, 180))
    invader_Xchange.append(1.2)
    invader_Ychange.append(50)
 
# Bullet
# rest - bullet is not moving
# fire - bullet is moving
bulletImage = pygame.image.load('data/bullet.png')
bullet_X = 0
bullet_Y = 500
bullet_Xchange = 0
bullet_Ychange = 3
bullet_state = "rest"
 
# Collision Concept
def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2,2)) +
                         (math.pow(y1 - y2,2)))
    if distance <= 50:
        return True
    else:
        return False
 
def player(x, y):
    screen.blit(playerImage, (x - 16, y + 10))
 
def invader(x, y, i):
    screen.blit(invaderImage[i], (x, y))
 
def bullet(x, y):
    global bullet_state
    screen.blit(bulletImage, (x, y))
    bullet_state = "fire"
 
# game loop
running = True
while running:
 
    # RGB
    screen.fill((0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
 
        # Controlling the player movement
        # from the arrow keys
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player_Xchange = -1.7
            if event.key == pygame.K_RIGHT:
                player_Xchange = 1.7
            if event.key == pygame.K_SPACE:
               
                # Fixing the change of direction of bullet
                if bullet_state is "rest":
                    bullet_X = player_X
                    bullet(bullet_X, bullet_Y)
                    bullet_sound = mixer.Sound('data/bullet.wav')
                    bullet_sound.play()
        if event.type == pygame.KEYUP:
            player_Xchange = 0
 
    # adding the change in the player position
    player_X += player_Xchange
    for i in range(no_of_invaders):
        invader_X[i] += invader_Xchange[i]
 
    # bullet movement
    if bullet_Y <= 0:
        bullet_Y = 600
        bullet_state = "rest"
    if bullet_state is "fire":
        bullet(bullet_X, bullet_Y)
        bullet_Y -= bullet_Ychange
 
    # movement of the invader
    for i in range(no_of_invaders):
         
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break
 
        if invader_X[i] >= 735 or invader_X[i] <= 0:
            invader_Xchange[i] *= -1
            invader_Y[i] += invader_Ychange[i]
        # Collision
        collision = isCollision(bullet_X, invader_X[i],
                                bullet_Y, invader_Y[i])
        if collision:
            score_val += 1
            bullet_Y = 600
            bullet_state = "rest"
            invader_X[i] = random.randint(64, 736)
            invader_Y[i] = random.randint(30, 200)
            invader_Xchange[i] *= -1
 
        invader(invader_X[i], invader_Y[i], i)
 
 
    # restricting the spaceship so that
    # it doesn't go out of screen
    if player_X <= 16:
        player_X = 16;
    elif player_X >= 750:
        player_X = 750
 
 
    player(player_X, player_Y)
    show_score(scoreX, scoreY)
    pygame.display.update()

输出: