pygame教你从0到1一步步实现点到点的智能追踪系统(其一)

Posted dhjabc_1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pygame教你从0到1一步步实现点到点的智能追踪系统(其一)相关的知识,希望对你有一定的参考价值。

pygame库越来越有趣了。

一直在思考如何构建一个目标追踪和定位的功能,今天终于落笔开始写成博客。下面是我的一些思考:

归根到最简单的功能,就是首先有一个初始的点,然后有一个目标点,然后通过时间片,结合算法计算出新的位置,不断更新初始的点,最后到达目标点的一个过程。

当然,真实的环境比这个复杂多了,譬如:

1、不能简单的把初始点和目标点,可能是2D的图形,或者3D的图形。 2、别的环境因素的影响等等。

作为技术上的考虑,我觉得开始不要想得太复杂,先实现了功能先。整体目录如下:

一、需要的数学知识

这里借用一下博主@GZR专家
的文章一个简单的导弹自动追踪以及实时图片旋转算法,Python-pygame代码实现(https://blog.csdn.net/guozirui12/article/details/86997123?utm_source=app)里面的数学知识和图,在此表示感谢!

(一)数学思路

在这里插入图片描述
根据上图,把时间t分割成足够小的片段(比如1/1000,这个时间片越小越精确),每一个片段分别构造如上三角形,计算出导弹下一个时间片走的方向(即∠a)和走的路程(即vt=|AC|),这时候目标再在第二个时间片移动了位置,这时刚才计算的C点又变成了第二个时间片的初始点,这时再在第二个时间片上在C点和新的目标点构造三角形计算新的vt,然后进入第三个时间片,如此反复即可。

(二)计算距离

假定导弹和目标的初始状态下坐标分别是(x1,y1),(x,y),构造出直角三角形ABE,这个三角形用来求∠a的正弦和余弦值,因为vt是自己设置的,我们需要计算A到C点x和y坐标分别移动了多少,移动的值就是AD和CD的长度,这两个分别用vt乘cosa和sina即可。
在这里插入图片描述

(三)计算X\\Y的值

在这里插入图片描述
AC的长度就是导弹的速度乘以时间即 |AC|=vt,然后即可计算出AD和CD的长度,于是这一个时间片过去后,导弹应该出现在新的位置C点,他的坐标就是老的点A的x增加AD和y减去CD。

于是,新的C点坐标就是:
在这里插入图片描述

二、一个点到点的案例

(一)对应的参数设置

x1,y1=100,600           #导弹的初始发射位置
x,y =500,200            #目标位置
velocity=0.3            #导弹速度

(二)循环更新追踪点位置

clock=pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    clock.tick(300)
    distance=sqrt(pow(x1-x,2)+pow(y1-y,2))      #两点距离公式
    section=velocity               #每个时间片需要移动的距离
    sina=(y1-y)/distance
    cosa=(x-x1)/distance
    angle=atan2(y-y1,x-x1)              #两点线段的弧度值
    x1,y1=(x1+section*cosa,y1-section*sina)

(三)绘制追踪点和目标点

pygame.draw.circle(screen, (255, 0, 0), (int(x1), int(y1)), 10)
pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)

(四)完整的效果演示

在这里插入图片描述

代码如下:

import pygame,sys
from math import *
pygame.init()
screen=pygame.display.set_mode((800,700))
x1,y1=100,600           #导弹的初始发射位置
x,y =500,200            #目标位置
velocity=0.3            #导弹速度
clock=pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    clock.tick(300)
    distance=sqrt(pow(x1-x,2)+pow(y1-y,2))      #两点距离公式
    section=velocity               #每个时间片需要移动的距离
    sina=(y1-y)/distance
    cosa=(x-x1)/distance
    angle=atan2(y-y1,x-x1)              #两点线段的弧度值
    x1,y1=(x1+section*cosa,y1-section*sina)
    pygame.draw.circle(screen, (255, 0, 0), (int(x1), int(y1)), 10)
    pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)
    pygame.display.update()

(五)让目标点随着鼠标运动起来

增加对鼠标位置的记录,核心代码如下:

x, y = pygame.mouse.get_pos()  # 获取鼠标位置,鼠标就是需要打击的目标

完整的代码如下:

import pygame,sys
from math import *
pygame.init()
screen=pygame.display.set_mode((800,700))
x1,y1=100,600           #导弹的初始发射位置
x,y =500,200            #目标位置
velocity=0.8            #导弹速度
clock=pygame.time.Clock()
while True:
    x, y = pygame.mouse.get_pos()  # 获取鼠标位置,鼠标就是需要打击的目标
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    clock.tick(300)
    distance=sqrt(pow(x1-x,2)+pow(y1-y,2))      #两点距离公式
    section=velocity               #每个时间片需要移动的距离
    sina=(y1-y)/distance
    cosa=(x-x1)/distance
    angle=atan2(y-y1,x-x1)              #两点线段的弧度值
    x1,y1=(x1+section*cosa,y1-section*sina)
    screen.fill((0,0,0))
    pygame.draw.circle(screen, (255, 0, 0), (int(x1), int(y1)), 10)
    pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)
    pygame.display.update()

运行效果如下:
在这里插入图片描述

(六)让追踪点拖着尾巴跑起来

通过增加list对象记录历史出现的所有的点的位置,然后绘制,核心代码如下:

steps = []
steps.append((int(x1), int(y1)))
for step in steps:
    pygame.draw.circle(screen, (255, 0, 0), step, 10)
pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)

完整代码如下:

import pygame,sys
from math import *
pygame.init()
screen=pygame.display.set_mode((800,700))
x1,y1=100,600           #导弹的初始发射位置
x,y =500,200            #目标位置
velocity=0.8            #导弹速度
clock=pygame.time.Clock()
steps = []
while True:
    x, y = pygame.mouse.get_pos()  # 获取鼠标位置,鼠标就是需要打击的目标
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    clock.tick(300)
    distance=sqrt(pow(x1-x,2)+pow(y1-y,2))      #两点距离公式
    section=velocity               #每个时间片需要移动的距离
    sina=(y1-y)/distance
    cosa=(x-x1)/distance
    angle=atan2(y-y1,x-x1)              #两点线段的弧度值
    x1,y1=(x1+section*cosa,y1-section*sina)
    screen.fill((0, 0, 0))
    steps.append((int(x1), int(y1)))
    for step in steps:
        pygame.draw.circle(screen, (255, 0, 0), step, 10)
    pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)
    pygame.display.update()

运行效果如下:
在这里插入图片描述
一个超级简单的点到点的目标追踪功能就开发好了。你是更喜欢拖着尾巴的追踪,还是喜欢不拖尾巴的追踪呢?

三、更复杂点的点到点案例

我们让目标点动起来,类似运动的小球一样,而且让小球更随机,即小球的运动速度、初始位置(x,y),小球的颜色、小球的半径等都是随机的。

(一)新建Ball类

通过Ball类实现运动的小球,具体的类代码如下:

from random import randint
import pygame

class Ball:

    def __init__(self, width,height,screen):
        self.scrnwidth = width
        self.scrnheight = height
        self.screen = screen
        self.reset()
        self.color = (randint(0,255),randint(0,255),randint(0,255))

    def draw_ball(self):
        pygame.draw.circle(self.screen, self.color, (self.xpos, self.ypos), self.radius)

    def reset(self):
        self.radius = randint(2, 10)
        self.xpos = randint(self.radius, int(self.scrnwidth)-self.radius)
        self.ypos = randint(self.radius, int(self.scrnheight)-self.radius)
        self.xvelocity = randint(1, 2)
        self.yvelocity = randint(1, 2)
        self.color = (randint(0,255),randint(0,255),randint(0,255))

    def move(self):
        # 进行相应的移动,如果坐标超过屏幕边缘则向相反方向移动
        # 让球的x坐标和y坐标,按照向量的大小进行增加,表示球的运行,向下和向右

        self.xpos += self.xvelocity
        self.ypos += self.yvelocity

        # 如果球的y坐标大于等于屏幕高度和球的半径的差,则调整球的运行y轴方向朝上
        if self.ypos >= self.scrnheight - self.radius:
            self.yvelocity = -self.yvelocity

        # 如果球的y坐标小于等于屏幕高度和球的半径的差,则调整球的y轴运行方向朝下
        if self.ypos <= self.radius:
            self.yvelocity = abs(self.yvelocity)

        # 如果球的x坐标大于等于屏幕宽度和球的半径差,则调整球的运行x轴方向朝左
        if self.xpos >= self.scrnwidth - self.radius:
            self.xvelocity = -self.xvelocity

        # 如果球的x坐标小于等于屏幕宽度和球半径的差,则调整球的运行x轴方向朝右
        if self.xpos <= self.radius:
            self.xvelocity = abs(self.xvelocity)

(二)初始化Ball对象并运动绘制

在主文件里面引入Ball文件,并初始化Ball对象。

from Ball import Ball
myball = Ball(800,700,screen)

在循环过程中更新Ball的位置,并画出Ball的surface信息。

myball.move()
myball.draw_ball()

(三)完整的代码

import pygame,sys
from math import *
from Ball import Ball

pygame.init()
screen=pygame.display.set_mode((800,700))
x1,y1=100,600           #导弹的初始发射位置
x,y =500,200            #目标位置
velocity=1.1            #导弹速度
clock=pygame.time.Clock()
steps = []
myball = Ball(800,700,screen)
while True:
    myball.move()
    x, y = myball.xpos,myball.ypos # 获取运动小球的位置
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
            sys.exit()
    clock.tick(300)
    distance=sqrt(pow(x1-x,2)+pow(y1-y,2))      #两点距离公式
    section=velocity               #每个时间片需要移动的距离
    sina=(y1-y)/distance
    cosa=(x-x1)/distance
    angle=atan2(y-y1,x-x1)              #两点线段的弧度值
    x1,y1=(x1+section*cosa,y1-section*sina)
    screen.fill((0, 0, 0))
    steps.append((int(x1), int(y1)))
    for step in steps:
        pygame.draw.circle(screen, (255, 0, 0), step, 10)
    myball.draw_ball()
    # pygame.draw.circle(screen, (0, 0, 255), (x,y), 10)
    pygame.display.update()

(四)运行效果如下:

在这里插入图片描述
这个是点到点的智能追踪系统的最简单的版本,后面将增加图片的运行效果,并增加其他更有趣的功能,欢迎持续关注啊。

感谢各位的支持,比心。

参考文档:
https://blog.csdn.net/guozirui12/article/details/86997123?utm_source=app

以上是关于pygame教你从0到1一步步实现点到点的智能追踪系统(其一)的主要内容,如果未能解决你的问题,请参考以下文章

pygame教你从0到1一步步实现点到点的智能追踪系统(其一)

LFS7.7一步步教你从 〇 开始撸个 Linux 系统 | 文末送书

李飞飞高徒教你从0到1构建GPT,马斯克点赞

干货! 一步步教你从Oracle 11gR2 RAC 升级至18c

神级程序员教你用Python实现简单的导弹自动追踪!此乃装逼神技!

感知机:教你用Python一步步实现