Jon Fillip
Jon Fillip

Reputation: 103

Pygame Sprite Movement glitch

I'm working on a pygame project but I'm having a few complications with the character's movement. The animation is not in sync (in lame terms), when I move right or left there is suppose to be an animation of the character moving left or right smoothly but in my case when the is moving either left or right I can still see the character image for when the character is in an idle position trailing the character when in walking motion. I also have an issue when my character jumps it doesn't come back own. I tweaked the character speed and refresh rate of the screen but nothing seems to help. Here is my code and image below.

File 1. Handles the running of the game

import sys
import os
import pygame
from game_settings import GameSettings
from knight import Knight


class AlienApocalypse:
    """Overall class to manage game assets and behaviour"""

    def __init__(self):
        """Initialize the game and create game resources"""
        self.walking_step = 6
        pygame.init()
        self.settings = GameSettings()
        # Set up a clock that regulates the FPS of the game window
        self.clock = pygame.time.Clock()
        self.settings.vertical_momentum = 0

        drivers = ['directfb', 'fbcon', 'svgalib']

        found = False
        for driver in drivers:
            if not os.getenv('SDL_VIDEODRIVER'):
                os.putenv('SDL_VIDEODRIVER', driver)
            try:
                pygame.display.init()
            except pygame.error:
                print('Driver: {0} failed.'.format(driver))
                continue
            found = True
            break

        if not found:
            raise Exception('No suitable video driver found!')

        self.screen_window = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))
        pygame.display.set_caption("Alien Apocalypse")

        """Setting background color"""
        self.background_color = (0, 0, 255)

        self.knight = Knight(self)

    def run_game(self):
        """Start the main loop for the game"""
        while True:
            self.clock.tick(27)
            self._check_events()
            self.knight.update()
            self._update_screen()

    def _check_events(self):
        """Respond to key presses and mouse events."""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_event(event)

            elif event.type == pygame.KEYUP:
                self._check_keyup_event(event)

    def _check_keydown_event(self, event):
        """Respond to KEYDOWN presses"""
        if event.key == pygame.K_RIGHT:
            self.knight.moving_right = True
        elif event.key == pygame.K_LEFT:
            self.knight.moving_left = True
        elif event.key == pygame.K_SPACE:
            self.knight.jump_move = True
        elif event.key == pygame.K_q:
            sys.exit()

    def _check_keyup_event(self, event):
        """Respond to KEY releases"""
        if event.key == pygame.K_RIGHT:
            self.knight.moving_right = False
        elif event.key == pygame.K_LEFT:
            self.knight.moving_left = False
        elif event.key == pygame.K_SPACE:
            self.knight.jump_move = False

    def _update_screen(self):
        # Redraw the screen during each pass through the loop.
        self.screen_window.fill(self.settings.background_color)
        self.knight.blitme()

        # Make the most recently drawn screen visible.
        pygame.display.flip()
        self.clock.tick(60)


if __name__ == "__main__":
    """Make a game instance, and run the game"""
    ap = AlienApocalypse()
    ap.run_game()

File2. Handles the game settings

class GameSettings:
    """This class stores all the game settings"""

    def __init__(self):
        """Initialize the game's settings attributes"""
        # Screen settings
        self.screen_width = 1200
        self.screen_height = 800
        self.background_color = (0, 0, 255)
        self.vertical_momentum = 0

        # Knight settings
        self.knight_speed = 2.5

        # Bullet/Sword settings
        self.bullet_speed = 1.0
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (255, 60, 60)

File 3. Handles the settings and attributes for my game character

import pygame
from pygame.sprite import Sprite


class Knight:
    """A class that manages the character knight"""

    def __init__(self, ap_game):
        """Initialize the knight and set its starting position."""
        self.neg = 0
        self.screen_window = ap_game.screen_window
        self.settings = ap_game.settings
        self.screen_window_rect = ap_game.screen_window.get_rect()

        # Load images for character walking movement
        self.walk_left = [
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left1.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left2.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left3.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left4.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left5.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/walk_left/walk_left6.bmp")
        ]
        self.walk_right = [
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk1.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk2.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk3.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk4.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk5.bmp"),
            pygame.image.load("/Users/username/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free"
                              "-pixel-art-game-heroes/PNG/Knight/Walk_right/walk6.bmp")
        ]

        # Load the character - Knight knight_idle and get its rect.
        image_file = "/Users/user/Desktop/alien_apocalypse/craftpix-891165-assassin-mage-viking-free-pixel-art" \
                     "-game-heroes/PNG/Knight/Idle/idle1.bmp"

        self.knight_idle = pygame.image.load(image_file)
        self.rect = self.knight_idle.get_rect()

        # Start each new character at the center of the screen.
        self.rect.center = self.screen_window_rect.center

        # Store the decimal value for the knight's horizontal position.
        self.x = float(self.rect.x)
        # Store the decimal value for the `knight's vertical position.
        self.y = float(self.rect.y)

        # Movement flag
        self.moving_right = False
        self.moving_left = False
        self.jump_move = False
        self.walk_count = 0
        self.jump_count = 10

    def update(self):
        """Update the knight's position based on the movement flag."""
        # Update the knight's x value, not the rect
        if self.moving_right and self.rect.right < self.screen_window_rect.right:
            self.x += self.settings.knight_speed

        if self.moving_left and self.rect.left > 0:
            self.x -= self.settings.knight_speed

        if self.jump_move:
            if self.jump_count >= -10:
                self.neg = 1
                if self.jump_count < 0:
                    self.neg = -1
                self.y -= (self.jump_count ** 2) * 0.5 * self.neg
                self.jump_count -= 1
            else:
                self.jump_count = 10

        # Update rect object from self.x.
        self.rect.x = self.x
        # Update rect object from self.y.
        self.rect.y = self.y

    def blitme(self):
        """Draw the character at its current location."""
        self.screen_window.blit(self.knight_idle, self.rect)
        if self.walk_count + 1 >= 18:
            self.walk_count = 0
        if self.moving_left:
            self.screen_window.blit(self.walk_left[self.walk_count // 3], self.rect)
            self.walk_count += 1

        elif self.moving_right:
            self.screen_window.blit(self.walk_right[self.walk_count // 3], self.rect)
            self.walk_count += 1
        else:
            self.screen_window.blit(self.knight_idle, self.rect)

Images of game window when the character walks left or right: character walking left

character walking left

Upvotes: 3

Views: 602

Answers (1)

Rabbid76
Rabbid76

Reputation: 210968

but in my case when the is moving either left or right I can still see the character image for when the character is in an idle position trailing the character when in walking motion.

This because the first what you do in Knight.blitme, is to draw the character in idle position. Then the left or right images is draw on top of it:

class Knight:
    # [...]

        def blitme(self):
        """Draw the character at its current location."""

        # self.screen_window.blit(self.knight_idle, self.rect) <------ DELETE

        if self.walk_count + 1 >= 18:
            self.walk_count = 0
        if self.moving_left:
            self.screen_window.blit(self.walk_left[self.walk_count // 3], self.rect)
            self.walk_count += 1
        elif self.moving_right:
            self.screen_window.blit(self.walk_right[self.walk_count // 3], self.rect)
            self.walk_count += 1
        else:
            self.screen_window.blit(self.knight_idle, self.rect)


I also have an issue when my character jumps it doesn't come back

Jumping works only if the key is hold down, because jumping is canceled by _check_keyup_event.

Remove self.knight.jump_move = False from _check_keyup_event:

def _check_keyup_event(self, event):
    """Respond to KEY releases"""
    if event.key == pygame.K_RIGHT:
        self.knight.moving_right = False
    elif event.key == pygame.K_LEFT:
        self.knight.moving_left = False

    # DELETE
    #elif event.key == pygame.K_SPACE:
    #    self.knight.jump_move = False

But do it when the jump is finished:

class Knight:
    # [...]

    def update(self):
        # [...]

         if self.jump_move:
            if self.jump_count >= -10:
                self.neg = 1
                if self.jump_count < 0:
                    self.neg = -1
                self.y -= (self.jump_count ** 2) * 0.5 * self.neg
                self.jump_count -= 1
            else:
                self.jump_count = 10
                self.jump_move = False # <------

Upvotes: 4

Related Questions