【问题标题】:Why won't my Spaceship point toward the planet? [duplicate]为什么我的宇宙飞船不指向地球? [复制]
【发布时间】:2021-01-31 09:53:26
【问题描述】:

Small gif showing problem but I don't have 10 reputation yet (this is only my 2nd question) and thus have to use link

我有一个简单的测试程序,其中有一艘宇宙飞船,它本应指向一颗行星,但它却指向了奇怪的方向。

该程序的目的是测试我的测试程序是否可以得到从飞船到行星的角度,因此另一种方法不起作用,因为我需要角度来确定在哪个方向上应用“重力” (这就是这个测试的目的)。

这也是脚本重复多次但仅以图形方式显示最终角度的原因。

我的程序使用从 SO 问题 Calculate angle (clockwise) between two points 获得的代码

“Chris St Pierre”的回答只是给了我一个错误,试图将浮点数除以零 (?)。

“ali_m”的回答给了我一个类似这样的问题。

我正在使用“Colin Basnett”的答案,这对我也不起作用,但这是我迄今为止最喜欢的方法,因为它不需要插件(而且因为它很短而且不只是直接 -向我抛出一个错误)。

我把它改编成下面的函数:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def get_angle_between(x0,y0,x1,y1): 
    v1 = Vector(x0, y0)
    v2 = Vector(x1, y1)
    
    v1_theta = math.atan2(v1.y, v1.x)
    v2_theta = math.atan2(v2.y, v2.x)
    
    r = (v2_theta - v1_theta) * (180.0 / math.pi)
    
    return r

这个脚本在 Spaceship sprite 的“move”函数中调用它:

if gravityJsonQ:
            for item in planets:
                centreOfGravityX = planets[item]["x"] + (planets[item]["s"] / 2)
                centreOfGravityY = planets[item]["y"] + (planets[item]["s"] / 2)
                centreOfGravityGravity = float(planets[item]["g"])
                pendingUtil = get_points(prevSubPositionX,prevSubPositionY,subPositionX,subPositionY)
                for item2 in pendingUtil:
                    cfx,cfy = item2
                    circular_percentage = get_angle_between(cfx,cfy,centreOfGravityX,centreOfGravityY) / 3.6

circular_percentage (cp) 本质上是度数/3.6(逆时针,虽然链接是顺时针角度,但我尝试从 100cp(360deg)中减去它无济于事,所以我怀疑这是问题所在)

get_points() 是“Bresenham 线算法”,效果很好。

planets 是以下字典:

{"Earthlike": {"x": 375, "y": 375, "s": 200, "i": "earthlike_1_beveled.png", "g": 11}}

我已经尝试过一点,看看它是否会开始工作,但主要问题是我不理解所涉及的任何数学,所以链接的 Wikipedia 文章就在我的脑海中。 我(坦率地说)不知道是什么导致了问题或如何解决它。

这是一个下载所有 194KB 的链接(解压缩后实际上小了 10KB)程序及其纹理。 (使用 WASD/方向键移动,问题出在第 49 到 63 行或第 100 到 108 行(第一行是 #1 而不是 #0)):

https://www.filehosting.org/file/details/920907/SOQ.zip

可能有一些不必要的代码,因为我刚刚得到我的主程序并删除了大部分不需要的部分。

以防万一,这是代码(它在 zip 中,但我想我可能还是应该把它放在这里,即使它是无法运行的(真正的单词?)没有纹理):

#See lines (this line is #1) - 49 to 63 - and - 100 to 108


import json, math, os, pygame, sys, time
from pygame.locals import *
pygame.init()
baseFolder = __file__[:-10]
FPS = 30
FramePerSec = pygame.time.Clock()
xVelocity = yVelocity = rVelocity = float(0)
def get_points(x0,y0,x1,y1):
    pointlist = []
    x0,y0 = int(x0),int(y0)
    x1,y1 = int(x1),int(y1)
    dx = abs(x1-x0)
    dy = abs(y1-y0)
    if x0 < x1: sx = 1
    else: sx = -1
    if y0 < y1: sy = 1
    else: sy = -1
    err = dx-dy
    while True:
        pointlist.append((x0,y0))
        if x0 == x1 and y0 == y1: return pointlist
        e2 = 2 * err
        if e2 > -dy:
            err = err - dy
            x0 += sx
        if e2 < dx:
            err = err + dx
            y0 += sy
screen_size = 750
spaceship_texture = "spaceship.png"
spaceship_texture = spaceship_texture.replace("\n","")
spaceship_size = 60
gravityJsonQ = True
planets = {"Earthlike": {"x": 375, "y": 375, "s": 200, "i": "earthlike_1_beveled.png", "g": 11}}
displaySurf = pygame.display.set_mode((screen_size,screen_size))
displaySurf.fill((0,0,0))
subPositionX = subPositionY = float(screen_size / 2)
circular_percentage = 0




#Problem:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def get_angle_between(x0,y0,x1,y1): 
    v1 = Vector(x0, y0)
    v2 = Vector(x1, y1)
    
    v1_theta = math.atan2(v1.y, v1.x)
    v2_theta = math.atan2(v2.y, v2.x)
    
    r = (v2_theta - v1_theta) * (180.0 / math.pi)
    
    return r

#or mabye...




class Spaceship(pygame.sprite.Sprite):
    def __init__(self):
        global baseFolder, screen_size, spaceship_images, spaceship_size, spaceship_texture
        super().__init__()
        spaceship_images = {}
        for pendingUtil in range(0,100): spaceship_images[str(pendingUtil)]  = pygame.image.load(baseFolder + "\\" + spaceship_texture + ".texture_map\\" + str(pendingUtil) + ".png")
        self.image = spaceship_images["0"]
        self.surf = pygame.Surface((int(spaceship_size), int(spaceship_size)))
        self.rect = self.surf.get_rect(center = (int(screen_size / 2),int(screen_size / 2)))
        self.image = pygame.transform.scale(self.image,(spaceship_size,spaceship_size))
    def move(self):
        global circular_percentage, rVelocity, prevSubPositionX, prevSubPositionY, subPositionX, subPositionY, xVelocity, yVelocity
        pressed_keys = pygame.key.get_pressed()
        if pressed_keys[K_UP] or pressed_keys[K_w]:
            yVelocity -= 0.1
        if pressed_keys[K_DOWN] or pressed_keys[K_s]:
            yVelocity += 0.1
        if pressed_keys[K_LEFT] or pressed_keys[K_a]:
            xVelocity -= 0.1
        if pressed_keys[K_RIGHT] or pressed_keys[K_d]:
            xVelocity += 0.1
        prevSubPositionX,prevSubPositionY = subPositionX,subPositionY
        subPositionX += xVelocity
        subPositionY += yVelocity
        
        
        
        
        #Problem:
        
        if gravityJsonQ:
            for item in planets:
                centreOfGravityX = planets[item]["x"] + (planets[item]["s"] / 2)
                centreOfGravityY = planets[item]["y"] + (planets[item]["s"] / 2)
                centreOfGravityGravity = float(planets[item]["g"])
                pendingUtil = get_points(prevSubPositionX,prevSubPositionY,subPositionX,subPositionY)
                for item2 in pendingUtil:
                    cfx,cfy = item2
                    circular_percentage = get_angle_between(cfx,cfy,centreOfGravityX,centreOfGravityY) / 3.6
        
        #Problem will (very likely) be either here or noted area above
        
        
        
        
        while circular_percentage < 0: circular_percentage += 100
        while circular_percentage > 99: circular_percentage -= 100
        self.rect = self.surf.get_rect(center = (int(subPositionX),int(subPositionY)))
        self.image = spaceship_images[str(int(circular_percentage))]
        self.image = pygame.transform.scale(self.image,(spaceship_size,spaceship_size))
Player = Spaceship()
all_sprites = pygame.sprite.Group()
all_sprites.add(Player)
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    displaySurf.fill((0,0,0))
    for item in planets:
        current_planet_image = pygame.image.load(planets[item]["i"])
        current_planet_image = pygame.transform.scale(current_planet_image,(planets[item]["s"],planets[item]["s"]))
        displaySurf.blit(current_planet_image,(planets[item]["x"],planets[item]["y"]))
    for entity in all_sprites:
        displaySurf.blit(entity.image,entity.rect)
        entity.move()
    pygame.display.update()
    FramePerSec.tick(FPS)

【问题讨论】:

    标签: python python-3.x math pygame pygame-surface


    【解决方案1】:

    注意,Pygame 提供了pygame.math.Vector2 类。没有必要以不同的角度绘制 100 幅宇宙飞船的图像。您可以使用pygame.transform.rotate 旋转图像。见How do I rotate an image around its center using PyGame?


    从点(x0y0)到点(x1y1)的向量是:

    v = Vector(x1-x0, y1-y0)
    

    向量的角度为(见How to know the angle between two points?):

    math.atan2(y1-y0, x1-x0)
    

    pygame坐标系的左上角是(0, 0)。因此,y 轴指向下方。因此,您必须反转 y 轴才能计算角度。

    get_angle_between函数:

    def get_angle_between(x0, y0, x1, y1):
        v = Vector(x1-x0, y1-y0)
        return math.degrees(math.atan2(-v.y, v.x))
    

    上式中,角度为0表示飞船指向右侧。如果你的飞船指向 0 角,你需要添加一个校正角(见How to rotate an image(player) to the mouse direction?):

    def get_angle_between(x0, y0, x1, y1):
        v = Vector(x1-x0, y1-y0)
        return math.degrees(math.atan2(-v.y, v.x)) - 90
    

    在这个答案中,我想解释计算的步骤。我想让它易于理解。当然,您可以跳过构造Vector 对象并将所有内容放在一行代码中:

    def get_angle_between(x0, y0, x1, y1):
        return math.degrees(math.atan2(y0-y1, x1-x0)) - 90
    

    然而,计算中的瓶颈是函数math.atan2

    【讨论】:

      猜你喜欢
      • 2015-08-26
      • 2014-01-22
      • 2011-01-30
      • 1970-01-01
      • 2010-10-24
      • 2015-08-02
      • 2015-08-02
      • 1970-01-01
      相关资源
      最近更新 更多