Python 在Pygame中旋转和移动精灵
我对Python、Pygame和编程都是新手。我正在尝试创建一个小行星克隆,但我不知道如何让我的玩家精灵同时移动和旋转。我使用了来自的Vector2D类(尝试将其修改为键盘而不是鼠标),因此我的精灵有点旋转(它不会在一个完整的圆圈中旋转),但现在它不会移动。我试着用上下键来加速/减速,用左右箭头来转弯。我希望船朝向它移动的方向 以下是迄今为止的代码:Python 在Pygame中旋转和移动精灵,python,rotation,pygame,sprite,Python,Rotation,Pygame,Sprite,我对Python、Pygame和编程都是新手。我正在尝试创建一个小行星克隆,但我不知道如何让我的玩家精灵同时移动和旋转。我使用了来自的Vector2D类(尝试将其修改为键盘而不是鼠标),因此我的精灵有点旋转(它不会在一个完整的圆圈中旋转),但现在它不会移动。我试着用上下键来加速/减速,用左右箭头来转弯。我希望船朝向它移动的方向 以下是迄今为止的代码: # an asteroids clone try: import sys import random import ma
# an asteroids clone
try:
import sys
import random
import math
import os
import getopt
import pygame
from socket import *
from pygame.locals import *
from pygame.mixer import Sound
except ImportError, err:
print "couldn't load module. %s" % (err)
sys.exit(2)
# these are warnings if font or sound modules are not available.
if not pygame.font: print 'Warning, fonts disabled'
if not pygame.mixer: print 'Warning, sound disabled'
# VECTOR CLASS
class Vector2D(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector2D(self.x - other.x, self.y - other.y)
def __mul__(self, other):
if isinstance(other, Vector2D):
# Vector multiplication
return self.x * other.x + self.y * other.y
else:
# Scalar multiplication
return Vector2D(self.x * other, self.y * other)
__radd__ = __add__
__rsub__ = __sub__
__rmul__ = __mul__
def get_length(self):
return (self.x ** 2 + self.y ** 2) ** (1/2)
def get_angle(self, other, radians=False):
"""Will return the angle between this vector and the other vector."""
if self.get_length() == 0 or other.get_length() == 0:
return 0
if not radians:
return (360 / (2 * math.pi)) * (math.atan2(other.y, other.x) - math.atan2(self.y, self.x))
else:
return math.atan2(other.y, other.x) - math.atan2(self.y, self.x)
def normalize(self):
if self.get_length() == 0:
return Vector2D(0, 0)
return Vector2D(self.x / self.get_length(), self.y / self.get_length())
class Player(pygame.sprite.Sprite):
"""moves ship on screen"""
def __init__(self, image_file, pos=(0, 0)):
super(Player, self).__init__() # call Sprite initializer
self.original_image = pygame.image.load(image_file).convert() # RemEMBER TO CONVERT
self.image = self.original_image # this will reference our rotated copy
self.rect = self.image.get_rect()
self.position = Vector2D(*pos)
self.moving = 0 # won't move at start of game
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.speed = 10
self.state = "still"
degree = 0
self.reinit()
def reinit(self):
self.state = "still"
self.movepos = [0,0]
def update(self):
newpos = self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect = newpos
# Create a vector pointing at the key position
key_pos = self.rect.move(self.movepos)
# Create a vector pointing from the image towards the key direction
rel_key_pos = key_pos - self.position
# Calculate the angle between the y_axis and the vector pointing from the
# image towards the mouse position
y_axis = Vector2D(0, -1)
angle = -y_axis.get_angle(rel_key_pos) # Negating bc pygame rotates counter-clockwise
# Create the rotated copy
self.image = pygame.transform.rotate(self.original_image, angle).convert() # Angle is absolute value!!
# Make sure your rect represent the actual Surface
self.rect = self.image.get_rect()
# Since the dimension probably changed you should move its center back to where it was.
self.rect.center = self.position.x, self.position.y
pygame.event.pump()
def accelerate(self):
self.speed += 1
self.state = "accelerate"
def decelerate(self):
self.speed -= 1
self.state = "decelerate"
def moveleft(self):
self.movepos[0]-=(self.speed)
self.state="moveleft"
def moveright(self):
self.movepos[0]+=(self.speed)
self.state="moveright"
class Bullet():
pass
class Asteroid():
pass
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
# main event loop
def main():
# initialize screen
pygame.init()
pygame.mixer.init()
pygame.key.set_repeat(500,30)
screen = pygame.display.set_mode((1280, 1024))
pygame.display.set_caption('Asteroids')
pygame.mouse.set_visible(0)
# make background
background = Background('data\stars1.jpg', [0,0])
# prepare background music
pygame.mixer.music.load('data\patakasmusic.wav')
pygame.mixer.music.play(-1)
# load player sprite
global player
player = Player('data\ship.png', [0,0])
# initialize player sprite
playersprite = pygame.sprite.RenderPlain((player))
# initialize clock
clock = pygame.time.Clock()
# event loop
while 1:
clock.tick(60)
# event loop
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN:
if event.key == K_UP:
player.accelerate()
if event.key == K_DOWN:
player.decelerate()
if event.key == K_LEFT:
player.moveleft()
if event.key == K_RIGHT:
player.moveright()
elif event.type == KEYUP:
if event.key == K_UP or event.key == K_DOWN:
player.movepos = [0,0]
screen.fill([255, 255, 255])
screen.blit(background.image, background.rect)
screen.blit(player.image, (500,500))
playersprite.draw(screen)
playersprite.update()
pygame.display.update()
playersprite.update()
pygame.display.flip()
if __name__ == '__main__': main()
我将使用另一个向量来存储精灵的
方向
,并添加一个角度\速度
属性。当用户想要转动船舶时,将角度速度
设置为所需的角度值,并在更新
方法中按角度速度旋转方向向量。要移动精灵,请将方向
乘以自身速度
,以获得速度并将其添加到自身位置
,然后更新rect
我建议使用这个类,因为它有更多的特性,而且速度非常快,因为它是用C实现的
import math
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos=(420, 420)):
super(Player, self).__init__()
self.image = pg.Surface((70, 50), pg.SRCALPHA)
pg.draw.polygon(self.image, (50, 120, 180), ((0, 0), (0, 50), (70, 25)))
self.original_image = self.image
self.rect = self.image.get_rect(center=pos)
self.position = Vector2(pos)
self.direction = Vector2(1, 0) # A unit vector pointing rightward.
self.speed = 2
self.angle_speed = 0
self.angle = 0
def update(self):
if self.angle_speed != 0:
# Rotate the direction vector and then the image.
self.direction.rotate_ip(self.angle_speed)
self.angle += self.angle_speed
self.image = pg.transform.rotate(self.original_image, -self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
# Update the position vector and the rect.
self.position += self.direction * self.speed
self.rect.center = self.position
def main():
pg.init()
screen = pg.display.set_mode((1280, 720))
player = Player((420, 420))
playersprite = pg.sprite.RenderPlain((player))
clock = pg.time.Clock()
done = False
while not done:
clock.tick(60)
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
player.speed += 1
elif event.key == pg.K_DOWN:
player.speed -= 1
elif event.key == pg.K_LEFT:
player.angle_speed = -4
elif event.key == pg.K_RIGHT:
player.angle_speed = 4
elif event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
player.angle_speed = 0
elif event.key == pg.K_RIGHT:
player.angle_speed = 0
playersprite.update()
screen.fill((30, 30, 30))
playersprite.draw(screen)
pg.display.flip()
if __name__ == '__main__':
main()
pg.quit()
我将使用另一个向量来存储精灵的
方向
,并添加一个角度\速度
属性。当用户想要转动船舶时,将角度速度
设置为所需的角度值,并在更新
方法中按角度速度旋转方向向量。要移动精灵,请将方向
乘以自身速度
,以获得速度并将其添加到自身位置
,然后更新rect
我建议使用这个类,因为它有更多的特性,而且速度非常快,因为它是用C实现的
import math
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos=(420, 420)):
super(Player, self).__init__()
self.image = pg.Surface((70, 50), pg.SRCALPHA)
pg.draw.polygon(self.image, (50, 120, 180), ((0, 0), (0, 50), (70, 25)))
self.original_image = self.image
self.rect = self.image.get_rect(center=pos)
self.position = Vector2(pos)
self.direction = Vector2(1, 0) # A unit vector pointing rightward.
self.speed = 2
self.angle_speed = 0
self.angle = 0
def update(self):
if self.angle_speed != 0:
# Rotate the direction vector and then the image.
self.direction.rotate_ip(self.angle_speed)
self.angle += self.angle_speed
self.image = pg.transform.rotate(self.original_image, -self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
# Update the position vector and the rect.
self.position += self.direction * self.speed
self.rect.center = self.position
def main():
pg.init()
screen = pg.display.set_mode((1280, 720))
player = Player((420, 420))
playersprite = pg.sprite.RenderPlain((player))
clock = pg.time.Clock()
done = False
while not done:
clock.tick(60)
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
player.speed += 1
elif event.key == pg.K_DOWN:
player.speed -= 1
elif event.key == pg.K_LEFT:
player.angle_speed = -4
elif event.key == pg.K_RIGHT:
player.angle_speed = 4
elif event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
player.angle_speed = 0
elif event.key == pg.K_RIGHT:
player.angle_speed = 0
playersprite.update()
screen.fill((30, 30, 30))
playersprite.draw(screen)
pg.display.flip()
if __name__ == '__main__':
main()
pg.quit()
请看一下。请看一下。使用pygame的vector类绝对是个好主意,但为什么不在每次更新中只存储角度而不是从方向向量计算角度呢?@WyattIsrael是的,这更简单。在这个示例的原始版本中,我只需要角度计算,因为我必须朝着鼠标旋转。我只是忘了更改那一行。@skrx我收到一个错误,说没有pygame.math模块。我在哪里能找到它?顺便说一句,我用的是Windows。这很奇怪。你使用什么pygame版本?那你是怎么安装的呢?没关系——我有1.9.1,现在安装了1.9.3,所以模块可以工作了。我的玩家精灵正在移动和旋转。谢谢-我感谢你的帮助!使用pygame的vector类绝对是一个好主意,但是为什么不在每次更新中只存储角度而不是从方向向量计算角度呢?@WyattIsrael是的,这更简单。在这个示例的原始版本中,我只需要角度计算,因为我必须朝着鼠标旋转。我只是忘了更改那一行。@skrx我收到一个错误,说没有pygame.math模块。我在哪里能找到它?顺便说一句,我用的是Windows。这很奇怪。你使用什么pygame版本?那你是怎么安装的呢?没关系——我有1.9.1,现在安装了1.9.3,所以模块可以工作了。我的玩家精灵正在移动和旋转。谢谢-我感谢你的帮助!