无法理解如何在PyGame中制作角色面部鼠标

时间:2015-03-16 19:14:38

标签: python math pygame game-physics

以下是我到目前为止的情况。此刻,玩家移动,我现在想要做的就是始终面向鼠标光标(想想热线迈阿密或其他自上而下的游戏)。我已经使用了一些我在网上找到的涉及atan2的代码,但我几乎不明白它的作用(找到播放器和鼠标之间的距离......)而且我的角色在屏幕外疯狂旋转直到我得到'内存不足'错误。任何帮助都会非常感激,我在互联网上看了一遍,找不到任何可以帮助我的东西。

import pygame, sys, math
from pygame.locals import *

pygame.init()

#setup the window with a 720p resolution and a title
winX, winY = 1280, 720
display = pygame.display.set_mode((winX, winY))
winTitle = pygame.display.set_caption("Game name")

#Colours
cBlack = (0, 0, 0)

#setup the clock and FPS limit
FPS = 70
clock = pygame.time.Clock()

#sprite groups
allSprites = pygame.sprite.Group()

#background image
bg = pygame.image.load("bg.jpg")

class Player(pygame.sprite.Sprite):
    def __init__(self, speed):
        #import the __init__ from the Sprite class
        pygame.sprite.Sprite.__init__(self)
        #sets the objects speed to the speed argument
        self.speed = speed
        #set the soldiers image
        self.image = pygame.image.load("soldier_torso_DW.png")
        #get the rectangle of the image (used for movement later)
        self.rect = self.image.get_rect()
        #sets starting position
        self.rect.x, self.rect.y = winX/2, winY/2

    def checkPlayerMovement(self):
        """Check if user has pressed any movement buttons
            and sets the characters position accordingly."""
        pressed = pygame.key.get_pressed()
        if pressed[K_w]:
            self.rect.y -= self.speed
        if pressed[K_s]:
            self.rect.y += self.speed
        if pressed[K_a]:
            self.rect.x -= self.speed
        if pressed[K_d]:
            self.rect.x += self.speed

    def checkMouseMovement(self):
        """Check if user has moved the mouse and rotates the
            character accordingly."""
        mX, mY = pygame.mouse.get_pos()
        angleRad = math.atan2(mY, mX) - math.atan2(self.rect.y, self.rect.x)
        angleDeg = math.degrees(angleRad)
        print angleDeg
        self.image = pygame.transform.rotate(self.image, angleDeg)

    def update(self):
        """Performs all movement and drawing functions and shit
            for the object"""
        self.checkPlayerMovement()
        self.checkMouseMovement()
        #draw the image at the given coordinate
        display.blit(self.image, (self.rect.x, self.rect.y))

def updateAll():
    #fill the window with black
    display.blit(bg, (0, 0))
    #update all sprites
    allSprites.update()
    #keeps FPS at 60
    clock.tick(FPS)
    #updates the display
    pygame.display.flip()

#creates a player with a speed of 5
mainChar = Player(5)
#add the player character to main sprite group
allSprites.add(mainChar)

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    updateAll()

2 个答案:

答案 0 :(得分:4)

(完全披露,我不熟悉pygame包,但我用其他语言做过这种编程)

讨论

当你希望玩家确定它应该旋转多少面对一个物体时,玩家应该认为自己是世界中心。但是,它的坐标并不总是(0,0)。我们首先需要通过从想要面对的对象中减去玩家的位置,将我们的坐标转换为自我中心坐标。

接下来,看起来你只是使用玩家的位置来计算旋转。除非玩家总是面向等于从当前位置到原点的矢量方向的方向,否则这不是正确的计算。您必须包含其他信息以跟踪玩家的旋转,这通常通过带有(x,y)组件的单位方向向量来完成。

方法

  1. 计算从对象位置到玩家位置的相对向量
    • 将此向量称为 rel
  2. 计算atan2(V rel ) - atan2(playerDir y ,playerDir x
    • 结果现在是玩家需要旋转的数量,相对于自身
  3. 将精灵转换为原点,执行旋转,转换回来(我确定pygame具有只需旋转的功能)
  4. atan2()函数

    atan2函数将从正X轴给出签名旋转。

    因此,给定笛卡尔XY平面和位置(x,y),如果从(0,0)到(x,y)绘制一个向量,那么atan2(y,x)将给出两者之间的角度向量(1,0)和(x,y)。例如,如果你的(x,y)是(0,1)(沿着y轴),那么atan2(1,0)将给你π/ 2或90°,如果你的(x,y)去了沿负y轴(0,-1),然后atan2(0,-1)将给你-π/ 2,或-90°。

    atan2的正角度输出始终为逆时针旋转,负角度为顺时针旋转。大多数计算器确实需要atan2(y,x)形式,但不是全部,所以要小心。 In Python's math library, it is atan2(y, x)

    实施例

    原谅不规模,糟糕的颜色选择,幼儿园质量图片,并尝试专注于概念。

    位置(5,5)处的对象 位置(-3,-1)的球员。    球员面向方向(-0.8,0.6)

    Initial setup

    1. 相对向量是(Object x - Player x ,Object y - Player y )=(5 ,5) - ( - 3,-1)=(5 - -3,5 - -1)=(5 + 3,5 + 1)= (8,6)
    2. computing relative vector

      1. atan2(V rel )= atan2(6,8)= 0.9272952180016122 rad

        • atan2(playerDir y ,playerDir x )= atan2(-0.8,0.6)= 2.498091544796509 rad
      2. Setup with only vectors computing individual angles

        • atan2(V rel ) - atan2(player)= 0.9272952180016122 - 2.498091544796509 = -1.5707963267948966 rad

        computing angle between direction vector and relative vector

        所以玩家必须围绕自己的中心(顺时针近90度)旋转-1.57 rad才能面对物体。

答案 1 :(得分:2)

您正在计算屏幕和鼠标之间的角度与精灵与其位置之间的角度之间的差异。那不是你想要的。

我建议:

angleRad = math.atan2(self.rect.y-mY, mX-self.rect.x) # y is reversed due to top-left coordinate system

这是精灵应该看鼠标指针的绝对角度。

但是,你可能还有第二个问题:你在每一步都按这个角度旋转精灵。但是你应该只通过精灵的当前方向和所需的方向之间的差异来旋转(如果精灵是90度,你希望它面向90度,那么你就不应该旋转它。)

您应该保留前一个角度,以便仅通过差异旋转(但每次旋转可能会稍微改变精灵),或保持精灵的非旋转副本每次旋转这个角度:

self.image = pygame.transform.rotate(self.unrotated_image, angleDeg)