Pygame 制作精灵面向鼠标

4

我对Python还行,但是对Pygame还不太熟悉。我正在制作一款俯视角度的丧尸射击游戏。
我已经成功实现了通过按下箭头键来移动游戏角色。但是现在我需要让角色面向鼠标/光标而不需要一直点击屏幕。
有什么帮助吗?


3
你已经解决了让玩家面向鼠标点击位置的问题,现在你只需要监听鼠标移动并像处理点击一样更新玩家。那么需要解决的问题是如何在Pygame中监听鼠标移动? - Dan D.
5个回答

4
for event in pygame.event.get():
    if event.type == MOUSEMOTION:
        mousex, mousey = event.pos
        # build a vector between player position and mouse position
        moveVector = (mousex-playerx, mousey-playery)

        """
        compute the angle of moveVector from current vector that player is facing (faceVector).
        you should be keeping and updating this unit vector, with each mouse motion
        assume you have initial facing vector as (1,0) - facing East
        """

        # compute angle as in [1]

        # rotate the image to that angle and update faceVector

[1] - 如何计算两个向量之间的夹角:http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm

当以小角度旋转图像时,图像可能会失去质量。这在Pygame文档页面中有所讨论:http://pygame.org/docs/ref/transform.html#pygame.transform.rotate


2
如果 event.type == pygame.MOUSEMOTION,你可以直接使用 event.pos 来获取鼠标位置,而不必调用 pygame.mouse.get_pos() - Dan D.
它能工作,但Pygame的'pygame.transform.rotate'使用角度,那么我该怎么做? - user735977
@Firetryer:学习向量算术。http://en.wikipedia.org/wiki/Dot_product#Properties - JAB

1
import math

mouseX, mouseY = pygame.mouse.get_pos()
playerX, playerY = player.get_pos()

angle = math.atan2(playerX-mouseX, playerY-mouseY)

你可能需要调整减法的顺序(例如,它可能是mousePosition-playerPosition),或者调整atan2函数中x和y参数的顺序(例如,你可能需要将Y差异作为第一个参数而不是X),但这取决于你的坐标系统。

0

工作代码:

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


#converte in base ai gradi le cordinate x,y
#maxXY= surface MaxXY
#gradoRot = grado di rotazione
#distXY = spostamento in x,y lungo il vettore di cordinate locali dalle cordinate x,y

#movement from one point to another
def Move(t0,t1,psx,psy,speed):
    global mx
    global my

    speed = speed

    distance = [t0 - psx, t1 - psy]
    norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
    direction = [distance[0] / norm, distance[1 ] / norm]

    bullet_vector = [direction[0] * speed, direction[1] * speed]
    return bullet_vector
# Main Function
if __name__ == '__main__':
    pygame.init()
    FPS = 30 # frames per second setting
    fpsClock = pygame.time.Clock()
    # set up the window
    DISPLAYSURF = pygame.display.set_mode((800, 600), 0, 32)
    alfhaSurface = DISPLAYSURF.convert_alpha() 
    pygame.display.set_caption('test')
    shipImg = pygame.image.load('ship.png')
    shipImgcpy=shipImg.copy()
    vetShip=pygame.math.Vector2(400,300)
    gradi = 0
    gradiRot=0
    mouseX=0
    mouseY=0
    SHIP_W=40
    SHIP_H=40
    vetMouse=pygame.math.Vector2(mouseX,mouseY)
    #main loop
    while True:
        DISPLAYSURF.fill((0,0,0)) 
        alfhaSurface.fill((0,0,0))
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()  
            if event.type == MOUSEBUTTONDOWN:
                mouseX, mouseY = pygame.mouse.get_pos()
                vetMouse=pygame.math.Vector2(mouseX,mouseY)

                gradiRot=**math.atan2(vetShip.x-vetMouse.x, vetShip.y-vetMouse.y)**
                gradiRot=**math.degrees(gradiRot)**
                pygame.display.set_caption(""+str(gradi) +"="+ str(gradiRot)+" "+ str(vetMouse.angle_to(vetShip)) ) 
        pygame.draw.line(alfhaSurface, (255,255,255), (vetShip.x+SHIP_W,vetShip.y+SHIP_H),(vetMouse.x,vetMouse.y),1)                      
        if gradi != int(gradiRot) :
            if gradiRot > gradi and gradi != gradiRot :
                gradi=gradi+1

            if gradiRot < gradi and gradi != gradiRot :
                gradi=gradi-1    

            shipImgcpy=pygame.transform.rotate(shipImg.copy(),gradi) 

        elif int(vetMouse.distance_to(vetShip)) >0:
            posNext=Move(mouseX,mouseY,vetShip.x+SHIP_W,vetShip.y+SHIP_H,1)                  
          vetShip=pygame.math.Vector2(vetShip.x+posNext[0],vetShip.y+posNext[1])


        alfhaSurface.blit(shipImgcpy, tuple(vetShip))
        DISPLAYSURF.blit(alfhaSurface,(0,0))
        pygame.display.update()
        fpsClock.tick(FPS)   

我刚刚测试了船的鼻子图像,看着鼠标并跟随它,请自行尝试。 - Manfre Manfre

0
_, angle = (pg.mouse.get_pos()-self.pos).as_polar()

这行代码首先计算到鼠标位置的向量(self.pos 必须是一个 pygame.math.Vector2),然后 .as_polar() 返回向量的极坐标,包括径向距离和角度。最后使用负角度(因为 pygame 的 y 轴被翻转了)来旋转精灵图像并重新计算矩形。

import pygame as pg


class Player(pg.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        self.image = pg.Surface((50, 30), pg.SRCALPHA)
        pg.draw.polygon(
            self.image,
            pg.Color('dodgerblue1'),
            ((1, 1), (49, 15), (1, 29)))
        self.orig_img = self.image
        self.rect = self.image.get_rect(center=pos)
        self.pos = pg.math.Vector2(pos)
        self.vel = pg.math.Vector2(0, 0)

    def update(self):
        self.rotate()
        self.pos += self.vel
        self.rect.center = self.pos

    def rotate(self):
        _, angle = (pg.mouse.get_pos()-self.pos).as_polar()
        self.image = pg.transform.rotozoom(self.orig_img, -angle, 1)
        self.rect = self.image.get_rect(center=self.rect.center)


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    all_sprites.add(Player((300, 200)))

    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

math.atan2可以作为一个替代方案。

def rotate(self):
    rel_x, rel_y = pg.mouse.get_pos() - self.pos
    angle = -math.degrees(math.atan2(rel_y, rel_x))
    self.image = pg.transform.rotozoom(self.orig_img, angle, 1)
    self.rect = self.image.get_rect(center=self.pos)

@Coder22,对我来说它可以正常工作,三角形会朝向鼠标旋转。具体哪里出了问题? - skrx

-1
if event.type == MOUSEBUTTONDOWN:
    mouseX, mouseY = pygame.mouse.get_pos()
    vetMouse=pygame.math.Vector2(mouseX,mouseY)
    gradiRot=vetMouse.angle_to(vetShip)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接