继续进行“大战外星人”的游戏编程实践,今天主要完成敌人的运动方式和子弹的编程。完成后的效果见题图。
一、游戏效果
外星人飞船在边界之间来回飞行,每碰到边界一次就下降一段距离,玩家可以发射导弹攻击外星人飞船,试图在外星人到达底部前击中它。击中后外星人飞船会消失然后在屏幕上方重新出现。
二、敌人的编程
敌人的行动逻辑,上文已经说了,代码基本上复制player的代码就行了,把原代码中的player换成enemy。在while循环内部增加这一段代码,实现外星飞船碰到边界后就反向(enemyx_change改变符号),同时下降一段距离
enemyx += enemyx_change
if enemyx <= 0.8:
enemyx_change=0.3
enemyy += 4
if enemyx >= 704:
enemyx_change=-0.3
enemyy += 4
三、子弹编程
子弹的逻辑就是取玩家飞机当前所在的位置,然后每个循环y坐标减少,实现向上飞行。同时设定一个状态变量,分为“fire”开火状态,“ready”预备状态,当按下空格键后,状态改为开火状态,只有处于开火状态,子弹才在屏幕上显示。与子弹有关的代码:
bulletImg=pygame.image.load('bullet.png')
bulletx=370
bullety=460
bullety_change=0.8
bullet_state='ready'
def bullet(x,y):
global bullet_state
bullet_state='fire'
screen.blit(bulletImg,(x+5,y+10))
...
running=True
while running:
....
if bullet_state == 'fire':
bullet(bulletx,bullety)
bullety -= bullety_change
if bullety <= 0:
bullet_state = 'ready'
bullety=460
四、碰撞检测
当子弹击中外星飞船时,外星飞船会消失,然后从屏幕上方重新出现。这个过程需要进行碰撞检测。碰撞检测的原理很简单,就是计算子弹和外星飞船之间的距离,当距离小于一个数值时就认为两者发生了碰撞。基于勾股定理的两点间距离公式:
与碰撞检测有关的代码:
def isCollision(enemyx,enemyy,bulletx,bullety):
distance=math.sqrt((enemyx+52.5-bulletx)**2+(enemyy+60-bullety)**2)
if distance <50 :
return True
else :
return False
....
if isCollision(enemyx,enemyy,bulletx,bullety) :
bullet_state = 'ready'
bullety=460
score += 1
enemyx=randint(0,704)
enemyy=randint(50,150)
print(score)
从上面的代码中可以看出,当检测到碰撞发生,子弹的状态会变为“ready”预备状态,不再显示,而敌人也会在屏幕上部重新出现,同时还有一个用来计分的变量score会加一。后面会学习如何在屏幕上显示分数。
五、目前程序的源代码和部分素材
外星敌人
导弹
游戏背景
程序源代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame
from random import randint
import math
# init
pygame.init()
# create screen
screen=pygame.display.set_mode((800,600))
#title and icon
pygame.display.set_caption('大战外星人')
icon=pygame.image.load('ufo.png')
pygame.display.set_icon(icon)
#player
playerImg=pygame.image.load('f18.png')
playerx=370
playery=460
playerx_change=0
def player(x,y):
screen.blit(playerImg,(x,y))
#background
backgroundImg=pygame.image.load('background.jpg')
#enemy
enemyImg=pygame.image.load('enemy.png')
enemyx=randint(0,704)
enemyy=randint(50,150)
enemyx_change=0.2
score = 0
def enemy(x,y):
screen.blit(enemyImg,(x,y))
#bullet
bulletImg=pygame.image.load('bullet.png')
bulletx=370
bullety=460
bullety_change=0.8
bullet_state='ready'
def bullet(x,y):
global bullet_state
bullet_state='fire'
screen.blit(bulletImg,(x+5,y+10))
def isCollision(enemyx,enemyy,bulletx,bullety):
distance=math.sqrt((enemyx+52.5-bulletx)**2+(enemyy+60-bullety)**2)
if distance <50 :
return True
else :
return False
running=True
while running:
screen.fill((0,0,128))
screen.blit(backgroundImg,(0,0))
#检查左右键是否被按下
for event in pygame.event.get():
if event.type == pygame.QUIT:
running=False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerx_change -= 0.4
if event.key == pygame.K_RIGHT:
playerx_change += 0.4
if event.key == pygame.K_SPACE and bullet_state == 'ready':
bullet(playerx,bullety)
bulletx=playerx
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerx_change=0
playerx += playerx_change
if playerx <= 0.8:
playerx=0.8
if playerx >= 704:
playerx=704
player(playerx,playery)
enemyx += enemyx_change
if enemyx <= 0.8:
enemyx_change=0.3
enemyy += 4
if enemyx >= 704:
enemyx_change=-0.3
enemyy += 4
enemy(enemyx,enemyy)
if bullet_state == 'fire':
bullet(bulletx,bullety)
bullety -= bullety_change
if bullety <= 0:
bullet_state = 'ready'
bullety=460
if isCollision(enemyx,enemyy,bulletx,bullety) :
bullet_state = 'ready'
bullety=460
score += 1
enemyx=randint(0,704)
enemyy=randint(50,150)
print(score)
pygame.display.update()