新手求助,关于外星人入侵项目的三个问题

雪地猢狲 2020-05-03 08:05:21
外星人入侵项目的学习来到了添加play按钮这一部分,但是游戏运行中遇到以下三个问题:
1.关于子弹和外星人碰撞的代码是这个
pygame.sprite.groupcollide(bullets,aliens,True,True)
两个布尔值都是Ture,那子弹击中外星人之后应该会一起消失才对,但是子弹一直穿透,到达屏幕顶端才消失。
2.就像视频这样,发射出来的子弹跟外星人贴图碰撞之后外星人没有消失,感觉碰撞监测不太稳定,有时碰撞之后外星人会消失,很多时候则不会。
3.就像视频这样,外星人碰到边缘之后会正常改变方向下移一点然后平移,但是好几次外星人群都莫名其妙的垂直下移,直接导致结束,这个我实在搞不明白。
论坛貌似传不了视频,我放到微云里,三个问题在视频里都有体现
链接:https://share.weiyun.com/5aVDzjW

有嫌疑的代码如下:
alien.py

#创建一个关于外星人的模块
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):

'''表示单个外星人的类'''
def __init__(self,ai_settings,screen):
#继承精灵类
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
#返回外星人图像并矩形化
self.image = pygame.image.load('image/humor.png')
self.rect = self.image.get_rect()
#每个外星人最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
#储存外星人的准确位置
self.x = float(self.rect.x)
self.y = float(self.rect.y)

def blitme(self):
'''在指定位置绘制外星人'''
self.screen.blit(self.image,self.rect)

def update(self):
#外星人坐标为速度乘以方向值,当方向值为负时方向改变
self.x += (self.ai_settings.alien_speed_factor *
self.ai_settings.fleet_direction)
self.rect.x = self.x
'''当方向值为1时,x 坐标增加,向右移动。方向值为-1时,x 坐标减少,向左移动'''
def check_edges(self):
#检查外星人是否碰到了边缘
#矩形化屏幕
screen_rect = self.screen.get_rect()
#当外星人贴图右边缘大于或等于屏幕矩形右边缘,返回正确
if self.rect.right >= screen_rect.right:
return True
#当外星人贴图左边缘小于或等于屏幕矩形左边缘(小于等于0),返回正确
elif self.rect.left <= screen_rect.left:
return True


bullet.py

from pygame.sprite import Sprite
class Bullet(Sprite):
'''一个对飞船发射的子弹进行管理的类'''
def __init__(self,ai_settings,screen,ship):
#通过函数super()来继承sprite
super().__init__()
self.screen = screen
#在(0,0)处创建一个代表子弹的矩形,再设置正确的位置,参数为初识坐标,子弹的宽和高
self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
#根据飞船位置来确定子弹位置
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
#储存用小数表示的子弹位置
'''由于子弹是直线向下移动,所以我们只考虑在y轴上坐标的变化,
而x轴的坐标是固定的,这由发射子弹时飞船的x轴坐标决定,
因为我们在前面定义了self.rect.centerx = ship.rect.centerx'''
self.y = float(self.rect.y)
#储存子弹颜色
self.color = ai_settings.bullet_bg_color
#储存速度
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
#让子弹向上移动
self.y -= self.speed_factor
#更新子弹rect的位置
self.rect.y = self.y
def draw_bullet(self):
#在屏幕上绘制子弹
pygame.draw.rect(self.screen,self.color,self.rect)


ship.py

import pygame
class Ship:
def __init__(self,ai_settings,screen):
'''初始化飞船并设置其初始位置'''
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图像,并获取其外接矩形
#load返回贴图所在文件
self.image = pygame.image.load('image/timg.PNG')
#矩形属性rect为贴图的矩形对象
#get_rect()是一个处理矩形图像的方法,返回值包含矩形的居中属性( center centerx centery )
#get_rect须加上(),否则后续程序在运行时会出现无法引用centerx和bottom的错误
self.rect = self.image.get_rect()
#先将表示屏幕的矩形储存在属性screen—rect中
self.screen_rect = screen.get_rect()
'''将每艘新飞船放在屏幕底部中央'''
#再将self.rect.centerx设置为表示屏幕的矩形属性centerx
#再将self.rect.bottom设置为表示屏幕的矩形属性bottom
#后面使用这个rect属性来放置飞船在屏幕底部中间
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
#在飞船属性center中储存小数点
self.center = float(self.rect.centerx)
#添加属性,设置一个飞船向右移动的标志
self.moving_right = False
#添加一个飞船向左移动的标志
self.moving_left = False
def blitme(self):
#方法blit 位块传输 将指定的像素内容传输到指定位置
self.screen.blit(self.image,self.rect)
def update(self):
#根据标志来向右移动飞船
#更新飞船的center值而不是rect(rect已被浮点化储存到center中)
'''添加条件,防止飞船移动到屏幕外'''
#以屏幕矩形的右边界为界,当按键事件(标志正确)以及飞船外接矩形坐标小于右边界时可向右移动
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
#根据标志向左移动飞船
#以屏幕矩形的左边界为准,即x轴坐标的0,当按键事件(标志正确)以及飞船外接矩形坐标大于0时可向左移动
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
'''此处使用两个if来应对左右方向按键,两个条件同时检测,当同时按下左右键时,飞船纹丝不动,
这有利于精准控制,如使用if—elif格式的话,if优先,故右键优先,同时按两个键时无法同时抵消,则向右移动'''
#根据center来更新rect
self.rect.centerx = self.center

def center_ship(self):
#让飞船底部居中
self.center = self.screen_rect.centerx


settings.py
#创建一个游戏设置的类
class Settings:
def __init__(self):
#储存游戏初始化数据
#初始化游戏的静态设置
self.screen_width = 1400
self.screen_height = 750
self.bg_color = (200,200,200)
#设置飞船数量
self.ship_limit = 3
#创建关于子弹的属性
self.bullet_width = 500
self.bullet_height = 15
self.bullet_bg_color = (60,0,0)
#设置限制子弹数量
self.bullets_allowed = 3
#设置外星人下降值
self.alien_drop_factor = 2
#设置速度提升倍数
self.speedup_scale = 1.1
#初始化速度值
self.initialize_dynamic_settings()

def initialize_dynamic_settings(self):
#初始化动态设置
# 设置外星人移动速度
self.alien_speed_factor = 0.5
# 设置外星人群移动值,向右为1,向左为-1
self.fleet_direction = 1
#设置子弹移动速度
self.bullet_speed_factor = 5
# 设置飞船移动速度
self.ship_speed_factor = 3

def increase_speed(self):
#提升速度值
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor*= self.speedup_scale


game_functions.py

#创建一个游戏设置的类
class Settings:
def __init__(self):
#储存游戏初始化数据
#初始化游戏的静态设置
self.screen_width = 1400
self.screen_height = 750
self.bg_color = (200,200,200)
#设置飞船数量
self.ship_limit = 3
#创建关于子弹的属性
self.bullet_width = 500
self.bullet_height = 15
self.bullet_bg_color = (60,0,0)
#设置限制子弹数量
self.bullets_allowed = 3
#设置外星人下降值
self.alien_drop_factor = 2
#设置速度提升倍数
self.speedup_scale = 1.1
#初始化速度值
self.initialize_dynamic_settings()

def initialize_dynamic_settings(self):
#初始化动态设置
# 设置外星人移动速度
self.alien_speed_factor = 0.5
# 设置外星人群移动值,向右为1,向左为-1
self.fleet_direction = 1
#设置子弹移动速度
self.bullet_speed_factor = 5
# 设置飞船移动速度
self.ship_speed_factor = 3

def increase_speed(self):
#提升速度值
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor*= self.speedup_scale


alien_invasion.py

#模块sys可用于退出游戏,因为模块game_functions中已经导入sys,主程序中不需要再导入
import pygame
from settings import Settings
from ship import Ship
#导入信息统计类
from game_stats import GameStats
#导入编组
from pygame.sprite import Group
#由于不在主程序创建外星人实例,此处不必导入
#导入game_functions,后面的事件管理部分从模块导入
import game_functions as gf
#导入按钮类
from button import Button
def run_game():
#初始化游戏并创建一个屏幕
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
#设置游戏屏幕为设置类中的数据
#设置屏幕对象
pygame.display.set_caption("alien_invision")
#创建按钮类 形参msg对应的实参为“play”
play_button = Button(ai_settings,screen,"Play")
#创建一个用于储存游戏信息统计的实例
stats = GameStats(ai_settings)
#创建一艘飞船
ship = Ship(ai_settings,screen)
#创建一个子弹编组
bullets = Group()
#创建一个外星人编组
aliens = Group()
# 使用gf模块中的函数绘制外星人群
gf.create_fleet(ai_settings,screen,ship,aliens)
#开始游戏主循环
while True:
#使用模块game_funcations中的方法
#check_events检测按键和鼠标点击事件
gf.check_events(ai_settings,ship,screen,bullets,stats,play_button,aliens)
#当标志正确时运行游戏:
if stats.game_active :
#方法update()用于确定事件标志以及移动距离和方向
ship.update()
#使用更新后的gf的函数用于更新和删除子弹
#检测外星人与子弹的碰撞,删除外星人与子弹 并创建外星人群
gf.update_bullets(bullets,aliens,ai_settings,screen,ship)
#由于外星人会被子弹击中,所以在绘制子弹之后绘制外星人
#增加实参 stats,bullets,screen
gf.update_aliens(ai_settings,ship,aliens,stats,bullets,screen)
#方法update_screen用于更新绘制屏幕各元素
gf.update_screen(ai_settings,ship,screen,aliens,bullets,stats,play_button)
#运行游戏
run_game()


一直没搞出个所以然来,只好来求助一波
...全文
596 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
weixin_45903952 2020-05-04
  • 打赏
  • 举报
回复
--snip是省略了一部分内容,不等于没有
雪地猢狲 2020-05-04
  • 打赏
  • 举报
回复
引用 7 楼 weixin_45903952的回复:
我看你以前的代码,那个好像只是检查碰撞的,
我不理解的地方是:def update_bullets(aliens, bullets): """更新子弹的位置,并删除已消失的子弹""" --snip- # 检查是否有子弹击中了外星人 # 如果是这样,就删除相应的子弹和外星人 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) 这是书上的代码,按书的意思,两个布尔值Ture就可以实现同归于尽的效果了,但是到我这里就不太行,貌似三个问题都跟这里有关系
weixin_45903952 2020-05-04
  • 打赏
  • 举报
回复
我看你以前的代码,那个好像只是检查碰撞的,
雪地猢狲 2020-05-04
  • 打赏
  • 举报
回复
啊哈,问题已解决
学习之路上还是不能太粗心啊
雪地猢狲 2020-05-03
  • 打赏
  • 举报
回复
引用 5 楼 weixin_45903952的回复:
[quote=引用 3 楼 雪地猢狲 的回复:] [quote=引用 1 楼 weixin_45903952的回复:]那子弹击中外星人之后应该会一起消失才对,但是子弹一直穿透,到达屏幕顶端才消失。 那是你在子弹,即昨天写的fires里没有remove那个碰撞的子弹
这不是昨天那个了,是另一个项目。碰撞代码pygame.sprite.groupcollide(bullets,aliens,True,True) 这个不是collidedeny那个,应该不需要再添加移除的代码了吧[/quote] 一样要移除,要不就会穿过屏幕一直到消失[/quote] 穿过屏幕之后移除子弹的代码有的。 不过书上面是这样: def update_bullets(aliens, bullets): """更新子弹的位置,并删除已消失的子弹""" --snip- # 检查是否有子弹击中了外星人 # 如果是这样,就删除相应的子弹和外星人 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) 一行代码就可以实现子弹和外星人同归于尽的啊,为什么到我这里出问题了
weixin_45903952 2020-05-03
  • 打赏
  • 举报
回复
引用 3 楼 雪地猢狲 的回复:
[quote=引用 1 楼 weixin_45903952的回复:]那子弹击中外星人之后应该会一起消失才对,但是子弹一直穿透,到达屏幕顶端才消失。 那是你在子弹,即昨天写的fires里没有remove那个碰撞的子弹
这不是昨天那个了,是另一个项目。碰撞代码pygame.sprite.groupcollide(bullets,aliens,True,True) 这个不是collidedeny那个,应该不需要再添加移除的代码了吧[/quote] 一样要移除,要不就会穿过屏幕一直到消失
雪地猢狲 2020-05-03
  • 打赏
  • 举报
回复
引用 2 楼 weixin_45903952的回复:
视频的链接挂了,看不到
https://share.weiyun.com/5aVDzjW 链接在此,居然会挂掉
雪地猢狲 2020-05-03
  • 打赏
  • 举报
回复
引用 1 楼 weixin_45903952的回复:
那子弹击中外星人之后应该会一起消失才对,但是子弹一直穿透,到达屏幕顶端才消失。 那是你在子弹,即昨天写的fires里没有remove那个碰撞的子弹
这不是昨天那个了,是另一个项目。碰撞代码pygame.sprite.groupcollide(bullets,aliens,True,True) 这个不是collidedeny那个,应该不需要再添加移除的代码了吧
weixin_45903952 2020-05-03
  • 打赏
  • 举报
回复
视频的链接挂了,看不到
weixin_45903952 2020-05-03
  • 打赏
  • 举报
回复
那子弹击中外星人之后应该会一起消失才对,但是子弹一直穿透,到达屏幕顶端才消失。 那是你在子弹,即昨天写的fires里没有remove那个碰撞的子弹

37,742

社区成员

发帖
与我相关
我的任务
社区描述
JavaScript,VBScript,AngleScript,ActionScript,Shell,Perl,Ruby,Lua,Tcl,Scala,MaxScript 等脚本语言交流。
社区管理员
  • 脚本语言(Perl/Python)社区
  • WuKongSecurity@BOB
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧