6
\$\begingroup\$

I'm trying to create a simple top-view 2D rpg, in the style of Zelda and Secret of Mana, using PyGame. I've managed to make the beginnings of a game, with an animated character walking around. However, when I start animating attacks, I'm running into problems because the sprite with the sword slash is bigger than the walking sprite. This makes the character appear to be jumping around when attacking.

I managed to handle the problem by defining a center of gravity, so to speak, for each image, and apply a suitable offset at each frame in the animation to make the center of the character stay at the same place throughout the animation. I defined a dictionary of lists of images (instances of pygame.Surface), where I pick out the correct list by the state of the character, so for example there is one list for walking left, and then I loop over the list to get the animation. To handle the offset, I similarly created a dictionary of lists of offsets, looping over those in the same way.

However, I'm not entirely pleased with this implementation, so I'm looking for a more elegant solution.

I tried to add an attribute called offset to each instance of the pygame.Surface class, to hold the offset for each image, but the Surface class doesn't allow new attributes to be set. I then thought about subclassing pygame.Surface, which would allow me to set any attribute I wanted, but then I couldn't load my images with pygame.image.load without a lot of extra code.

I imagine everyone who makes a game with animations where the size of the sprite changes between frames would have to deal with this problem, so if anyone could suggest an elegant implementation, that would be great. If example code with PyGame is available, that would be even greater.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ One option would be to change all of the animation images to the same size as the biggest one and re-position every sprite to be in the centre in order to avoid a "jumping" effect. \$\endgroup\$
    – Savlon
    Commented Jan 27, 2013 at 22:52
  • \$\begingroup\$ @Savlon I thought about that, and it might be a good solution, but it would introduce some extra problems regarding rects and collision detection, I guess. \$\endgroup\$
    – Tor
    Commented Jan 28, 2013 at 7:08
  • 3
    \$\begingroup\$ Yeh It would if you were using the dimensions of the actual image file... When I do animations I have them on a spritesheet of 32x32 size tiles. However, instead of using the image file dimensions, I create a custom bounding box for my NPC's etc if they are smaller than the actual image file size. Why dont you do that? Just create custom collision boxes after repositioning all of the sprites? \$\endgroup\$
    – Savlon
    Commented Jan 28, 2013 at 7:34
  • \$\begingroup\$ You already have the best possible solution for a flexible width. You could only simplify it by sacrificing flexibility, for example by saying "All walking frames will be this big and all fighting sprites that big" \$\endgroup\$
    – API-Beast
    Commented Apr 14, 2014 at 21:39

2 Answers 2

2
\$\begingroup\$

Imagine the worst case scenario, a fighting game where each moves' frames are different in size. Some kicks have an exceptionally far reach and some even further (think Dhalsim)

enter image description here

The bounding box may be very different in each frame and so are the frame's size and the relative position point. There is no mystic way to do it. Normally to handle complex sprites' animations, one of the teams' members uses a tool to define a bounding rectangle around each frame and place a relative positioning dot in each frame. This data is saved to an xml file often but is created with a specialized tool.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ TexturePacker is such a specialized Tool, free and very flexible in terms of packing algorithms used and output files \$\endgroup\$ Commented Apr 15, 2014 at 6:59
  • \$\begingroup\$ I like Tiled (mapeditor.org) for this kind of thing too. You can use an image-layer for the sprite-sheet an object-layers for collision polygons/rects/circles etc and another one to place handles indicating the center of the sprite. \$\endgroup\$ Commented Apr 15, 2014 at 9:34
1
\$\begingroup\$

I'm kinda late, but I was having the same problem, so yesterday I made a tool that tries to handle the case of the accepted answer (it identifies each rectangle in each animation line, then sorts then by line, so you can use the output to create a list of rectangles for each frame of each animation in each sprite sheet, instead of marking the rectangles manually), it still needs some work tough, seems to break with large files, and it doesn't handle non black background yet...

https://gitlab.com/pedroga/way-of-the-fist/-/blob/master/tools/frame-identifier/identify.cpp

I'll be improving it as need arises, but feel free to modify it to suit your needs.

Example output:

Line 0: {.x = 19, .y = 22, .w = 62, .h = 100} {.x = 90, .y = 22, .w = 63, .h = 100} {.x = 162, .y = 19, .w = 67, .h = 103} {.x = 237, .y = 18, .w = 70, .h = 103} {.x = 316, .y = 22, .w = 64, .h = 100} {.x = 389, .y = 22, .w = 61, .h = 100} {.x = 459, .y = 22, .w = 61, .h = 100} {.x = 529, .y = 22, .w = 61, .h = 100} {.x = 599, .y = 22, .w = 61, .h = 100} {.x = 664, .y = 28, .w = 68, .h = 94}

Line 1: {.x = 15, .y = 141, .w = 63, .h = 89} {.x = 80, .y = 136, .w = 70, .h = 93} {.x = 154, .y = 135, .w = 68, .h = 95} {.x = 232, .y = 134, .w = 59, .h = 95} {.x = 306, .y = 135, .w = 54, .h = 94} {.x = 374, .y = 136, .w = 56, .h = 93} {.x = 438, .y = 141, .w = 63, .h = 89} {.x = 507, .y = 136, .w = 61, .h = 93} {.x = 575, .y = 135, .w = 54, .h = 94} {.x = 643, .y = 134, .w = 54, .h = 95}

Line 2: ...

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .