守卫家园
游戏说明
“守卫家园”是一种二维战斗类计算机游戏,游戏场景中有四个圆形城堡,是玩家要守卫的家园,垂直均匀分布在画布的左侧,位置固定。有一名战士,游戏开始时位于画布左侧中间,按w、a、s、d键可以向上、左、下、右移动战士,战士肩扛弓弩,点击鼠标可以让战士面朝鼠标落点方向并超该方向发射一枚弓箭。敌人从画布右侧发起攻击,每个敌人的垂直初始位置及左移速度随机变化。战士发射的弓箭可以消灭敌人(必须击中),敌人接触到城堡将会导致家园被摧毁游戏的规则也很简单,游戏界面如上图所示。战士成功守卫家园要同时满足以下三个条件:
1、战士消灭敌人的数量达到100
2、至少有1个城堡完好无损
3、逃脱的敌人少于10名(包括摧毁城堡的敌人和越过左侧边线的敌人)
如果全部城堡被敌人摧毁或者消灭的敌人数量未达到100但逃脱的敌人超过了10名,守卫家园失败,游戏结束。
程序说明
游戏主程序的文件名称为HomeGuard.py,通过该项目,你可以巩固前7个项目学会的本领,同时了解Python集合(set)的使用方法、进一步熟悉Python面向对象编程概念。
通过该项目你可以获得以下能力:
l 了解如何在程序中使用集合(set)
l 进一步熟悉Python面向对象编程概念
l 了解如何检测游戏角色之间是否发生了碰撞
l 增强逻辑思维能力
l 培养解决问题的能力
编程步骤
我们已经为该小项目提供了一个基本模板,请仔细阅读模板提供的代码,读懂这些代码有助于你顺利完成本项目。
建议“守卫家园”游戏的编码步骤为:
1、编写计算两点距离的辅助函数distance(p,q),参数p、q为平面坐标点,该函数将用于检测两个对象是否发生碰撞。
2、编写游戏初始化辅助函数init(),在该函数中对全局变量进行初始化,应当通过Soldier类创建一个战士对象、通过Sprite类创建4个城堡对象并存储到castle_group集合中,还应当开启背景音乐。
3、完善class Soldier(战士类),该类的set_angle(self, angle)方法、get_pos(self)方法、set_shooting(self,is_shooting)方法、set_vel(self, new_vel)均非常直观。
shoot (self)方法的功能是发射弓箭,首先应当计算弓箭的初始位置坐标,然后计算弓箭的速度,接着通过Sprite类创建一个弓箭对象并将其存储到arrow_group集合中。
draw(self, canvas)将调用draw_image 并以恰当的私有属性为参数在画布绘制战士,应当根据shooting属性绘制平铺图片中的不同图像来实现射箭的动画效果。
update(self) 方法将用self.vel更新self.pos,如果战士的位置移出画布,应当在画布对面出现。
而collide(self, other)则根据self.move_direction的取值计算是否和另一个静止的棋子发生碰撞,如果发生碰撞或到达棋盘边界则返回True,否则返回False。
4、完善class Sprite(精灵类),该类的get_radius(self)方法、get_pos(self)方法均非常直观。
collide(self, other)用来计算是否和另一个对象发生碰撞,如果发生碰撞则返回True,否则返回False。
draw(self, canvas)将调用draw_image 并以恰当的私有属性为参数在画布绘制精灵,应当根据animated属性绘制平铺图片中的不同图像来实现动画效果。
update(self) 方法将用self.vel更新self.pos,同时要判断age(年龄)是否小于lifespan(寿命),如果小于则返回True,否则返回False。其它函数将更加该方法的返回值决定是否要销毁对象。
5、编写时间事件处理函数enemy_spawner()用来定期产生敌人,请注意在事件处理函数注册部分我们有timer = timer = gui.create_timer(1000, enemy_spawner)语句,这表明游戏程序每1秒会调用enemy_spawner ()函数1次,即每1秒会产生一个敌人。如果game_over和game_success的值为False,首先随机生成敌人的垂直位置,新产生敌人的水平位置总是画布的最右侧,然后随机生成敌人的水平移动速度,接着将敌人的角度设置为0(表示图片不旋转),最后通过Sprite类创建一个敌人对象并将其存储到enemy_group集合中。
6、编写辅助函数process_sprite_group(sprites,canvas)来处理一组精灵,用for循环遍历sprites的一个副本并调用每个精灵的draw方法完成对sprites集合所有精灵的绘制,根据游戏的状态(game_over、game_success)决定是否调用每个精灵的update方法更新精灵,并更加update方法方法返回的值决定是否销毁该精灵。
7、编写辅助函数enemy_escape_check()来检查越过左边界敌人,用for循环遍历enemy_group的一个副本并调用判断每个敌人是否越过左边界,如果越过,增加全局变量enemy_escaped的值以记录逃脱敌人的总数。
8、编写辅助函数group_collide(group,other_object) 检测一组对象和另一个对象是否发生碰撞,用for循环遍历group的一个副本并调用每个对象collide(other_object)方法完成对集合所有对象的检测,如果发生碰撞,通过Sprite类创建一个爆炸对象并将其存储到explosion_group集合并销毁发生碰撞的对象。
9、编写辅助函数group_group_collide(group1, group2) 来检测一组对象和另一个对象发生碰撞的情况,用for循环遍历group1的一个副本并group_collide函数完成两组对象的碰撞检测,如果发生碰撞,累计发生碰撞的次数,通过Sprite类创建一个爆炸对象并将其存储到explosion_group集合并销毁发生碰撞的对象,函数返回碰撞次数。
10、编写屏幕刷新事件处理函数(主后绘制函数)draw(canvas),该函数应进行一下操作:
(1)绘制游戏背景
(2)绘制战士
(3)更新战士
(4)批量绘制和更新所有城堡
(5)批量绘制和更新所有敌人
(6)批量绘制和更新所有箭
(7)检查逃脱的敌人
(8)检查所有敌人和所有箭的碰撞情况
(9)检查所有敌人和所有城堡的碰撞情况
(10)更新控制面板标签的显示内容
(11)判断游戏的输赢结果并绘制对应的画面
11、编写鼠标点击事件的处理函数mouse_handler(pos),如果game_over和game_success的值为False,首先计算鼠标落点和战士之间形成的角度,调用战士的set_angle方法来调整其朝向,然后将战士的shooting属性设置为True,最后调用战士的shoot()方法来发射一枚弓箭。
12、编写按键事件处理函数key_down(key),使得玩家按w、a、s、d键时战士可以向上、左、下、右移动。
13、编写键盘事件处理函数key_up(key),使得玩家释放w、a、s、d中的某个按键时战士停止移动。
项目模板
# “守卫家园”游戏
import simpleguitk as gui
import math
import random
# 全局变量
WIDTH = 800 # 画布宽度
HEIGHT = 600 # 画布高度
enemy_killed = 0 # 消灭敌人数量
castle_left = 4 # 画布完好数量
enemy_escaped = 0 # 逃脱敌人数量
escaped_limit = 10 # 运行逃脱敌人的数量上限
success_limit = 100 # 消灭敌人数量
game_over = False # 守卫是否以失败结束
game_success = False # 守卫是否以成功结束
soldier = None # 战士对象
enemy_group = set([]) # 所有敌人对象的集合
castle_group = set([]) # 所有城堡对象的集合
arrow_group = set([]) # 所有箭对象的集合
explosion_group = set([]) # 所有爆炸对象的集合
# 图片信息类
class ImageInfo:
def __init__(self, center, size, radius=0, lifespan=None, animated=False, frame=None):
self.center = center # 图片的中心坐标
self.size = size # 图片的大小
self.radius = radius # 图片的半径,用来计算是否和其它对象发生碰撞
if lifespan:
self.lifespan = lifespan # 由该图片生成对象的寿命,以帧为单位,通常每秒为60帧
else:
self.lifespan = float('inf') # 表示无穷大
self.animated = animated # 由该图片生成对象是否具备动画效果
self.frame = frame # 为实现动画效果所提供的平铺图片数量
def get_center(self):
return self.center
def get_size(self):
return self.size
def get_radius(self):
return self.radius
def get_lifespan(self):
return self.lifespan
def get_animated(self):
return self.animated
def get_frame(self):
return self.frame
# 加载图片资源
grassland_info = ImageInfo([960, 600], [1920, 1200])
grassland_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/grassland.jpg") # 地面背景
arrow_info = ImageInfo([21, 5], [42, 10],5,60)
arrow_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/arrow.png") # 箭
castle_info = ImageInfo([54, 52], [109, 105],50)
castle_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/castle.png") # 城堡
enemy_info = ImageInfo([32, 15], [64, 29], 15, 1000, True,4)
enemy_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/enemy.png") # 敌人,图像文件中包含4副图片用来实现动画
soldier_info = ImageInfo([32, 26], [64, 52])
soldier_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/soldier.png") # 战士,图像文件中包含2副图片用来实现动画
win_info = ImageInfo([320, 240], [640, 480])
win_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/win.png") # 游戏成功图片
game_over_info = ImageInfo([320, 240], [640, 480])
game_over_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/gameover.png") # 游戏结束图片
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True,24)
explosion_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/explosion.png") # 爆炸,图像文件中包含多副图片用来实现动画
# 加载音效资源
back_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/moonlight.wav") # 背景音乐
shoot_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/shoot.wav") # 箭发射声音
explode_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/explode.wav") # 箭击中敌人的声音
enemy_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/enemy.wav") # 敌人击中城堡的声音
# 游戏初始化辅助函数
def init():
pass
# 计算两点距离的辅助函数
def distance(p,q):
pass
# 处理一组精灵的辅助函数
def process_sprite_group(sprites,canvas):
pass
# 检查越过左边界敌人的辅助函数
def enemy_escape_check():
pass
#
# 检测一组对象和另一个对象是否发生碰撞的辅助函数
def group_collide(group,other_object):
pass
# 检测两组对象是否发生碰撞的辅助函数
def group_group_collide(group1, group2):
pass
# 战士类
class Soldier:
def __init__(self, pos, vel, angle, image, info):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.shooting = False
self.angle = angle
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
def get_pos(self):
pass
def shoot(self):
global arrow_group
arrow_pos = [self.pos[0] + self.image_size[0] * math.cos(self.angle), self.pos[1] + self.image_size[0] * math.sin(self.angle)]
arrow_vel =[0,0]
arrow_vel[0] = 10 * math.cos(self.angle)
arrow_vel[1] = 10 * math.sin(self.angle)
a_arrow = Sprite(arrow_pos, arrow_vel, self.angle, arrow_image, arrow_info, shoot_sound)
arrow_group.add(a_arrow)
def set_angle(self, angle):
pass
def set_shooting(self, is_shooting):
pass
def set_vel(self,new_vel):
self.vel=new_vel
def draw(self,canvas):
pass
def update(self):
pass
# 精灵类
class Sprite:
def __init__(self, pos, vel, ang, image, info, sound = None):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.angle = ang
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.lifespan = info.get_lifespan()
self.animated = info.get_animated()
self.frame = info.get_frame()
self.age = 0
if sound:
sound.set_volume(0.05)
sound.rewind()
sound.play()
def get_radius(self):
pass
def get_pos(self):
pass
def collide(self,other_object):
pass
def draw(self, canvas):
pass
def update(self):
pass
# 主绘制函数
def draw(canvas):
pass
# 处理鼠标点击事件的函数
def mouse_handler(pos):
pass
# 处理键盘按下事件的函数
def key_down(key):
pass
# 处理键盘释放事件
def key_up(key):
pass
# 用来产生敌人的时间事件处理函数
def enemy_spawner():
pass
# 创建窗口
frame = gui.create_frame("守卫家园", WIDTH, HEIGHT)
# 添加按钮
frame.add_button("重新开始", init, 100)
# 添加标签
label_killed = frame.add_label("消灭敌人 = 0")
label_escaped = frame.add_label("逃脱敌人 = 0")
label_attacked = frame.add_label("受到袭击 = 0")
# 注册事件处理函数
frame.set_mouseclick_handler(mouse_handler)
frame.set_keydown_handler(key_down)
frame.set_keyup_handler(key_up)
frame.set_draw_handler(draw)
# 创建定时器
timer = gui.create_timer(1000.0, enemy_spawner)
# 启动游戏
init()
timer.start()
frame.start()
以下为完整代码
# “守卫家园”游戏
import simpleguitk as gui
import math
import random
# 全局变量
WIDTH = 800 # 画布宽度
HEIGHT = 600 # 画布高度
enemy_killed = 0 # 消灭敌人数量
castle_left = 4 # 画布完好数量
enemy_escaped = 0 # 逃脱敌人数量
escaped_limit = 10 # 运行逃脱敌人的数量上限
success_limit = 100 # 消灭敌人数量
game_over = False # 守卫是否以失败结束
game_success = False # 守卫是否以成功结束
soldier = None # 战士对象
enemy_group = set([]) # 所有敌人对象的集合
castle_group = set([]) # 所有城堡对象的集合
arrow_group = set([]) # 所有箭对象的集合
explosion_group = set([]) # 所有爆炸对象的集合
# 图片信息类
class ImageInfo:
def __init__(self, center, size, radius=0, lifespan=None, animated=False, frame=None):
self.center = center
self.size = size
self.radius = radius
if lifespan:
self.lifespan = lifespan
else:
self.lifespan = float('inf')
self.animated = animated
self.frame = frame
def get_center(self):
return self.center
def get_size(self):
return self.size
def get_radius(self):
return self.radius
def get_lifespan(self):
return self.lifespan
def get_animated(self):
return self.animated
def get_frame(self):
return self.frame
# 加载图片资源
grassland_info = ImageInfo([960, 600], [1920, 1200])
grassland_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/grassland.jpg") # 地面背景
arrow_info = ImageInfo([21, 5], [42, 10],5,60)
arrow_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/arrow.png") # 箭
castle_info = ImageInfo([54, 52], [109, 105],50)
castle_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/castle.png") # 城堡
enemy_info = ImageInfo([32, 15], [64, 29], 15, 1000, True,4)
enemy_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/enemy.png") # 敌人,图像文件中包含4副图片用来实现动画
soldier_info = ImageInfo([32, 26], [64, 52])
soldier_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/soldier.png") # 战士,图像文件中包含2副图片用来实现动画
win_info = ImageInfo([320, 240], [640, 480])
win_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/win.png") # 游戏成功图片
game_over_info = ImageInfo([320, 240], [640, 480])
game_over_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/gameover.png") # 游戏结束图片
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True,24)
explosion_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project8/explosion.png") # 爆炸,图像文件中包含多副图片用来实现动画
# 加载音效资源
back_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/moonlight.wav") # 背景音乐
shoot_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/shoot.wav") # 箭发射声音
explode_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/explode.wav") # 箭击中敌人的声音
enemy_sound = gui.load_sound("http://202.201.225.74/video/PythonResoure/ProjectResource/sounds/project8/enemy.wav")# 敌人击中城堡的声音
# 游戏初始化辅助函数
def init():
global soldier, enemy_group, castle_group,arrow_group,enemy_killed,castle_left, explosion_group,game_over, enemy_escaped, game_success
game_over = False
game_success = False
enemy_killed = 0
castle_left = 4
enemy_escaped = 0
soldier = Soldier([castle_info.get_size()[0], HEIGHT / 2], [0, 0], 0, soldier_image, soldier_info)
for i in range(4):
castle = Sprite((castle_info.get_size()[0]/2,HEIGHT / 8 + i * (HEIGHT / 4)),(0,0),0,castle_image,castle_info)
castle_group.add(castle)
enemy_group = set([])
arrow_group = set([])
explosion_group = set([])
back_sound.rewind()
back_sound.set_volume(0.5)
back_sound.play()
# 计算两点距离的辅助函数
def dist(p,q):
return math.sqrt((p[0] - q[0]) ** 2+(p[1] - q[1]) ** 2)
# 处理一组精灵的辅助函数
def process_sprite_group(sprites,canvas):
set_sprites = set(sprites)
for sprite in set_sprites:
sprite.draw(canvas)
if not game_over and not game_success:
if not sprite.update():
sprites.discard(sprite)
# 检查越过左边界敌人的辅助函数
def enemy_escape_check():
global enemy_escaped
set_enemy = set(enemy_group)
for enemy in set_enemy:
if enemy.get_pos()[0] < 0:
enemy_escaped += 1
enemy_group.discard(enemy)
# 检测一组对象和另一个对象是否发生碰撞的辅助函数
def group_collide(group,other_object):
global explosion_group
tmp_group = set(group)
collided = False
for sprite in tmp_group:
if sprite.collide(other_object):
explosion_pos = sprite.get_pos()
a_explosion = Sprite(explosion_pos, [0,0], 0, explosion_image,explosion_info, explode_sound)
explosion_group.add(a_explosion)
group.discard(sprite)
collided = True
return collided
# 检测两组对象是否发生碰撞的辅助函数
def group_group_collide(group1, group2):
global explosion_group
tmp_group1 = set(group1)
i = 0
for object in tmp_group1:
if group_collide(group2, object):
explosion_pos = object.get_pos()
a_explosion = Sprite(explosion_pos, [0,0], 0, explosion_image,explosion_info, explode_sound)
explosion_group.add(a_explosion)
group1.discard(object)
i += 1
return i
# 战士类
class Soldier:
def __init__(self, pos, vel, angle, image, info):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.shooting = False
self.angle = angle
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
def get_pos(self):
return self.pos
def get_radius(self):
return self.radius
def shoot(self):
global arrow_group
arrow_pos = [self.pos[0] + self.image_size[0] * math.cos(self.angle), self.pos[1] + self.image_size[0] * math.sin(self.angle)]
arrow_vel =[0,0]
arrow_vel[0] = 10 * math.cos(self.angle)
arrow_vel[1] = 10 * math.sin(self.angle)
a_arrow = Sprite(arrow_pos, arrow_vel, self.angle, arrow_image, arrow_info, shoot_sound)
arrow_group.add(a_arrow)
def set_angle(self, angle):
self.angle = angle
def set_shooting(self, is_shooting):
self.shooting = is_shooting
def set_vel(self,new_vel):
self.vel=new_vel
def draw(self,canvas):
source_center = [0,0]
if self.shooting:
source_center = [self.image_center[0]+self.image_size[0],self.image_center[1]]
self.shooting = False
else:
source_center = self.image_center
canvas.draw_image(self.image, source_center, self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.pos[0] += self.vel[0]
self.pos[0] = self.pos[0] % WIDTH
self.pos[1] += self.vel[1]
self.pos[1] = self.pos[1] % HEIGHT
# 精灵类
class Sprite:
def __init__(self, pos, vel, ang, image, info, sound = None):
self.pos = [pos[0],pos[1]]
self.vel = [vel[0],vel[1]]
self.angle = ang
self.image = image
self.image_center = info.get_center()
self.image_size = info.get_size()
self.radius = info.get_radius()
self.lifespan = info.get_lifespan()
self.animated = info.get_animated()
self.frame = info.get_frame()
self.age = 0
if sound:
sound.set_volume(0.05)
sound.rewind()
sound.play()
def get_radius(self):
return self.radius
def get_pos(self):
return self.pos
def collide(self,other_object):
if dist(self.pos, other_object.get_pos()) <= self.radius + other_object.get_radius():
return True
else:
return False
def draw(self, canvas):
if self.animated and self.frame > 1:
source_center = [self.image_center[0] +self.age % self.frame * self.image_size[0], self.image_center[1] ]
canvas.draw_image(self.image, source_center, self.image_size, self.pos, self.image_size, self.angle)
else:
canvas.draw_image(self.image, self.image_center, self.image_size, self.pos, self.image_size, self.angle)
def update(self):
self.pos[0] += self.vel[0]
self.pos[1] += self.vel[1]
self.age += 1
if self.age < self.lifespan:
return True
else:
return False
# 主绘制函数
def draw(canvas):
global enemy_killed, castle_left,game_over,enemy_escaped, game_success
# 绘制背景
canvas.draw_image(grassland_image,grassland_info.get_center(),grassland_info.get_size(), [WIDTH / 2, HEIGHT / 2], [WIDTH, HEIGHT])
soldier.draw(canvas) # 绘制战士
soldier.update()
process_sprite_group(castle_group, canvas) # 绘制城堡
process_sprite_group(enemy_group, canvas) # 绘制敌人
process_sprite_group(arrow_group,canvas) # 绘制箭
process_sprite_group(explosion_group,canvas) # 绘制爆炸
enemy_escape_check()
enemy_killed += group_group_collide(enemy_group,arrow_group)
label_killed.set_text("消灭敌人 = " + str(enemy_killed))
i = group_group_collide(enemy_group,castle_group)
castle_left -= i
enemy_escaped += i
label_escaped.set_text("逃脱敌人 = " + str(enemy_escaped))
label_attacked.set_text("完好城堡 = " + str(castle_left))
if castle_left == 0 or enemy_escaped >= escaped_limit:
game_over = True
if enemy_killed >= success_limit:
game_success = True
if game_over:
canvas.draw_image(game_over_image,game_over_info.get_center(),game_over_info.get_size(), [WIDTH / 2, HEIGHT / 2],[320,240])
back_sound.pause()
if game_success:
canvas.draw_image(win_image,win_info.get_center(),win_info.get_size(), [WIDTH / 2, HEIGHT / 2],[320,240])
back_sound.pause()
# 处理鼠标点击事件的函数
def mouse_handler(pos):
global soldier
if not game_over and not game_success:
angle = math.atan2((pos[1] -soldier.get_pos()[1]) , (pos[0] -soldier.get_pos()[0]))
soldier.set_angle(angle)
soldier.set_shooting(True)
soldier.shoot()
# 处理键盘按下事件的函数
def key_down(key):
global soldier
if key == gui.KEY_MAP["w"]: # 向上
soldier.set_vel([0,-10])
elif key == gui.KEY_MAP["a"]: # 向左
soldier.set_vel([-10,0])
elif key == gui.KEY_MAP["d"]: # 向右
soldier.set_vel([10,0])
elif key == gui.KEY_MAP["s"]: # 向下
soldier.set_vel([0,10])
# 处理键盘释放事件
def key_up(key):
global soldier
soldier.set_vel([0,0])
# 用来产生敌人的时间事件处理函数
def enemy_spawner():
global enemy_group
if not game_over and not game_success:
random_pos = [WIDTH,abs(random.randrange(HEIGHT) - 80) + 40]
random_vel = [-(1.0 + random.random()*0.8),0]
random_ang = 0
a_enemy = Sprite(random_pos, random_vel, random_ang, enemy_image, enemy_info)
enemy_group.add(a_enemy)
# 创建窗口
frame = gui.create_frame("守卫家园", WIDTH, HEIGHT)
# 添加按钮
frame.add_button("重新开始", init, 50)
# 添加标签
label_killed = frame.add_label("消灭敌人 = 0")
label_escaped = frame.add_label("逃脱敌人 = 0")
label_attacked = frame.add_label("受到袭击 = 0")
# 注册事件处理函数
frame.set_mouseclick_handler(mouse_handler)
frame.set_keydown_handler(key_down)
frame.set_keyup_handler(key_up)
frame.set_draw_handler(draw)
# 创建定时器
timer = gui.create_timer(1000.0, enemy_spawner)
# 启动游戏
init()
timer.start()
frame.start()