经过几个小时的完全混乱之后,我仍然没有找到一个旋转精灵来面向鼠标位置的解决方案。我已经从其他帖子中实现了几个例子,链接在下面,但它们似乎都没有效果。任何有关我的问题的帮助,将非常感激:)
原始代码:
class Player(pygame.sprite.Sprite):
def __init__(self, game, x, y):
pygame.sprite.Sprite.__init__(self)
self.game = game
sprite_sheet = Spritesheet("Sprites/ships_spritesheet.png")
image = sprite_sheet.get_image(204, 115, 66, 113)
self.image = pygame.transform.flip(image, False, True)
self.orig_img = self.image
self.rect = self.image.get_rect()
self.pos = vec(x, y)
self.vel = vec(0, 0)
self.health = PLAYER_HEALTH
def update(self):
self.rotate()
self.pos += self.vel
self.rect.x = self.pos.x
self.collide_with_tiles(self.game.obstacle_list, "x")
self.rect.y = self.pos.y
self.collide_with_tiles(self.game.obstacle_list, "y")
def rotate(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y - self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pygame.transform.rotate(self.orig_img, int(angle))
self.rect = self.image.get_rect(center=self.pos)
新守则:
class Player(pygame.sprite.Sprite):
def __init__(self, game, pos):
pygame.sprite.Sprite.__init__(self)
self.game = game
sprite_sheet = Spritesheet("Sprites/ships_spritesheet.png")
image = sprite_sheet.get_image(204, 115, 66, 113)
self.image = pygame.transform.flip(image, False, True)
self.orig_img = self.image
self.rect = self.image.get_rect(center=pos)
self.pos = vec(pos)
self.vel = vec(0, 0)
self.health = PLAYER_HEALTH
def update(self):
self.rotate()
self.pos += self.vel
self.rect.centerx = self.pos.x
#self.rect.x = self.pos.x
self.collide_with_tiles(self.game.obstacle_list, "x")
self.rect.centery = self.pos.y
#self.rect.y = self.pos.y
self.collide_with_tiles(self.game.obstacle_list, "y")
self.vel = vec(0, 0)
def rotate(self):
mouse_pos = pygame.mouse.get_pos()
rel_x, rel_y = mouse_pos - self.pos
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.orig_img, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def collide_with_tiles(self, group, dir):
if dir == "x":
hits = pygame.sprite.spritecollide(self, group, False)
if hits:
if self.vel.x > 0:
self.rect.right = hits[0].rect.left
if self.vel.x < 0:
self.rect.left = hits[0].rect.right
self.pos.x = self.rect.centerx
if dir == "y":
hits = pygame.sprite.spritecollide(self, group, False)
if hits:
if self.vel.y > 0:
self.rect.bottom = hits[0].rect.top
if self.vel.y < 0:
self.rect.top = hits[0].rect.bottom
self.pos.y = self.rect.centery
我的游戏类
import pygame, pytmx, sys, os
from Settings import *
from Obstacle import *
from Player import *
from Camera import *
from TiledMap import *
from MainMenu import *
from PauseMenu import *
from OptionsMenu import *
from HUD import *
class Game:
def __init__(self):
pygame.init()
pygame.mixer.init()
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.display.set_caption(GAME_TITLE)
self.window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
self.clock = pygame.time.Clock()
self.click_sound = pygame.mixer.Sound("Sounds/click1.ogg")
self.main_menu = MainMenu(self, self.window)
self.obstacle_list = pygame.sprite.Group()
self.island_boundary_list = pygame.sprite.Group()
self.pause_menu = PauseMenu(self.window)
self.options_menu = OptionsMenu(self.window)
self.hud = HUD()
self.display_pause_menu = False
self.display_options_menu = False
self.display_main_menu = True
def get_map(self):
map_dir = TiledMap("Sprites/Maps/map_01.tmx")
self.map = map_dir.generate_map()
self.map_rect = self.map.get_rect()
for tile_obj in map_dir.tmxdata.objects:
if tile_obj.name == "Obstacle":
obstacle = Obstacle(self, tile_obj.x, tile_obj.y, 64, 64)
self.obstacle_list.add(obstacle)
if tile_obj.name == "PLAYER":
self.player = Player(self, (tile_obj.x, tile_obj.y))
def game_loop(self):
self.get_map()
self.camera = Camera(5120, 5120)
while True:
self.clock.tick(FPS)
self.game_events()
if not self.display_pause_menu and not self.display_options_menu and not self.display_main_menu:
self.update_game()
self.draw_game()
def game_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.run_game = False
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p and not self.display_options_menu:
self.display_pause_menu = not self.display_pause_menu
if event.key == pygame.K_o and not self.display_pause_menu:
self.display_options_menu = not self.display_options_menu
if event.type == pygame.MOUSEBUTTONDOWN and self.display_main_menu:
x, y = event.pos
self.click_sound.play()
if self.main_menu.play_button.collidepoint(x, y):
self.display_main_menu = False
if self.main_menu.credits_button.collidepoint(x, y):
pass
if self.main_menu.exit_button.collidepoint(x, y):
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and self.display_pause_menu:
x, y = event.pos
self.click_sound.play()
if self.pause_menu.pause_resume_button.collidepoint(x, y) or self.pause_menu.pause_x_button.collidepoint(x, y):
self.display_pause_menu = False
if self.pause_menu.pause_options_button.collidepoint(x, y):
self.display_pause_menu = False
self.display_options_menu = True
if self.pause_menu.pause_quit_button.collidepoint(x, y):
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and self.display_options_menu:
x, y = event.pos
self.click_sound.play()
if self.options_menu.options_x_button.collidepoint(x, y):
self.display_options_menu = False
if self.options_menu.options_reset_button.collidepoint(x, y):
#reset options to original options if modified
pass
if self.options_menu.options_home_button.collidepoint(x, y):
self.display_options_menu = False
self.display_main_menu = True
if self.options_menu.options_ok_button.collidepoint(x, y):
#save settings
self.display_options_menu = False
mouse_x, mouse_y = pygame.mouse.get_pos()
if mouse_x > self.main_menu.play_button.x and mouse_x < self.main_menu.play_button.x + self.main_menu.play_button.width and mouse_y > self.main_menu.play_button.y and mouse_y < self.main_menu.play_button.y + self.main_menu.play_button.height:
self.main_menu.img_id = 1
elif mouse_x > self.main_menu.credits_button.x and mouse_x < self.main_menu.credits_button.x + self.main_menu.credits_button.width and mouse_y > self.main_menu.credits_button.y and mouse_y < self.main_menu.credits_button.y + self.main_menu.credits_button.height:
self.main_menu.img_id = 2
elif mouse_x > self.main_menu.exit_button.x and mouse_x < self.main_menu.exit_button.x + self.main_menu.exit_button.width and mouse_y > self.main_menu.exit_button.y and mouse_y < self.main_menu.exit_button.y + self.main_menu.exit_button.height:
self.main_menu.img_id = 3
else:
self.main_menu.img_id = 0
if mouse_x > self.pause_menu.pause_resume_button.x and mouse_x < self.pause_menu.pause_resume_button.x + self.pause_menu.pause_resume_button.width and mouse_y > self.pause_menu.pause_resume_button.y and mouse_y < self.pause_menu.pause_resume_button.y + self.pause_menu.pause_resume_button.height:
self.pause_menu.img_id = 1
elif mouse_x > self.pause_menu.pause_x_button.x and mouse_x < self.pause_menu.pause_x_button.x + self.pause_menu.pause_x_button.width and mouse_y > self.pause_menu.pause_x_button.y and mouse_y < self.pause_menu.pause_x_button.y + self.pause_menu.pause_x_button.height:
self.pause_menu.img_id = 2
elif mouse_x > self.pause_menu.pause_options_button.x and mouse_x < self.pause_menu.pause_options_button.x + self.pause_menu.pause_options_button.width and mouse_y > self.pause_menu.pause_options_button.y and mouse_y < self.pause_menu.pause_options_button.y + self.pause_menu.pause_options_button.height:
self.pause_menu.img_id = 3
elif mouse_x > self.pause_menu.pause_quit_button.x and mouse_x < self.pause_menu.pause_quit_button.x + self.pause_menu.pause_quit_button.width and mouse_y > self.pause_menu.pause_quit_button.y and mouse_y < self.pause_menu.pause_quit_button.y + self.pause_menu.pause_quit_button.height:
self.pause_menu.img_id = 4
else:
self.pause_menu.img_id = 0
if mouse_x > self.options_menu.options_x_button.x and mouse_x < self.options_menu.options_x_button.x + self.options_menu.options_x_button.width and mouse_y > self.options_menu.options_x_button.y and mouse_y < self.options_menu.options_x_button.y + self.options_menu.options_x_button.height:
self.options_menu.img_id = 1
elif mouse_x > self.options_menu.options_reset_button.x and mouse_x < self.options_menu.options_reset_button.x + self.options_menu.options_reset_button.width and mouse_y > self.options_menu.options_reset_button.y and mouse_y < self.options_menu.options_reset_button.y + self.options_menu.options_reset_button.height:
self.options_menu.img_id = 2
elif mouse_x > self.options_menu.options_home_button.x and mouse_x < self.options_menu.options_home_button.x + self.options_menu.options_home_button.width and mouse_y > self.options_menu.options_home_button.y and mouse_y < self.options_menu.options_home_button.y + self.options_menu.options_home_button.height:
self.options_menu.img_id = 3
elif mouse_x > self.options_menu.options_ok_button.x and mouse_x < self.options_menu.options_ok_button.x + self.options_menu.options_ok_button.width and mouse_y > self.options_menu.options_ok_button.y and mouse_y < self.options_menu.options_ok_button.y + self.options_menu.options_ok_button.height:
self.options_menu.img_id = 4
else:
self.options_menu.img_id = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.player.vel.x = PLAYER_SPEED
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.player.vel.x = -PLAYER_SPEED
if keys[pygame.K_UP] or keys[pygame.K_w]:
self.player.vel.y = -PLAYER_SPEED
if keys[pygame.K_DOWN] or keys[pygame.K_s]:
self.player.vel.y = PLAYER_SPEED
def update_game(self):
self.player.update()
self.camera.update(self.player)
if self.player.rect.x <= 0:
self.player.rect.x = 0
if self.player.rect.right >= 5120:
self.player.rect.right = 5120
if self.player.rect.y <= 0:
self.player.rect.y = 0
if self.player.rect.bottom >= 5120:
self.player.rect.bottom = 5120
def draw_game(self):
self.window.blit(self.map, self.camera.apply_rect(self.map_rect))
self.window.blit(self.player.image, self.camera.apply(self.player))
self.hud.draw_health(self.window, 10, 10, self.player.health / PLAYER_HEALTH)
if self.display_main_menu:
self.main_menu.draw()
if self.display_pause_menu:
self.pause_menu.draw()
if self.display_options_menu:
self.options_menu.draw()
pygame.display.flip()
def main():
g = Game()
g.game_loop()
if __name__ == "__main__":
main()
相机课程
import pygame
from Settings import *
class Camera:
def __init__(self, width, height):
self.camera = pygame.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, target):
return target.rect.move(self.camera.topleft)
def apply_rect(self, rect):
return rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.centerx + int(WINDOW_WIDTH/2)
y = -target.rect.centery + int(WINDOW_HEIGHT/2)
x = min(0, x)
y = min(0, y)
x = max(-(self.width - WINDOW_WIDTH), x)
y = max(-(self.height - WINDOW_HEIGHT), y)
self.camera = pygame.Rect(x, y, self.width, self.height)
答案 0 :(得分:1)
使用中心点self.rect.centerx
和self.rect.centery
或仅self.rect.center
和self.pos
代替self.rect.x
self.rect.y
(topleft坐标)。
以下是我用来测试代码的完整示例:
import math
import pygame
from pygame.math import Vector2
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
self.image,
pygame.Color('dodgerblue1'),
((0, 0), (50, 15), (0, 30)))
self.rect = self.image.get_rect(center=pos)
self.orig_img = self.image
self.pos = Vector2(pos)
self.vel = Vector2(0, 0)
def update(self):
self.rotate()
self.pos += self.vel
self.rect.centerx = self.pos.x
self.rect.centery = self.pos.y
def rotate(self):
mouse_pos = pygame.mouse.get_pos()
# Calculate the vector to the mouse position by subtracting
# the self.pos vector from the mouse_pos.
rel_x, rel_y = mouse_pos - self.pos
# Use math.atan2 to get the angle in radians and convert it to degrees.
angle = -math.degrees(math.atan2(rel_y, rel_x))
# Rotate the image.
self.image = pygame.transform.rotozoom(self.orig_img, angle, 1)
# Update the rect and keep the center at the old position.
self.rect = self.image.get_rect(center=self.rect.center)
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
sprite_group = pygame.sprite.Group()
player = Player((300, 200))
sprite_group.add(player)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
sprite_group.update()
screen.fill((30, 30, 30))
sprite_group.draw(screen)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
pygame.init()
main()
pygame.quit()
Edit3:在这个例子中,我使用另一个pygame.Rect
(称为hitbox
)来处理与墙壁的碰撞。玩家的rect
无法用于碰撞检测,因为它会随着每次旋转而改变其大小,如果玩家触摸墙壁则会导致跳跃。我使用Rect.colliderect
因为spritecollide
使用rect
而非hitbox
,但您也可以将自定义collided
回调函数传递给spritecollide。 (红色和绿色显示player.rect
和player.hitbox
。)
import math
import pygame
from pygame.math import Vector2 as vec
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, walls):
pygame.sprite.Sprite.__init__(self)
self.walls = walls
self.image = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
self.image,
pygame.Color('dodgerblue1'),
((0, 0), (50, 15), (0, 30)))
self.rect = self.image.get_rect(center=(x, y))
self.hitbox = pygame.Rect(x, y, 50, 50)
self.orig_img = self.image
self.pos = vec(x, y)
self.vel = vec(0, 0)
def update(self):
self.rotate()
self.pos += self.vel
self.hitbox.centerx = self.pos.x
self.collide_with_tiles(self.walls, "x")
self.hitbox.centery = self.pos.y
self.collide_with_tiles(self.walls, "y")
self.rect.center = self.pos
def rotate(self):
rel_x, rel_y = pygame.mouse.get_pos() - self.pos
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.orig_img, int(angle))
self.rect = self.image.get_rect(center=self.pos)
def collide_with_tiles(self, group, dir):
if dir == "x":
for wall in self.walls:
if self.hitbox.colliderect(wall.rect):
if self.vel.x > 0:
self.hitbox.right = wall.rect.left
if self.vel.x < 0:
self.hitbox.left = wall.rect.right
self.vel.x = 0
self.pos.x = self.hitbox.centerx
if dir == "y":
for wall in self.walls:
if self.hitbox.colliderect(wall.rect):
if self.vel.y > 0:
self.hitbox.bottom = wall.rect.top
if self.vel.y < 0:
self.hitbox.top = wall.rect.bottom
self.vel.y = 0
self.pos.y = self.hitbox.centery
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(pygame.Color('sienna1'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
sprite_group = pygame.sprite.Group()
walls = pygame.sprite.Group()
wall = Wall(100, 200, 300, 30)
walls.add(wall)
sprite_group.add(wall)
player = Player(300, 400, walls)
sprite_group.add(player)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.vel.y = -3
elif event.key == pygame.K_s:
player.vel.y = 3
elif event.key == pygame.K_a:
player.vel.x = -3
elif event.key == pygame.K_d:
player.vel.x = 3
elif event.type == pygame.KEYUP:
player.vel = vec(0, 0)
sprite_group.update()
screen.fill((30, 30, 30))
sprite_group.draw(screen)
pygame.draw.rect(screen, (200, 30, 30), player.rect, 2)
pygame.draw.rect(screen, (0, 200, 30), player.hitbox, 2)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
pygame.init()
main()
pygame.quit()
编辑4:要在计算中包含相机,请将Player
相机作为属性,并在rotate
方法中更改此行:
rel_x, rel_y = pg.mouse.get_pos() - vec(self.camera.apply(self).center)