[pygame] help inconsistent character movement velocity

[pygame] help inconsistent character movement velocity

Postby Pedro H. Forli » Thu Aug 01, 2013 2:27 am

Hello! I'm a noob at python and pygame, also forgive for possible english mistakes, i'm actually from Brasil.
I'm creating a plataform game using tilemaps and loading it with Richard's Jones tmx library, and i have come across a "bug":
When i'm moving my character around, he goes faster to the left and down directions.
First, i thought it was an error with my code, but after making differents test's using 20-scenes.py, written by Richard Jones, i've realized that this problem ocurrs with his game. If you press both the left and the right arrows together you will see that the caracter has the tendency of going left, also all the objects (Bullet, enemy, Player...) can't have a speed bellow 20 pixels/second (in my game, you can't set a speed bellow 31 pixels/second) otherwize it can't move to the right direction.
What is the source of the problem? How do i fix it?

Here is richard Jones source code:
https://bitbucket.org/r1chardj0n3s/pyga ... at=default

And here is the code of my enemy object:

Code: Select all
import pygame, random
from pygame.locals import *
from Funsoes import *
import resources

class Enemy(pygame.sprite.Sprite):
    def __init__(self, location, name, *groups):
        super(Enemy, self).__init__(*groups)

        self.type = 'Enemy'
       
        self.AllDirection = {'Down': 0, 'Right': 1, 'Up': 2, 'Left': 3}
        self.All = {'Lesma': (16, 12, -2, -5, 1, 20)}

        self.nome = name

        self.originalPosition = location

        self.direction = 'Down'
        self.number_of_sprite = 0

        self.spritesheet = load_sheet('%s.png'%name,'Imagens',
                                      self.All[name][0], self.All[name][1])

        self.image = self.spritesheet[self.AllDirection[self.direction]][self.number_of_sprite]
        self.rect = pygame.rect.Rect(location, self.image.get_size())

        self.deadImage = pygame.image.load(resources.file_path('%sdead.png'%name, 'Imagens')).convert_alpha()

        self.collisionRect = pygame.rect.Rect(self.rect.x + self.All[name][2],
                                             self.rect.y + self.All[name][3], 12, 5)

        self.life = self.All[name][4]
        self.vida = self.life

        self.Max = len(self.spritesheet[0])

        self.vy = self.All[name][5]
        self.vx = 0

        self.mask = pygame.mask.from_surface(self.image)

        self.alive = True
        self.atking = False

        self.cont = 0

    def update(self, dt, Game):
        if not Game.Pause:

            if self.alive:
                last = self.collisionRect.copy()

                self.vx = self.vy = 0

                if self.cont >= 4*dt:
                    self.number_of_sprite += 1
                    self.cont = 0

                if self.number_of_sprite == self.Max:
                    self.direction = random.choice(['Right', 'Up','Down', 'Left'])
                    self.number_of_sprite = 0

                if self.direction == 'Down':
                    self.vy = 31
                elif self.direction == 'Up':
                    self.vy = (-1)*self.All[self.nome][5]
                elif self.direction == 'Right':
                    self.vx = 31
                else:
                    self.vx = (-1)*self.All[self.nome][5]


                self.collisionRect.centerx += self.vx * dt
                self.collisionRect.centery += self.vy * dt

                new = self.collisionRect
                for cell in Game.tilemap.layers['triggers'].collide(new, 'block'):
                    blockers = cell['block']
                    if 'l' in blockers and last.right <= cell.left and new.right > cell.left:
                        new.right = cell.left
                    if 'r' in blockers and last.left >= cell.right and new.left < cell.right:
                        new.left = cell.right
                    if 't' in blockers and last.bottom <= cell.top and new.bottom > cell.top:
                        new.bottom = cell.top
                    if 'b' in blockers and last.top >= cell.bottom and new.top < cell.bottom:
                        new.top = cell.bottom
               
                self.rect.left = new.left - 2
                self.rect.top = new.top - 5

                self.cont+= dt
                self.image = self.spritesheet[self.AllDirection[self.direction]][self.number_of_sprite]
                self.mask = pygame.mask.from_surface(self.image)

            else:
                if self.cont >= 2*dt:
                    self.number_of_sprite += 1
                    self.cont = 0
                if self.number_of_sprite == self.Max:
                    self.kill()
                    for sprite in Game.sprites:
                        if sprite.type == 'Player':
                            sprite.placedPositions.remove(self.originalPosition)
                            break

                self.cont += dt
               
               
    def draw(self, Surface):
        Surface.blit(self.image, self.rect)
        if not self.alive:
            Surface.blit(self.spritesheet[0][self.number_of_sprite], (self.rect.x, self.rect.y - 8))


Also, i kind of modified the tmx library a bit(only the draw method in the SpriteLayer object):

Code: Select all
class SpriteLayer(pygame.sprite.AbstractGroup):
    def __init__(self):
        super(SpriteLayer, self).__init__()
        self.visible = True

    def set_view(self, x, y, w, h, viewport_ox=0, viewport_oy=0):
        self.view_x, self.view_y = x, y
        self.view_w, self.view_h = w, h
        x -= viewport_ox
        y -= viewport_oy
        self.position = (x, y)

    [b]def draw(self, screen):
        ox, oy = self.position
        w, h = self.view_w, self.view_h
        OrderedSprites = OrderSprites(self.sprites())
        for sprite in OrderedSprites:
            sx, sy = sprite.rect.topleft
            screen.blit(sprite.image, (sx-ox, sy-oy))[/b]


The OrderedSprites function:

Code: Select all
def OrderSprites(spriteGroup):
    OrderedSprites = []
    Sprites = spriteGroup
    cont = len(spriteGroup)
   
    while len(OrderedSprites) < cont:
        MaxY = 0
        for sprite in Sprites:
            if sprite.rect.bottom > MaxY:
                MaxY = sprite.rect.bottom
                chosed = sprite
        OrderedSprites.append(chosed)
        Sprites.remove(chosed)

    OrderedSprites.reverse()

    return OrderedSprites
Last edited by Pedro H. Forli on Thu Aug 01, 2013 3:21 am, edited 1 time in total.
Pedro H. Forli
 
Posts: 14
Joined: Thu Aug 01, 2013 1:50 am

Re: [pygame] TMX

Postby metulburr » Thu Aug 01, 2013 3:11 am

to be honest, once i saw your code *not* in code tags, i didnt even read your first few paragraphs, ill read them when i see that you added code tags, check my signature for new users info on code tags.
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1476
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [pygame] TMX

Postby Pedro H. Forli » Thu Aug 01, 2013 3:25 am

metulburr wrote:to be honest, once i saw your code *not* in code tags, i didnt even read your first few paragraphs, ill read them when i see that you added code tags, check my signature for new users info on code tags.

Thank you. Didn't know about the existence of this tool.
Pedro H. Forli
 
Posts: 14
Joined: Thu Aug 01, 2013 1:50 am

Re: [pygame] TMX

Postby Mekire » Thu Aug 01, 2013 4:26 am

Well I have never bothered with TMX as usually write a tile loader to fit my own needs but...

The problem with the player favoring left when pressing both left and right sounds like it is just part of your key/event handling. I handle this by creating a list of direction keys as they are pressed and popping the key from the list when it is released. The player's direction is always the last element of the list. The minimum speed thing sounds like a rect issue. Rects can only hold integers, so if you add a fractional amount directly to the rectangle coordinates, it will be truncated/ignored. If you require speeds that would entail your location to get changed by fractional pixels, you will have to store the data in another object that can hold floats (probably just a list).

-Mek
User avatar
Mekire
 
Posts: 988
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [pygame] TMX

Postby Pedro H. Forli » Thu Aug 01, 2013 12:57 pm

Mekire wrote:The problem with the player favoring left when pressing both left and right sounds like it is just part of your key/event handling.

That's why i posted my enemy object, to show that the problem has nothing to do with key/event handling

Mekire wrote:The minimum speed thing sounds like a rect issue. Rects can only hold integers, so if you add a fractional amount directly to the rectangle coordinates, it will be truncated/ignored. If you require speeds that would entail your location to get changed by fractional pixels, you will have to store the data in another object that can hold floats (probably just a list).

Yeah, that would explain it, if it wasn't for the fact that to the left and down directions the minimum speed acctually is 21 pixel/second. Another thing is that doesn't matter the speed, the objects go faster to the left and down directions aniway
Pedro H. Forli
 
Posts: 14
Joined: Thu Aug 01, 2013 1:50 am

Re: [pygame] TMX

Postby Mekire » Thu Aug 01, 2013 2:29 pm

Look:
Code: Select all
>>> import pygame
>>> rect = pygame.Rect(50,50,200,200)
>>> rect.x -= 3.25
>>> rect.x += 3.25
>>> rect.x
49
We've moved backwards.

Rects int everything you give them so if you add and subtract the same float, you don't get the number you started with.
That is why this doesn't work right:
Code: Select all
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
    self.rect.x -= 300 * dt
    self.image = self.left_image
    self.direction = -1
if key[pygame.K_RIGHT]:
    self.rect.x += 300 * dt
    self.image = self.right_image
    self.direction = 1

I suspect your moving faster in one direction and having a certain minimum speed are for similar reasons.

In the above code the dt argument is equal to 0.033. Look:
Code: Select all
>>> 31*0.033
1.0230000000000001
>>> 30*0.033
0.99
31 pixels a second still yields a value over 1 so you can still add it to the rect. 30 pixels per second however yields a value under 1. If you try and change a rect coordinate by a fraction of a pixel in one direction, it won't change. In the other it will.

ie:
Code: Select all
>>> int(50+0.99)
50
>>> int(50-0.99)
49
This same effect for larger pixel per second values acounts for the differences in speed when moving in certain directions.

-Mek
User avatar
Mekire
 
Posts: 988
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [pygame] TMX

Postby Pedro H. Forli » Thu Aug 01, 2013 5:14 pm

Thank you Mek, now the game is working just fine
Pedro H. Forli
 
Posts: 14
Joined: Thu Aug 01, 2013 1:50 am


Return to Game Development

Who is online

Users browsing this forum: Google [Bot] and 2 guests