Page 1 of 1

DragonDePlatino's PyGame Workshop

Posted: Sat Nov 01, 2014 9:40 pm
by DragonDePlatino
Hoo boy, I think I've been struggling silently for long enough, and it's time to reach out for some help.

For the past few years, it's always been a dream of mine to learn game programming. I already know how to draw graphics, compose music and write a story, so programming is my final hurdle for becoming an indie developer. So far, I understand many of the basics of PyGame such as functions and classes, as well as how to do basic math. I've managed to create a screen, draw a character and set up some acceleration-based movement as well as a running. The problem is, I'm having difficulties loading a sprite sheet and extracting individual sprites from that sheet to animate my character.

Attached is a .ZIP file containing my PyGame project so far. Running "Game Old.py" will give you a surface-based graphics engine. The game loads the entire sprite sheet as a giant sprite, and uses that for the character. The player's velocity is also printed once per frame.

It's in "Game.py" where I'm having my problem. I'm trying to create a 32x32 surface for each animation frame using a while loop, but attempting to do this produces a list of empty surfaces. Is there a problem with my while loop? Should I use a for loop like the example shown here?

Re: DragonDePlatino's PyGame Workshop

Posted: Sat Nov 01, 2014 11:20 pm
by Kasumi
Man... so I downloaded this, read some docs about pygame and was pretty sure I was right about why it was happening. However, I didn't have python/pygame installed, and didn't want to make a post with a guess...

One install of pygame later, I was right.

Here's what you've got:

Code: Select all

sheet.set_clip(pygame.Rect(spritesize[0], spritesize[1], scanloc[0], scanloc[1]))
Here's the docs on pygame.Rect
Here's the relevant part:

Code: Select all

Rect(left, top, width, height)
spritesize[0] and spritesize[1] are the width and height, scanloc[0] and scanloc[1] are the left and top of the sprite. You've got them backwards. Replace the above with this:

Code: Select all

sheet.set_clip(pygame.Rect(scanloc[0], scanloc[1], spritesize[0], spritesize[1]))
Edit: So what was happening is that guySheet[0] (the only sprite that's drawn in the current source code), was being created at 32x32 of the file, with a width and height of 0. So... blank sheet.
Edit2: The others (guySheet[1 through 14]) work properly too with the fix, so your loop itself was fine.

Re: DragonDePlatino's PyGame Workshop

Posted: Sun Nov 02, 2014 7:14 am
by DragonDePlatino
Awesome! Thanks a lot! I can't believe you downloaded PyGame and read up on it's documentation just to help me with such a beginner's mistake.

Yeah, it seems this problem has been fixed. I'm getting an output of

Code: Select all

[<Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>, <Surface(32x32x32 SW)>]
So everything looks like it's working. If I end up running into any other struggles I'll go ahead and post them here.

Re: DragonDePlatino's PyGame Workshop

Posted: Wed Nov 05, 2014 9:05 pm
by DragonDePlatino
I've made a lot of progress over the past few days, but now I'm stuck on collision. I've searched the net on how to approach collision, but all existing examples are either:

A) Space shooters which handle collision with booleans. If bullets collide with any part of a sprite, the sprite is removed.
B) Platforming engines which load map data (i.e. "0, 0, 0, 1") and check each frame to see if the player is touching a map tile.

What I'm trying to do here is check for collision between my player sprite and any of the box sprites. If the player touches a box, they should not be able to go inside it. I'll be creating maps later, but for now I want to handle sprite-sprite collisions. Pygame's documentation on sprites gives lots of useful functions like collide_rect and groupcollide, but all of those either output booleans or dictionaries. Booleans aren't specific enough for my purposes and I don't know how to check collisions between sprites in the dictionaries. Could I please have some help doing the latter?

EDIT:

It seems a few people over on the Starmen.net forums have taken a liking to my simple little engine.

Re: DragonDePlatino's PyGame Workshop

Posted: Thu Nov 06, 2014 1:07 am
by Kasumi
Full disclosure: I have never written a Python program ever. In fact, your program is the first Python program I ever even successfully ran. I'm no Python expert, basically. The time investment to learn about python specific stuff is greater for me than finding a problem in logic.

So... just generally there's two parts to collision. Detecting it which is easy. And deciding what to do when you've detected it which is harder. It's not really a language specific problem.

For what to do once you've detected it...

1. A really simple (but not really glitch free) way to do this is to move the player. If they're in a box, put them back where they were before the movement. However, imagine a situation where the player is inside a box at the start of the frame. They'll be unable to move if they're far enough in the box. (They'll attempt to move. Their new position is inside the box, so it puts them back where they were. Which was inside the box. :P )

2. Better is move the player horizontally. If they are inside the box, compare the box's X position with the player's X position. If the player's position is less than the box's, the player is on the left, else the player is on the right. (Edit4: Well uh... really one should use the midpoints, but forget about that for now.)

If the player is on the left, add the player's width to his X position, and subtract the box's X position from this. This will give you how many pixels you need to move the player to the left in order for him to be outside the box. Move them that many pixels left.

If the player is on the right, add the box's width to its X position, and subtract the player's X position from this. This will give you how many pixels you need to move the player to the right for him to be outside the box. Move them that many pixels right.

Then move the player vertically. If they are inside the box do a similar thing, except with Y and height and moving the player up and down.

That approach also has some problems, but gets you an idea.

As for detecting a collision in the first place it looks like you have that solved in a Pygame specific way I don't have time to look up and understand right now. (Apparently I found the time.) From the look of things, at the very least behavior 1 would be very easy to do using groupcollide.

Edit: I have now actually checked. Yes, behavior 1 is easy to do. Though it gets a little wonky because you have acceleration. :P Like I said not a great method. I guess I'll try to figure out how to make 2 work.

Edit2: AH SNAP SON! Got it. This might help get you started. (It also probably has terrible python programming style.) Edit 3: Fixed up the syntax, maybe. I'm starting to get why people like python.

Code: Select all

        if playercollide:
            for i in playercollide[player]:
                print(i.rect.topleft)
The above prints the topleft corner of every box colliding with player. You'll noticed it will print both of the two boxes' top left corners if player is standing on both of the two that are next to each other.

One of the things you'll learn about programming is that things that seem very simple can get very complicated. You can imagine that most games launch with the developers unaware of any ways to get inside walls. If they were aware, they'd fix it! People still find them. When you get good at finding the stupid cases that make things like that possible, you end up writing more and more code to handle those cases. And then you release the game, and you still missed something. :lol:

Blah blah blah... give implementing the logic a try, make a post with a success story or at least what you tried. It may be worth finding a community that specializes in Python or Pygame, though. Not that I mind helping, but I'd be reading docs (and maybe misinterpreting them) mere minutes before making posts rather than working from real experience which is better.

Re: DragonDePlatino's PyGame Workshop

Posted: Sat Nov 08, 2014 3:42 pm
by DragonDePlatino
Awesome, awesome, awesome! After 2 days of work and a lot of frustration, I've finally managed to achieve near pixel-perfect collision detection in only 12 lines of code:

Code: Select all

def collide(player, objectGroup): # Check for collisions between a sprite and a group.
	for sprite in objectGroup:
		if player.hitbox.colliderect(sprite.hitbox):
			if (player.hitbox.bottom - player.speed * 2 < sprite.hitbox.top):
				player.hitbox.bottom = sprite.hitbox.top
			elif (player.hitbox.top + player.speed * 2 > sprite.hitbox.bottom):
				player.hitbox.top = sprite.hitbox.bottom
			elif (player.hitbox.right - player.speed * 2 < sprite.hitbox.left):
				player.hitbox.right = sprite.hitbox.left
			elif (player.hitbox.left + player.speed * 2 > sprite.hitbox.right):
				player.hitbox.left = sprite.hitbox.right
	player.rect.midbottom = player.hitbox.midbottom
I don't have the code for handling layers yet, but I'm really happy with my results here. Thanks for the push in the right direction, Kasumi! Now I'll be able to move on to some of the more fun stuff, like tile maps and player animation. If I have any difficulties with those I'll be asking here. Now that I've gotten a stronger grip on Python's syntax and PyGame's methods, I'll start asking more general game-programming questions instead of Pygame-specific ones.