pygame里实现导弹追踪效果,同时对python的指针机制有一点点思考

news2024/10/1 23:39:37

       最近,儿子一直缠着让我把之前给他编写的游戏重做一下,要加一些功能.但是因为之前写代码的时候刚学会python,当时的想法就是能跑就行,现在回头看来,代码的可维护性几乎为零.所以没办法只能冲头再来,重构了几乎所有代码.在编写的时候遇到了一个有意思的问题,儿子让我给游戏添加一种带追踪能力的导弹.导弹不仅要能追踪目标不断修正轨迹向着目标前进,同时导弹的弹头要一直朝向目标,我一听,这不就是弹道导弹嘛,有意思,整!

        当时我想,这还不简单,在追踪的时候顺手把本体和目标之间连线的斜率计算出来不久完了吗?于是说干就干,但是当我到了真正编写的时候还是发现了一些问题.今天就来和大家分享一下.

        首先呢,路径追踪很简单,我之前写过一篇相关的文章可以参考这个http://t.csdnimg.cn/soVGy,所以路径这里咱们就跳过.

        这篇文章主要就聊聊如何实现导弹通过旋转始终指向目标.

先来看一张示意图

如图,当A点向B移动时是沿着AB移动,所以只要计算出AB的斜率时就会得到第一个旋转角度,当A移动到A`点时追踪目标变为了C,这时算出A`C的斜率就能得到第二个旋转角度,如此循环往复,无论被追踪的目标如何变化,我们只要算出当前目标和本身的斜率就能得出要旋转的角度了.明白了实现旋转的方法以后,我们就开始写代码.这里多说一句,其实一开始我在这里思考了很长时间,主要的问题是我的一个闪念,既然正切函数能够得到斜率,那么正弦余弦甚至正割余割,也应该能到倾斜角度(其实是废话,利用推导公式本来就可以推导出的,但我也不知道为什么非要跟自己较劲,花了一整天时间去复习初中数学),但是,正弦余弦有一个问题,就是要判断象限.我甚至写了一大段"if"函数去判断象限.知道我发现math模块里的atan2()这个方法,我才明白,我之前想多了.这个方法不用考虑象限,只需要输入对边临边的值就会自动判断象限,从而得出当前的弧度.

代码如下:

import math

import pygame,sys
from math import *
pygame.init()
screen=pygame.display.set_mode((800,700),0,32)
pygame.display.set_caption("弹道导弹")
clock = pygame.time.Clock()

class Sprite1(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load('2.png')
        self.rect = self.image.get_rect()

    def update(self, *args, **kwargs):
        self.rect.center = pygame.mouse.get_pos()

class Sprite2(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.mumimage = pygame.image.load('1.png')
        self.image = self.mumimage
        # print(id(self.mumimage), id(self.image))
        self.rect = self.image.get_rect()
        self.speed = 3

    def update(self, target):
        deltax = target.rect.centerx - self.rect.midtop[0]
        deltay = target.rect.centery - self.rect.midtop[1]
        distance = math.sqrt(deltax ** 2 + deltay ** 2)
        if distance != 0:
            angle = math.degrees(math.atan2(-deltay, deltax))
            self.image = pygame.transform.rotate(self.mumimage, angle - 90)
            # print(id(self.mumimage), id(self.image))
            stepx = self.speed * deltax / distance
            stepy = self.speed * deltay / distance
            self.rect.centerx += stepx
            self.rect.centery += stepy




sprite1 = Sprite1()
sprite2 = Sprite2()
sprites = pygame.sprite.Group()
sprites.add(sprite1,sprite2)
while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()

    screen.fill((0,0,0))
    sprites.update(sprite1)
    sprites.draw(screen)
    pygame.draw.rect(screen, (0,255,0), sprite2.rect, 2)


    pygame.display.update()
    clock.tick(60)

运行效果如下

其实写到这里,我要的目的目的其实已经达到了.但是,在写代码的时候我发现一个问题.

可以看到,我在编写sprite2的时候,定义了一个self.mumimage对象,然后又创建了一个self.image对象指向self.mumimage.这样做,主要是因为python的变量赋值其实是将变量指向了对象的内存地址,也就是说python里的变量都是指针变量.

pygame.transform.rotate()这个方法会生成一个新的对象,同时在内存中开辟一个新的地址.

如果我们直接使用self.image = pygame.transform.rotate(self.mumimage, angle - 90),那么就会产生递归,self.image 会不停的迭代self.image会不停的指向新地址而pygame.transform.rotate()方法会使用self.image迭代的新对象.这就产生了无限递归,直至内存泄漏,程序崩溃.下面举个例子.当我们删掉self.mumimage这个变量,直接定义self.image = pygame.image.load('1.png'),那么运行会得到以下结果.

所以,在这里我们必须要先声明一个变量self.mumimage,然后用self.image捕获self.mumimage迭代后的对象.这样才能保证pygame.transformer.rotate()这个方法一直作用与self.mumimage而不会产生无限的递归导致程序崩溃.

最后是文章中用到的素材

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1395297.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pyside6入门教学——编写一个UI界面并显示

1、安装Pyside6 输入下列命令安装Pyside6。 pip install Pyside6 2、设计UI 打开Qt设计工具(在安装Pyside6包的目录下)。 【注】我这用的是anaconda虚拟环境,所以我的路径是D:\App\Anaconda3\envs\snake\Lib\site-packages\PySide6。设计…

【Python学习】Python学习19- 异常处理

目录 【Python学习】Python学习19- 异常处理 前言python标准异常异常处理带异常类型语法不带异常类型语法使用except而带多种异常类型try-finally 语句触发异常 参考 文章所属专区 Python学习 前言 本章节主要说明Python的异常处理。 python标准异常 BaseException 所有异常…

GNU Radio简介及流程图搭建

文章目录 前言一、GNU Radio 是什么?二、GNU Radio 安装三、搭建第一个流程图1、创建 GRC 文件2、添加块3、运行流程图 前言 欢迎来到无线通信的世界,初步接触 GNU Radio,对其学习进行一个记录。 一、GNU Radio 是什么? GNU Rad…

【C语言编程之旅 4】刷题篇-关键字

第一题 解析 C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字 A:错误,关键字是语言自身定义的 B:正确 C:错误,关键字具有特殊含义&#xff…

docker部署项目,/var/lib/docker/overlay2目录满了如何清理?

docker部署项目,/var/lib/docker/overlay2目录满了如何清理? 一、问题二、解决1、查看 /var/lib/docker 目录(1)、containers 目录(2)、volumes 目录(3)、overlay2 目录 2、清理&…

Java开发分析 JProfiler 14 中文

JProfiler 14是一款强大的Java分析工具,专为帮助Java开发者优化应用性能而设计。它提供了实时监控、内存分析、线程分析、CPU分析等多种功能,帮助开发者快速定位和解决性能问题。JProfiler 14具有直观的用户界面,使用户能够轻松上手。此外&am…

苹果Find My可查找添加32件物品,伦茨科技ST17H6x芯片加速产品赋能

苹果最近更新的支持文档证实,从 iOS 16 开始,"Find My"可查找添加物品从16件增加到32件,AirTag 和“查找”网络中的物品利用“查找”网络的强大功能来发挥作用,这个网络由数亿台加密的匿名 Apple 设备构成。“查找”网络…

Kafka-多线程消费及分区设置

目录 一、Kafka是什么?消息系统:Publish/subscribe(发布/订阅者)模式相关术语 二、初步使用1.yml文件配置2.生产者类3.消费者类4.发送消息 三、减少分区数量1.停止业务服务进程2.停止kafka服务进程3.重新启动kafka服务4.重新启动业…

PPT大神带你飞!!!

1、OneKeyTools 官网:http://oktools.xyz/ OneKeyTools是一款免费开源的PowerPoint第三方平面设计辅助插件,功能涵盖了形状、调色、三维、图片处理、辅助功能等等方面。 插件功能: 插件从面世逐步受到广大PPT设计师和爱好者的追捧&#x…

感谢大家的支持,继续耕耘

有什么大家感兴趣的领域,欢迎留言

SSH数据流量监控

简介 检查网络连接的数据传输情况有以下一些实际意义: 安全监控:检查数据传输情况可以帮助你识别异常活动或潜在的安全威胁。如果发现大量不寻常的数据传输活动,可能表示有未经授权的访问或恶意行为。通过监控数据传输,可以及时发…

软件测评中心▏正式验收测试和非正式验收的优缺点简析

软件正式验收测试需要非常严格的管理,是对系统测试的延续,这种验收测试的测试用例应是系统测试的子集。非正式验收测试不像正式验收测试那么严格,不需要执行指定的测试用例,可以由测试人员自主决定,但制定测试用例时必…

node.js(express.js)+mysql实现登录功能

文章目录 前言实现步骤 实现步骤一、检测登录表单的数据是否合法(3)新建schema/user.js(4)在routes/use.js中引入schema/user.js中的方法reg_login_schema,代码如下: 二、根据用户名查询用户的数据三、判断…

浅析Redis①:命令处理核心源码分析(上)

写在前面 Redis作为我们日常工作中最常使用的缓存数据库,其重要性不言而喻,作为普调开发者,我们在日常开发中使用Redis,主要聚焦于Redis的基层数据结构的命令使用,很少会有人对Redis的内部实现机制进行了解&#xff0c…

C++:类与结构体的对比

2024年1月18日 内容来自The Cherno:C系列 -------------------------------------------------------------------------------------------------------------------------------- C中关于class与struct,几乎没有区别,只有一个关于“可见度”的区别…

Go 爬虫之 colly 从入门到不放弃指南

文章目录 概要介绍如何学习官方文档如何安装快速开始如何配置调试分布式代理层面执行层面存储层面存储多收集器配置优化持久化存储启用异步加快任务执行禁止或限制 KeepAlive 连接扩展总结如果想用 GO 实现爬虫能力,该如何做呢?抽时间研究了 Go 的一款爬虫框架 colly。 概要…

【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

文章目录 Element Plus SpringBoot实现图片上传,预览,删除效果展示 1. 后端代码1.1 controller1.2 service 2. 前端代码2.1 路由创建2.2 api接口2.2 文件创建 3. 前端上传组件封装 前言:最近写项目,发现了一些很有意思的功能&…

SD-WAN组网设计原则:灵活、安全、高效

在实现按需、灵活和安全的SD-WAN组网方案中,我们必须遵循一系列关键的设计原则,以确保网络的可靠性和效率。通过以下几点设计原则,SD-WAN能够满足企业对灵活性、安全性和高效性的迫切需求。 灵活的Overlay网络互联 SD-WAN通过IP地址在站点之间…

appium之联动pycharm

前置条件: 1.java环境安装好了 2.android-sdk安装好(uiautomatorviewer 也可以把这个启动起来) 3.appium安装好 4.adb devices查看下设备是否连接 pycharm入门代码--固定写法 from appium import webdriver# 定义字典变量 desired_caps …