0

I am working on a simple game. I created a pygame sprite and moved it by adding its rect position with a direction (from wasd input). However, it seems to be moving left and up (where all the directions are negative) quicker than right and down (where all the directions are positive)

Here is the code:

import pygame
from settings import *
from support import import_folder

class Player(pygame.sprite.Sprite):
    def __init__(self, pos, groups,obstacle_sprites,create_attack,destroy_attack,create_magic):
        #for sprites
        super().__init__(groups)
        self.image = pygame.image.load(f'{abs_path}/graphics/test/player.png').convert_alpha()
        self.rect = self.image.get_rect(topleft = pos)
        self.hitbox = self.rect.inflate(0,-26)

        # graphics setup
        self.import_player_assets()
        self.status = 'down'
        self.frame_index = 0
        self.animation_speed = 0.15
        
        #movement
        self.direction = pygame.math.Vector2()
        self.attacking = False
        self.attack_cooldown = 400
        self.attack_time = None

        self.obstacle_sprites = obstacle_sprites

        #weapon
        self.create_attack = create_attack
        self.destory_attack = destroy_attack
        #gets the correct data from weapon dictionary in settings.py also turns keys into list
        self.weapon_index = 0
        self.weapon = list(weapon_data.keys())[self.weapon_index]
        self.can_switch_weapon = True
        self.weapon_switch_time = None
        self.switch_duration_cooldown = 200

        # Magic
        self.create_magic = create_magic
        self.magic_index = 0
        self.magic = list(magic_data.keys())[self.magic_index]
        self.can_switch_magic = True
        self.magic_switch_time = None

        #Stats
        self.stats = {'health': 100, 'energy':60, 'attack': 10, 'magic': 4, 'speed': 5}
        self.health = self.stats['health']
        self.energy = self.stats['energy']
        self.exp = 0
        self.speed = self.stats['speed']


    #For the player animations
    def import_player_assets(self):
        character_path = f'{abs_path}/graphics/player2/'
        self.animations = {'up': [], 'down': [], 'left': [], 'right': [],
            'right_idle': [], 'left_idle': [], 'up_idle': [], 'down_idle': [],
            'right_attack': [], 'left_attack': [], 'up_attack': [], 'down_attack': []}

        for animation in self.animations.keys():
            full_path = character_path + animation
            self.animations[animation] = import_folder(full_path)


    def input(self):
        keys = pygame.key.get_pressed()

        #Movement Input
        #The extra if statement is to make the speed the same even when its going in diagonals, some are set to .8
        #because pygame is wierd

        if not self.attacking:
            if (keys[pygame.K_w] and keys[pygame.K_s]):
                self.direction.y = 0
            elif keys[pygame.K_w]:
                if (keys[pygame.K_a] or keys[pygame.K_d]):
                    self.direction.y = -.7
                else:
                    self.direction.y = -1
                self.status = 'up'
            elif keys[pygame.K_s]:
                if (keys[pygame.K_a] or keys[pygame.K_d]):
                    self.direction.y = .7
                else:
                    self.direction.y = 1
                self.status = 'down'
            else:
                self.direction.y = 0

            if (keys[pygame.K_d] and keys[pygame.K_a]):
                self.direction.x = 0        
            elif keys[pygame.K_d]:
                if (keys[pygame.K_w] or keys[pygame.K_s]):
                    self.direction.x = .7
                else:
                    self.direction.x = 1
                self.status = 'right'
            elif keys[pygame.K_a]:
                if (keys[pygame.K_w] or keys[pygame.K_s]):
                    self.direction.x = -.7
                else:
                    self.direction.x = -1
                self.status = 'left'
            else:
                self.direction.x = 0


            #Attack Input
            #if keys[pygame.K_LSHIFT] and not self.attacking
            if keys[pygame.K_SPACE]:
                self.attacking = True
                self.attack_time = pygame.time.get_ticks()
                self.create_attack()

            #Spell Input
            if keys[pygame.K_LSHIFT]:
                self.attacking = True
                self.attack_time = pygame.time.get_ticks()
                style = list(magic_data.keys())[self.magic_index]
                strength = list(magic_data.values())[self.magic_index]['strength'] + self.stats['magic']
                cost = list(magic_data.values())[self.magic_index]['cost']
                self.create_magic(style, strength, cost)

            #Switch weapons Input
            if keys[pygame.K_q] and self.can_switch_weapon:
                self.can_switch_weapon = False
                self.weapon_switch_time = pygame.time.get_ticks()

                if self.weapon_index < len(list(weapon_data.keys())) - 1:
                    self.weapon_index += 1
                else:
                    self.weapon_index = 0

                self.weapon = list(weapon_data.keys())[self.weapon_index]

            #Switch spells Input
            if keys[pygame.K_e] and self.can_switch_magic:
                self.can_switch_magic = False
                self.magic_switch_time = pygame.time.get_ticks()

                if self.magic_index < len(list(magic_data.keys())) - 1:
                    self.magic_index += 1
                else:
                    self.magic_index = 0

                self.magic = list(magic_data.keys())[self.magic_index]


    def get_status(self):

        #Idle Status:
        if self.direction.x == 0 and self.direction.y == 0:
            if not 'idle' in self.status and not 'attack' in self.status:
                self.status = self.status + '_idle'
        
        if self.attacking:
            self.direction.x = 0
            self.direction.y = 0
            if not 'attack' in self.status:
                if 'idle' in self.status:
                    self.status = self.status.replace('_idle','_attack')
                else:
                    self.status = self.status + '_attack'
                
        else:
            if 'attack' in self.status:
                self.status = self.status.replace('_attack','')


    def move(self, speed):

        #Moving the player feat. collision detection
        self.hitbox.x += self.direction.x * speed
        self.collision('horizontal')
        self.hitbox.y += self.direction.y * speed
        self.collision('vertical')
        self.rect.center = self.hitbox.center

    #Pygame cannot tell if something collides but only if it overlaps
    #So i check for horizontal/vertical movement because it cant tell where it overlaps
    def collision(self, direction):
        if direction == 'horizontal':
            for sprite in self.obstacle_sprites:
                #Checking the hitbox of sprite with hitbox of obstacle
                if sprite.hitbox.colliderect(self.hitbox):
                    if self.direction.x > 0: #checks if player is moving right
                        #moves the right side of player to left side of obstacle
                        self.hitbox.right = sprite.hitbox.left
                    if self.direction.x < 0:
                        #vice versa
                        self.hitbox.left = sprite.hitbox.right
        

        if direction == 'vertical':
            for sprite in self.obstacle_sprites:
                #Checking the hitbox of sprite with hitbox of obstacle
                if sprite.hitbox.colliderect(self.hitbox):
                    if self.direction.y > 0: #checks if player is moving down
                        #moves the bottom side of player to top side of obstacle
                        self.hitbox.bottom = sprite.hitbox.top
                    if self.direction.y < 0: #move up
                        #vice versa
                        self.hitbox.top = sprite.hitbox.bottom

    #Cooldown function so people cant spam attacks
    def cooldowns(self):
        current_time = pygame.time.get_ticks()

        if self.attacking:
            if current_time - self.attack_time >= self.attack_cooldown:
                self.attacking = False
                self.destory_attack()

        if not self.can_switch_weapon:
            if current_time - self.weapon_switch_time >= self.switch_duration_cooldown:
                self.can_switch_weapon = True

        if not self.can_switch_magic:
            if current_time - self.magic_switch_time >= self.switch_duration_cooldown:
                self.can_switch_magic = True
                

    #Loop the images to make moving sprites
    def animate(self):
        #Goes into the image dictionary and puts player status as key, the animation = the item
        animation = self.animations[self.status]

        #loop over frame index
        self.frame_index += self.animation_speed
        if self.frame_index >= len(animation):
            self.frame_index = 0

        #Set the image
        self.image = animation[int(self.frame_index)]
        self.rect = self.image.get_rect(center = self.hitbox.center)




    def update(self):
        self.input()
        self.cooldowns()
        self.get_status()
        self.animate()
        self.move(self.speed)
Sehwab
  • 1
  • Since [`pygame.Rect`](https://www.pygame.org/docs/ref/rect.html) is supposed to represent an area on the screen, a `pygame.Rect` object can only store integral data. Since a floating point number is truncated when stored as an integer, it appears to move faster in the negative direction (left and up). – Rabbid76 Jan 16 '23 at 05:42

0 Answers0