pygame sprite not moving

2019-09-06 08:44发布

问题:

I'm faced with a logic error where the sprite simply doesn't move regardless of input.
My code will be below so no context is left out, it's fairly short.
Is there a better way of moving the sprite apart from the blit?
I've seen somewhere stuff about updating the sprite or some such, done quite differently to simply blitting it.

import pygame
pygame.init()
import random
import math

screen=pygame.display.set_mode([700,400])
black    = (   0,   0,   0)
white    = ( 255, 255, 255)
red      = ( 255,   0,   0)
player_x=350
player_y=200
player_x_vel=0
player_y_vel=0
rot_player=pygame.image

pi=math.pi

class Player(pygame.sprite.Sprite):
    def __init__(self):
        global player
        pygame.sprite.Sprite.__init__(self)
        self.pos=(350,200)
        self.image=pygame.image.load("arrowtest.png").convert()
        self.rect=self.image.get_rect()
        screen=pygame.display.get_surface()
        self.area=screen.get_rect()
        self.speed=10
        self.state="still"
        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
        pygame.event.pump()

    def moveup(self):
        self.movepos[1]-=(self.speed)
        self.state="moveup"
    def movedown(self):
        self.movepos[1]+=(self.speed)
        self.state="movedown"
    def moveleft(self):
        self.movepos[0]-=(self.speed)
        self.state="moveleft"
    def moveright(self):
        self.movepos[0]+=(self.speed)
        self.state="moveright"
    def moveupright(self):
        self.movepos[1]-=(self.speed)
        self.movepos[0]+=(self.speed)
    def moveupleft(self):
        self.movepos[1]-=(self.speed)
        self.movepos[0]-=(self.speed)
    def movedownright(self):
        self.movepos[1]+=(self.speed)
        self.movepos[0]+=(self.speed)
    def movedownleft(self):
        self.movepos[1]+=(self.speed)
        self.movepos[0]-=(self.speed)

    def angleplayer(self):
        mouse_pos=pygame.mouse.get_pos()
        dx=mouse_pos[0]-player_x
        dy=mouse_pos[1]-player_y
        rads=math.atan2(-dy, dx)
        rads %= 2*pi
        angle = math.degrees(rads)
        print angle
        rot_player.image=pygame.transform.rotate(player.image, angle-90)

done=False
clock=pygame.time.Clock()

while done==False:

    player = Player()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done=True
        if event.type == pygame.MOUSEBUTTONDOWN:
            fired_pos=pygame.mouse.get_pos()
            fired=True
        if event.type == pygame.KEYDOWN:
            player.angleplayer()
            if event.key == pygame.K_w:
                player.moveup()
            if event.key == pygame.K_s:
                player.movedown()
            if event.key == pygame.K_a:
                player.moveleft()
            if event.key == pygame.K_d:
                player.moveright()

            print "co ords", player_x,player_y
            print "x vel", player_x_vel
            print "y vel", player_y_vel

        if event.type == pygame.KEYUP:
            player.movepos=[0,0]
            player.state="still"
            player.angleplayer()

        screen.fill(white)
        screen.blit(player.image, player.pos)

    clock.tick(20)
    pygame.display.flip()

pygame.quit()

Thanks in advance

回答1:

First of all, you are creating a new player every iteration of your main loop:

...
while done == False:
    player = Player()
    ...

You want to create the player once, so move the creation outside the loop:

...
player = Player()
while not done:
    ...

Second: To get the position of the player, you use player.pos:

...
screen.blit(player.image, player.pos)
...

but you never update player.pos (it's always (350,200)), you only change self.rect:

def update(self):
    newpos=self.rect.move(self.movepos)
    if self.area.contains(newpos):
        self.rect=newpos
    pygame.event.pump()

either use player.rect to get the player position, or update player.pos accordingly:

def update(self):
    newpos=self.rect.move(self.movepos)
    if self.area.contains(newpos):
        self.rect = newpos
        self.pos = self.rect.topleft
        # don't call pygame.event.pump() here. Doesn't make any sense :-)

Third, you update the player position in the update function, but you never call it. Call it before drawing the player:

...
while not done:
    ...
    player.update()
    screen.fill(white)
    screen.blit(player.image, player.pos)
...

You can simplify your code alot by setting movepos directly and removing the move... functions.

working example:

import pygame
pygame.init()
colors = pygame.color.THECOLORS
screen = pygame.display.set_mode([700,400])

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.surface.Surface((32,32))
        self.image.fill(colors['green'])
        self.rect = self.image.get_rect().move(350, 200)
        self.speed = 4

    def update(self):
        dx, dy = self.movepos[0] * self.speed, self.movepos[1] * self.speed
        self.rect = self.rect.move(dx, dy)


done=False
clock = pygame.time.Clock()
player = Player()

while not done:

    if pygame.event.get(pygame.QUIT):
        break

    pressed = pygame.key.get_pressed()
    l, r, u, d = [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s]
    player.movepos = -l + r, -u + d
    player.update()

    screen.fill(colors['white'])
    screen.blit(player.image, player.rect.topleft)
    pygame.display.flip()

    clock.tick(60)


回答2:

You have a lot of move functions. Try combining them into a simple two function class like this example:

class Puck(pygame.sprite.Sprite):
    def __init__(self, image_file, speed, 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

The two main controllers are the self.rect.left and self.rect.top. By changing their values, you can move the sprites like in this example.

#Name of varible# = Puck('#Image File#', [#value of self.rect.left#, value of self.rect.top]

Then you can use events to change them like:

    for event in pygame.event.get():
    if event.type==pygame.QUIT:
        pygame.quit()
        exit(0)
    elif event.type == pygame.KEYDOWN:
        if event.key == K_UP:
            random.rect.top =random.rect.top - 75
        elif event.key == K_LEFT:
            random.rect.left = random.rect.left - 75
        elif event.key == K_DOWN:
            random.rect.top = random.rect.top + 75
        elif event.key == K_RIGHT:
            randoml.rect.left = randoml.rect.left + 75
        elif event.key == K_w:
            random.rect.top = random.rect.top - 50
        elif event.key == K_a:
            random.rect.left = random.rect.left - 50
        elif event.key == K_s:
            random.rect.top = random.rect.top + 50
        elif event.key == K_d:
            random.rect.left = random.rect.left + 50

This should be able to move your sprite.