【问题标题】:Countermeasure for having the coordinate grid upside down?坐标网格倒置的对策?
【发布时间】:2017-12-10 04:41:42
【问题描述】:

所以我使用pygame 来创建一个简单的自上而下的射击游戏,并且我从自上而下的角度进行了大量的角度计算。让我们以一个简单的箭头和一个球为例,我希望红色箭头始终指向蓝色球,而不管蓝色球移动到哪里:

而且看起来很简单,我只需要atan2

angle = math.atan2(blue.y - red.y, blue.x - red.x)

但问题是,atan2 适用于这样的数学坐标网格:

在哪里alpha = math.atan2(blue.y - red.y, blue.x - red.x)

pygame(至少在 Windows 上)的问题是坐标网格不像数学坐标网格那样工作,它实际上是从游戏窗口的左上角开始颠倒的:

因此,虽然蓝色球看起来更高,因此在数学上blue.y 应该大于red.y,但实际上并非如此,因为倒置坐标网格,Python 的math.atan2() 没有知道,以及我原来的计算:

angle = math.atan2(blue.y - red.y, blue.x - red.x)

实际上产生了正确的角度的否定。

现在我想出的第一个显而易见的解决方案就是翻转标志,这很公平:

angle = -math.atan2(blue.y - red.y, blue.x - red.x)

但是,一旦我需要根据之前计算的角度进行进一步的计算,问题又开始了,从技术上讲,这个角度现在是颠倒的。

我可以采取什么对策来“永久”摆脱这个问题?

这是我需要这个的实际示例,我有一个“僵尸”实体,它什么都不做,只是遵循给定的目标:

class Zombie(Entity):

    def __init__(self, *args, target=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.target = target

    def update(self, dt, app):
        if self.target:
            # Face towards target
            dx = self.target.x - self.x
            dy = self.target.y - self.y
            self.angle = math.atan2(dy, dx)
            # Change velocity towards target
            speed = self.get_max_speed()
            vel_x = math.cos(angle) * speed
            vel_y = math.sin(angle) * speed
            self.velocity = (vel_x, vel_y)
        else:
            self.velocity = (0, 0)
        # Moves the zombie based on velocity
        super().update(dt, app)

对于这种特殊情况,我设法通过将角度存储到一个单独的变量中以供以后使用来解决它,并在设置 self.angle 时单独否定它:

# Face towards target
dx = self.target.x - self.x
dy = self.target.y - self.y
angle = math.atan2(dy, dx)
self.angle = -angle
# Change velocity towards target
speed = self.get_max_speed()
vel_x = math.cos(angle) * speed
vel_y = math.sin(angle) * speed
self.velocity = (vel_x, vel_y)

但这只是在乞求更多的错误,我正在寻找一个更通用的解决方案。

【问题讨论】:

  • pygame 有pygame.math.Vector2,适合计算。顺便说一句:即使使用math 模块,我也从来没有遇到过角度问题
  • 我对这个解决方案也没有问题。你具体指的是什么问题?我通常也使用pygame.math.Vector2s。 Here's an example,其中我还使用as_polar 方法而不是math.atan2 来获取角度。
  • 好吧,以前从未听说过Vector2,应该一开始就使用它。 Omw 然后重构......谢谢大家
  • 顺便说一句:几天前我用Vector2-stackoverflow.com/a/47644510/1832058做了例子
  • 当我阅读您的问题时,我认为问题不是角度而是翻转坐标。您在 bottom 左角使用 (0,0) 在系统中计算所有内容,并且您必须在 top 左角使用 (0,0) 在翻转系统中绘制它。因此,您必须在绘制之前翻转所有 y 值,然后在 bottom 角落中获得 (0,0)screen_y = SCREEN_HEIGHT - real_y

标签: python pygame coordinates python-3.6 angle


【解决方案1】:

您可以自己计算角度,而不是更改为负号。我用了你的球和箭的例子。这是非常简单的三角函数:

#Import needed programs
import pygame, sys, time, math
from pygame.locals import *

#Initialize pygame
pygame.init()
window = pygame.display.set_mode((600, 450))
pygame.display.set_caption('PyCloud')

#Define colours
aqua = 0,255,255
white = 255,255,255

#Defne an arrow sprite class
arrow = pygame.image.load("arrow.png")
arrow = pygame.transform.scale(arrow,(50,200))

#Define a function to calculate angle
def calcAngle(triangleA,triangleB):
    sinAngle = triangleA/triangleB
    angle = math.asin(sinAngle)
    return math.degrees(angle)    

#Creat clock lop for stability
clock = pygame.time.Clock()

#start main loop
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            exit()
        else:
            pass

    #Get mouse pos
    mouse = pygame.mouse.get_pos()
    x = mouse[0]
    y = mouse[1]

    #calculate triangle lengths
    triangleA = x
    triangleB = math.hypot(x,(450-y))
    angle = calcAngle(triangleA,triangleB)
    print(angle)

    #draw screen
    window.fill(white)
    pygame.draw.circle(window,aqua,(x,y),10,0)
    window.blit(arrow,(0,350))
    clock.tick(1000)
    pygame.display.update()

程序将箭头应转动的准确角度存储在名为angle 的变量中。我会让你决定你蚂蚁如何处理角度本身。这与您所做的不同之处在于它基于 pygame 轴而不是数学轴来计算它。

如果您想测试一下,这是箭头图像。只需将以下图像保存在与程序相同的文件夹中:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多