使用 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()
输出: