星际争霸之小霸王之小蜜蜂(七)--消失的子弹

简介: 星际争霸之小霸王之小蜜蜂(七)--消失的子弹

前言

昨天我们已经让子弹飞了起来,但是会面临一个和之前小蜜蜂一样的问题,小蜜蜂的行动应该限制在窗口内,那么子弹也是有相同之处,也需要限制一个移动范围,当超出范围之后,就要将其消灭,释放内存,因为子弹飞出屏幕外不是真的消失,只是不显示而已,依然占用内存空间。

一、删除子弹

按照上面的说法,我们只需要判断子弹的位置,如果子弹已经超出窗口就可以删除。这个判断放在哪里合适呢,个人觉得放在刷新窗口前比较合适,在显示窗口内容前判断是否需要删除后,就不用浪费资源了。这样,我们来修改主函数:

import pygame
import settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
    pygame.init()
    new_setting=settings.Settings()
    screen = pygame.display.set_mode((new_setting.screen_width,new_setting.screen_height))
    ship = Ship(screen,new_setting)
    pygame.display.set_caption("狂敲代码的橘子")
    bullets = Group()
    while True:
        gf.check_events(new_setting,screen,ship,bullets)
        ship.update()
        bullets.update()
        for bullet in bullets:
            if bullet.rect.bottom<=0:
                bullets.remove(bullet)
        print(len(bullets))
        gf.update_screen(new_setting,screen,ship,bullets)
run_game()

我们再确定了每个子弹的位置后,添加循环判断代码,之前我们说过,窗口的左上角坐标是(0.0),所以只要子弹的最下边小于0就可以判断该子弹已经出了窗口,因为在游戏的显示中通过肉眼是无法判断子弹飞出窗口后有没有删除,所以增加了 print(len(bullets))来测试,当子弹删除后,bullets的长度会减少,直至为0,经运行,确实达到了想要的目的。


这里还有一个问题,我们写的for循环是for bullet in bullets:,但是“大蟒蛇”上写的是for bullet in bullets.copy():,这两者有什么区别呢?当我们在遍历一个列表的同时对其进行修改(如添加、删除元素),可能会导致程序出错或产生意外的结果。这是因为在遍历过程中,Python会不断地更新列表的长度和元素的索引,从而可能导致索引错误或遗漏某些元素。


而使用bullets.copy()创建了一个副本,遍历的是这个副本,对原列表的修改不会影响到副本,从而避免了上述问题。虽然两种写法都能实现我们想要的目的,但是明显第二种更加严谨、稳妥,第一种也许不知道什么时候就会发生错误。


二、限制子弹数量

“大蟒蛇”中认为一般的游戏子弹都有限制,我不记得我玩的游戏子弹有限制,好像都是无限子弹,最多对子弹的发射速度有限制,我们还是按照书上来实践操作。这个功能应该不难实现,只要在创建子弹之前加一个判断,如果存在的子弹小于限制数,就创建一个子弹,并添加到bullets中,如果不是就不做任何操作,这个判断语句代码写在game_functions模块中,但在这之前,要先在settings模块设置一下最大子弹数量属性。

class Settings():
    def __init__(self):
        self.screen_width = 800
        self.screen_height = 600
        self.bg_color = (220,220,220)
        self.ship_speed_factor = 0.1
        self.bullet_speed_factor = 0.3
        self.bullet_width = 2
        self.bullet_hight = 5
        self.bullet_color = 60,60,60
        self.bullets_allowed = 3
import sys
import pygame
from bullet import Bullet
def check_keydown_events(event,new_setting,screen,ship,bullets):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        if len(bullets)<new_setting.bullets_allowed:
            new_bullet = Bullet(new_setting,screen,ship)
            bullets.add(new_bullet)
def check_keyup_events(event,ship):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    if event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(new_setting,screen,ship,bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type==pygame.KEYDOWN:
            check_keydown_events(event,new_setting,screen,ship,bullets)
        elif event.type==pygame.KEYUP:
            check_keyup_events(event, ship)
def update_screen(new_setting,screen,ship,bullets):
    screen.fill(new_setting.bg_color)
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
pygame.display.flip()

通过修改这两处代码,每次屏幕上最多只有3发子弹

可以看出,我一直在敲击空格键,但是窗口内最多只有3发子弹。

三、继续重构代码

现在“大蟒蛇”又觉得主程序内容有点多了,决定将判断删除子弹代码转移到game_functions中,并创建函数update_bullets,这样主函数只要调用update_bullets就行了,update_bullets里代码就是照搬过来的,没什么好说的。因为我们在判断按键是否为空格里又加了判断子弹数量,因此我还需单独写一个函数fire_bullet()来存放判断子弹数量代码,需要时直接调用,使代码块看起来更简洁。

import sys
import pygame
from bullet import Bullet
def check_keydown_events(event,new_setting,screen,ship,bullets):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(new_setting, screen, ship, bullets)
def check_keyup_events(event,ship):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    if event.key == pygame.K_LEFT:
        ship.moving_left = False
def check_events(new_setting,screen,ship,bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type==pygame.KEYDOWN:
            check_keydown_events(event,new_setting,screen,ship,bullets)
        elif event.type==pygame.KEYUP:
            check_keyup_events(event, ship)
def fire_bullet(new_setting,screen,ship,bullets):
    if len(bullets) < new_setting.bullets_allowed:
        new_bullet = Bullet(new_setting, screen, ship)
        bullets.add(new_bullet)
def update_bullets(bullets):
    bullets.update()
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
def update_screen(new_setting,screen,ship,bullets):
    screen.fill(new_setting.bg_color)
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    pygame.display.flip()

总结

截至目前,玩家操作部分基本完成,后面我将添加敌对的虫族,以及用子弹消灭他们。

相关文章
|
11月前
|
SQL 监控 关系型数据库
SQL语句当前及历史信息查询-performance schema的使用
本文介绍了如何使用MySQL的Performance Schema来获取SQL语句的当前和历史执行信息。Performance Schema默认在MySQL 8.0中启用,可以通过查询相关表来获取详细的SQL执行信息,包括当前执行的SQL、历史执行记录和统计汇总信息,从而快速定位和解决性能瓶颈。
561 1
|
11月前
|
机器学习/深度学习 算法 数据挖掘
提高时钟置换算法的性能
【10月更文挑战第25天】通过上述一种或多种方法的综合应用,可以在不同程度上提高时钟置换算法的性能,使其更好地适应各种复杂的系统环境和应用场景,提高虚拟内存管理的效率和系统的整体性能。
259 62
|
11月前
|
移动开发 自然语言处理 JavaScript
虚拟 DOM 如何保证跨平台的兼容性?
【10月更文挑战第25天】虚拟 DOM 通过其抽象的表示、渲染器的解耦以及针对不同平台的特定渲染器实现、事件系统适配、样式处理兼容性和统一的数据绑定与状态管理等多方面的设计和机制,有效地保证了跨平台的兼容性,使得开发者能够使用一套代码在多种平台上构建具有一致体验和高性能的应用。
|
11月前
|
数据采集 机器人 计算机视觉
一手训练,多手应用:国防科大提出灵巧手抓取策略迁移新方案
【10月更文挑战第24天】国防科技大学研究人员提出了一种新颖的机器人抓取方法,通过学习统一的策略模型,实现不同灵巧夹具之间的策略迁移。该方法分为两个阶段:与夹具无关的策略模型预测关键点位移,与夹具相关的适配模型将位移转换为关节调整。实验结果显示,该方法在抓取成功率、稳定性和速度方面显著优于基线方法。论文地址:https://arxiv.org/abs/2404.09150
155 1
|
Ubuntu Linux 网络安全
准备搞OpenStack了,先装一台最新的Ubuntu 23.10
准备搞OpenStack了,先装一台最新的Ubuntu 23.10
|
SQL 关系型数据库 MySQL
MySQL中一定要遵守的12个SQL规范
本文档提供了12条SQL编写和数据库管理的最佳实践建议,旨在帮助开发者提高SQL查询效率、增强数据库安全性及可维护性。
387 1
|
网络协议 安全 数据安全/隐私保护
|
存储 编解码 Shell
|
云安全 存储 运维
首次全面解析云原生成熟度模型:解决企业「诊断难、规划难、选型难」问题
从“上云”到“云上”原生,云原生提供了最优用云路径,云原生的技术价值已被广泛认可。当前行业用户全面转型云原生已是大势所趋,用户侧云原生平台建设和应用云原生化改造进程正在加速。
2671 110
首次全面解析云原生成熟度模型:解决企业「诊断难、规划难、选型难」问题
|
Java API Android开发
Sui为根应用提供Java APIs,滴API。主要提供直接使用Android APIs的能力(几乎以Java作为root的身份
Sui为根应用提供Java APIs,滴API。主要提供直接使用Android APIs的能力(几乎以Java作为root的身份,在root下启动app自己的AIDL风格的Java服务。这将使root应用程序开发变得更加容易。
328 0