jerky sprite movement

jerky sprite movement

Postby dboxall123 » Mon Aug 12, 2013 12:58 pm

Hello everyone! I've just found an example of a very basic side-scroller that just has 2 sets of platforms and a little square that jumps around. Now that I konw how, I can expand on this and make my level bigger. Before I do this though, there is an issue that needs addressing. When my little box sprite is on a platform, his movement is very jerky, and I don't really know how to fix it. I thought that perhaps I've typed something wrong but I've checked and double checked it with the example and I can't find anything wrong with it. I figured that as this was on a tutorial website (www.programarcadegames.com) that it would be all good, but it's horrible! Here is the code I have:

Code: Select all
import pygame as pg
import os

black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
blue = (0,0,255)

class Platform(pg.sprite.Sprite):
    def __init__(self,color,width,height):
        pg.sprite.Sprite.__init__(self)

        self.image = pg.Surface([width,height])
        self.image.fill(color)
        self.rect = self.image.get_rect()


class Player(pg.sprite.Sprite):
    change_x = 0
    change_y = 0

    jump_ready = False
    frame_since_collision = 0
    frame_since_jump = 0

    def __init__(self,x,y):
        pg.sprite.Sprite.__init__(self)

        self.image = pg.Surface([15,15])
        self.image.fill(red)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def change_speed_x(self,x):
        self.change_x = x

    def change_speed_y(self,y):
        self.change_y = y

    def update(self,blocks):
        old_x = self.rect.x
        new_x = old_x + self.change_x
        self.rect.x = new_x

        collide = pg.sprite.spritecollide(self,blocks,False)
        if collide:
            self.rect.x = old_x

        old_y = self.rect.y
        new_y = old_y + self.change_y
        self.rect.y = new_y

        block_hit_list = pg.sprite.spritecollide(self,blocks,False)
        for block in block_hit_list:
            self.rect.y = old_y
            self.rect.x = old_x

            self.change_y = 0
            self.frame_since_collision = 0

        if self.frame_since_collision < 6 and self.frame_since_jump < 6:
            self.frame_since_jump = 100
            self.change_y -= 8

        self.frame_since_collision += 1
        self.frame_since_jump += 1

    def calc_grav(self):
        self.change_y += .35

        if self.rect.y >= 485 and self.change_y >= 0:
            self.change_y = 0
            self.rect.y = 485
            self.frame_since_collision = 0

    def jump(self,blocks):
        self.jump_ready = True
        self.frame_since_jump = 0


pg.init()
size = [700,500]
os.environ['SDL_VIDEO_CENTERED'] = '1'
screen = pg.display.set_mode(size)

def create_level_1(block_list,all_sprites_list):

    for x in range(-600,1500,200):
        block = Platform(white,100,20)
        block.rect.x = x
        block.rect.y = 420
        block_list.add(block)
        all_sprites_list.add(block)

    for x in range(-500,1500,300):
        block = Platform(blue,100,20)
        block.rect.x = x
        block.rect.y = 340
        block_list.add(block)
        all_sprites_list.add(block)

block_list = pg.sprite.Group()
all_sprites_list = pg.sprite.Group()
create_level_1(block_list,all_sprites_list)

player = Player(20,15)
player.rect.x = 340
player.rect.y = 485
all_sprites_list.add(player)

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

while not done:
    for event in pg.event.get():

        if event.type == pg.QUIT:
            done = True

        if event.type == pg.KEYDOWN:
            if event.key == pg.K_LEFT:
                player.change_speed_x(-6)
            if event.key == pg.K_RIGHT:
                player.change_speed_x(6)
            if event.key == pg.K_UP:
                player.jump(block_list)
            if event.key == pg.K_DOWN:
                player.change_speed_y(6)

        if event.type == pg.KEYUP:
            if event.key == pg.K_LEFT:
                player.change_speed_x(-0)
            if event.key == pg.K_RIGHT:
                player.change_speed_x(0)

    if player.rect.x >= 500:
        diff = player.rect.x - 500
        player.rect.x = 500
        for block in block_list:
            block.rect.x -= diff

    if player.rect.x <= 120:
        diff = 120 - player.rect.x
        player.rect.x = 120
        for block in block_list:
            block.rect.x += diff

    player.calc_grav()
    player.update(block_list)
    block_list.update()

    screen.fill(black)
    all_sprites_list.draw(screen)

    clock.tick(40)
    pg.display.flip()
   

pg.quit()


Try it out, it's horrible isn't it? Does anyone know how to make my little sprite move smoothly when he's on the platforms? I can't make a game with my hero jerking around on every platform he's on, it would be terrible. Any advice would be much appreciated.
Thanks!

Dan
dboxall123
 
Posts: 109
Joined: Fri Jul 12, 2013 5:28 pm

Re: jerky sprite movement

Postby Mekire » Mon Aug 12, 2013 1:24 pm

http://python-forum.org/viewtopic.php?f=26&t=5341

Tired of this guy's "examples". I recommend you don't use that site. Especially as this exact question was just asked recently. There are two ways to do this. If only ever colliding with rectangular objects you can, on collision, set the player's rect to the wall that he collides with.

i.e. if the player was falling and hit a platform below him, you would:
Code: Select all
player.rect.bottom = block.rect.top
and similar for all other directions.

This however is a dirty way to do it. If you start using mask collision, this won't work, and you will have to check collisions in a while loop decrementing by one pixel at a time until clear.

Check out fall_rect.py for rectangle collision and fall_mask.py for mask collision:
https://github.com/Mekire/meks-pygame-samples/tree/master/platforming

-Mek

Edit:
Oh yeah. And this one is a work in progress but here is a sidescroller with slopes:
https://github.com/Mekire/platformer-with-slopes
User avatar
Mekire
 
Posts: 1018
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: jerky sprite movement

Postby dboxall123 » Mon Aug 12, 2013 2:58 pm

Wow, I didn't realise that his examples were that bad lol. When I first found the website, I clicked on the link that leads to 'aout the author' and saw that he was a professor so figured it would be quite good. This isn't the only 'example' that I've had trouble with neither. There was another one which just showed how to make a wall that a sprite cannot pass through, but when you move the sprite towards the wall, because it's moving 3 pixels at a time, there is a visible gap when the sprite colides with the wall. Not very good at all lol. I will copy your example and have a mess around with that, see if I can understand it. Thanks Mek!

Dan

ps: do you know of any better tutorials? And also, do you know of any tutorials that cover the use of tiles? I'd quite like to try to make a map with tiles. Thanks again!
dboxall123
 
Posts: 109
Joined: Fri Jul 12, 2013 5:28 pm

Re: jerky sprite movement

Postby Mekire » Wed Aug 14, 2013 8:17 am

Honestly there are tons of people out there "writing tutorials" that are just awful. I can't think of any at the moment that are actually decent. The problem is that the way to get the most visibility is to promise the world. Because of this you don't often see Pygame tutorials aimed at people that already know python. They are all written for (and far to often by) people that have just started to learn to program. In my opinion this is the wrong approach. Effective game programming--be it with Pygame or anything else--requires an Object Oriented approach. Pretending anything otherwise is not helpful to anyone.

There are certain cardinal sins that you can look out for though when trying to pick a good tutorial.

If the author does any of the following, just walk away:
  • Uses star imports of any kind.
  • Uses global variables of any kind (global CONSTANTS are fine).
  • Codes there main game loop in the global namespace.
  • Doesn't separate the event loop into its own function
  • Has multiple game loops or multiple event loops.
  • Uses the global keyword (there are cases where this is acceptable but most people who do it, do it for the wrong reason).
  • Shows basic errors like using repeated ifs in a block where elifs are indicated.

If you download and go through all the examples in my example repo in detail you should get a fairly good idea of the basics of Pygame. And will be better suited to ask questions when you do encounter things you don't understand.

The approximate order of difficulty is:
  • color_change.py
  • drag_text.py
  • eight_dir_move.py
  • punch_a_hole
  • resizable
  • tank_turret
  • four_direction_movement
  • topdown_scrolling
  • platforming

For working with tiles you basically have two options. Write your own; or use someone else's tile loading library. I always write my own though (which I highly recommend as an exercise) so I can't really comment on tile loaders.

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

Re: jerky sprite movement

Postby dboxall123 » Wed Aug 14, 2013 9:59 am

Cool cheers Mek. Do you know that every single tutorial I've looked at includes at least one of the cardinal sins? Lol, you'd think that somebody would have made a decent tutorial. Oh well, Ive got your examples so I can play around with them and see what's going on. As for writing my own tile loader, I'd like to be able to do that, but I really don't thin I could. I looked at Richard Jones TMX loader (it's Python 2.7 so it's no good to me anyway) and honestly, I think that it's way beyond me. But, who knows, maybe with some reading I'll be able to.
Thanks Mek
Dan
dboxall123
 
Posts: 109
Joined: Fri Jul 12, 2013 5:28 pm


Return to Game Development

Who is online

Users browsing this forum: No registered users and 1 guest