Pygame, trying to rotate sprite - python

I'm trying to rotate of sprite for my game written in pygame
I don't get any consol error, but my sprite stay exactly the same and doesn't rotate :(
Any idea ?
perso.image = pygame.image.load("sprites/[shadow]main_char_sprite.png").convert_alpha()
perso.image = pygame.transform.scale(perso.image, (53,60))
perso.rect = perso.image.get_rect()
perso.rect.x = 200
perso.rect.y = 200
perso.add(perso_group)
while 1:
screen.fill(white)
pygame.transform.rotate(perso.image,30) ########not working :(
all_group.add(statique_group, zombie_group, perso_group)
all_group.draw(screen)
pygame.display.flip()

The documentation for the transform functions says:
All these functions take a Surface to operate on and return a new Surface with the results.
So you need to assign the return value of rotate to the variable:
perso.image = pygame.transform.rotate(perso.image,30)
However, the documentation also says:
Some of the transforms are considered destructive. These means every time they are performed they lose pixel data. Common examples of this are resizing and rotating. For this reason, it is better to retransform the original surface than to keep transforming an image multiple times.
So you may want to keep the original, and keep increasing the rotation angle instead.

Related

How to speed up or optimize for loop used for collision detection using pygame/pytmx?

I am using a for loop combined with .colliderect() for collision detection while attempting to make a game using pygame, the loop gets too slow with ~340 wall Rectangles, I was wondering if it could be faster somehow because it severely effects the game play loop?
I have tried using coordinate points on different places on every wall but only works if you're moving certain amounts of pixels at a time and every time you half the movement speed it quadruples the amount of coordinate points you save.
#disregard indent, this is all in an update function that is called every time that a player decides to move.
self._old_position = self.position
PlayerRectangle = pygame.Rect(self.position[0]+ x,self.position[1]+y,16,16)
cwd = os.getcwd()
tmxData = load_pygame(cwd+"\\Maps\\TestfileMap.tmx")
movement = True
for obj in self.walls:
if(pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)):
movement = False
self.move_back()
else:
continue
if movement:
self.position[0] += x
self.position[1] += y
self.stats["position"]=self.position
self.rect.topleft = self.position
self.feet.midbottom = self.rect.midbottom
The provided code works, however it is too slow, I was wondering if there is a different method in collision detection or if there is a way to make what is shown faster, it bogs down things greatly. Thank you
EDIT:
So the solution was basically that I had load_pygame that ran literally every time it looped simply take out the line that does that and it clears things up a lot more, for further optimization change the line that makes a Rect for each object and just use a list of Rects that are already constructed, this limits function calls.
Without a minimal working example it is tough to give assertive advice.
As I stated in the comments, there is a spurious call to a "load_pygame" function that seems to read file data inside this code - that alone could be the cause of your slowdown. Moreover, the data read is not used in the collision detection.
The other advice I't have is to let your walls rectangles pre-calculated in a sprite group, instead of creating new rectangles for all walls in every check with:
pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)). then you can use the sprite method "spritecollideany" - https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollideany - that should optimize the rectangle-collision verification.
(This will also require your Player object to be a Sprite if it is not already).

What do ".subsurface()", ".convert_alpha()", and "%" do?

I'm trying to learn Pygame, and the tutorial that I am following has a section explaining how to animate sprites. It gives me a sprite sheet that has 8 images measuring 128x128 each, while the entire sheet measures 1024x128.
Then it presents the following code:
#! /usr/bin/env_python
import pygame, sys
from pygame.local import *
pygame.init()
ZONE = pygame.display.set_mode((400,300))
pygame.display.set_caption("Game Zone")
RED = (255,0,0)
clock = pygame.time.Clock()
counter = 0
sprites = []
sheet = pygame.image.load("spritesheet.gif").convert_alpha()
width = sheet.get_width()
for i in range(int(width/128)):
sprites.append(sheet.subsurface(i*128,0,128,128))
while True:
pygame.display.update()
ZONE.fill(RED)
ZONE.blit(sprites[counter],(10,10))
counter = (counter + 1) % 8
clock.tick(16)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
The tutorial is very vague about what those lines do, so I wonder:
What does sheet.subsurface() do? And what do those four parameters stand for? (I believe that the third and fourth are referring to the individual images' width and height.)
What does .convert_alpha() do? The tutorial says it "preserves transparency," but I found it strange since I already used images with transparent backgrounds before and none of those needed such conversion.
What does % do? I already know that / stands for division, but the tutorial never explained %.
subsurface gets you a surface that represents a rectangular section of a larger surface. In this case you have one big surface with lots of sprites on it, and subsurface is used to extract the pieces from that surface. You could also create new surfaces and use blit to copy the pixels, but it's a bit easier to use subsurface and it doesn't need to copy the pixel data.
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.subsurface
Suggested search: pygame subsurface
convert and convert_alpha are both used to convert surfaces to the same pixel format as used by the screen. This ensures that you won't lose performance because of conversions when you're blitting them to the screen. convert throws away any alpha channel, whereas convert_alpha keeps it. The comment that you see refers to the choice to use convert_alpha instead of convert, rather than a choice to use convert_alpha instead of nothing.
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert
Suggested search: pygame convert_alpha
The '%' operator isn't a Pygame feature, it's just Python's "modulo/remainder" operator. In this case it's used to make the counter variable loop repeatedly through the values 0 through to 7 and back to 0 again.
https://docs.python.org/2/reference/expressions.html#binary-arithmetic-operations
Suggested search: python percent sign
Let's talk about subsurface(). Assume you have 1,600 images you want to load into the program. There are two ways to do that. (Well, more than two, but I'm making a point here.) First, you could create 1,600 files, load each one into a surface in turn, and start the program. Alternately, you could place them in one file, load that one file into a single surface, and use subsurface(). In this case, spritesheet.gif is 128 pixels high, and contains a new image every 128 pixels.
The two ways basically do the same thing, but one may be more convenient than the other. In particular, opening and reading a file has a small performance cost, and if you need to do this 1,600 times in a row, that cost could be significant.
My understanding of a child surface is that it's basically a Pygame Surface, but defined in terms of a parent surface; if you changed the parent Surface, any child surfaces would be changed in the same way. However, in all other ways, it can be treated as a regular surface.

Pyglet: blit_into texture and alpha

I've been using pyglet for a while now and I really like it. I've got one thing I'd like to do but have been unable to do so far, however.
I'm working on a 2D roleplaying game and I'd like the characters to be able to look different - that is to say, I wouldn't like use completely prebuilt sprites, but instead I'd like there to be a range of, say, hairstyles and equipment, visible on characters in the game.
So to get this thing working, I thought the most sensible way to go on about it would be to create a texture with pyglet.image.Texture.create() and blit the correct sprite source images on that texture using Texture.blit_into. For example, I could blit a naked human image on the texture, then blit a hair texture on that, etc.
human_base = pyglet.image.load('x/human_base.png').get_image_data()
hair_style = pyglet.image.load('x/human_hair1.png').get_image_data()
texture = pyglet.image.Texture.create(width=human_base.width,height=human_base.height)
texture.blit_into(human_base, x=0, y=0, z=0)
texture.blit_into(hair_style, x=0, y=0, z=1)
sprite = pyglet.sprite.Sprite(img=texture, x=0, y=0, batch=my_sprite_batch)
The problem is that blitting the second image into the texture "overwrites" the texture already blitted in. Even though both of the images have an alpha channel, the image below (human_base) is not visible after hair_style is blit on top of it.
One reading this may be wondering why do it this way instead of, say, creating two different pyglet.sprite.Sprite objects, one for human_base and one for hair_style and just move them together. One thing is the draw ordering: the game is tile-based and isometric, so sorting a visible object consisting of multiple sprites with differing layers (or ordered groups, as pyglet calls them) would be a major pain.
So my question is, is there a way to retain alpha when using blit_into with pyglet. If there is no way to do it, please, any suggestions for alternative ways to go on about this would be very much appreciated!
setting the blend function correctly should fix this:
pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA,pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)
I ran into the very same problem and couldn't find a proper solution. Apparently blitting two RGBA images/textures overlapping together will remove the image beneath. Another approache I came up with was using every 'clothing image' on every character as an independent sprite attached to batches and groups, but that was far from the optimal and reduced the FPS dramatically.
I got my own solution by using PIL
import pyglet
from PIL import Image
class main(pyglet.window.Window):
def __init__ (self):
TILESIZE = 32
super(main, self).__init__(800, 600, fullscreen = False)
img1 = Image.open('under.png')
img2 = Image.open('over.png')
img1.paste(img2,(0,0),img2.convert('RGBA'))
img = img1.transpose(Image.FLIP_TOP_BOTTOM)
raw_image=img.tostring()
self.image=pyglet.image.ImageData(TILESIZE,TILESIZE,'RGBA',raw_image)
def run(self):
while not self.has_exit:
self.dispatch_events()
self.clear()
self.image.blit(0,0)
self.flip()
x = main()
x.run()
This may well not be the optimal solution, but if you do the loading in scene loading, then it won't matter, and with the result you can do almost almost anything you want to (as long as you don't blit it on another texture, heh). If you want to get just 1 tile (or a column or a row or a rectangular box) out of a tileset with PIL, you can use the crop function.

Creating DampedRotarySpring in pymunk between a dynamic body and a moving static body

I'm trying to do what the title says. I have a character with a gun constrained to its hand, and I'm trying to get the gun to point at the cursor. I figured that a DampedRotarySpring would be a nice way to do it, but it turns out not to be as simple as that. The gun is a dynamic body with a Segment shape, and for the cursor I create a static body whose position I set to the mouse location with pygame each step.
When I run the program, the gun simply does not move at all except for the effect of gravity or collisions.
Here is the relevant code:
# add crosshairs at the location of the mouse
pointer_body = pymunk.Body()
pointer_shape1 = pymunk.Segment(pointer_body, (0,CROSSHAIRS_SIZE), (0,-CROSSHAIRS_SIZE), 1) # vertical segment
pointer_shape2 = pymunk.Segment(pointer_body, (-CROSSHAIRS_SIZE,0), (CROSSHAIRS_SIZE,0), 1) # horizontal segment
# add a spring that will angle the gun toward the mouse
spring = pymunk.DampedRotarySpring(me.gun.body, pointer_body, 0, 0.01, 1)
space.add(pointer_shape1, pointer_shape2, spring)
while True:
# handle event queue
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
from math import atan2
# update location of pointer
pointer_body.position = flipy(pygame.mouse.get_pos())
pointer_body.angle = atan2( (pointer_body.position.y - me.gun.body.position.y), (pointer_body.position.x - me.gun.body.position.x) )
Edit:
Here is a Gist repository of all my code: https://gist.github.com/4470807.
The main loop is in ragdoll.py.
The problem with the code in the gist is that you have attached the gun to the hand with two joints to keep them in the same place and same rotation. However, the the hand is a rouge body and wont rotate. Therefor the gun wont rotate when its pulled by the spring between it and the cursor, because that other joint is stronger.
Im not sure exactly how you want the setup, but you can see that it all works if you remove the RotaryLimitJoint from the gun-hand.
Take a look at a fixed fork of the code for the exact details: https://gist.github.com/4505219
Some tips for future troubleshooting that I did to find the problem:
Make everything 10x bigger so its easy to see what happens. I know pymunk only draws in one size, but it was easy to just add a 0 on the end of all sizes in the code.
Make the hand not move so its easier to see how it rotates (removed all stuff in the update_hand_position method)
Disable collisions between all shapes in the scene so that the rotating gun is not hindered by some body part. (did a simple loop of space.shapes and ran shape.group=1)
Maybe your problem is with the spring parameters? The stiffness and damping looks very low unless the gun is extremely light.
Check out this code example I added to pymunk yesterday: http://code.google.com/p/pymunk/source/browse/trunk/examples/damped_rotary_spring_pointer.py
(There is one thing going on with the rotation when it flip over between positive and negative pi that I will look at)

Any way to speed up Python and Pygame?

I am writing a simple top down rpg in Pygame, and I have found that it is quite slow.... Although I am not expecting python or pygame to match the FPS of games made with compiled languages like C/C++ or event Byte Compiled ones like Java, But still the current FPS of pygame is like 15. I tried rendering 16-color Bitmaps instead of PNGs or 24 Bitmaps, which slightly boosted the speed, then in desperation , I switched everything to black and white monochrome bitmaps and that made the FPS go to 35. But not more. Now according to most Game Development books I have read, for a user to be completely satisfied with game graphics, the FPS of a 2d game should at least be 40, so is there ANY way of boosting the speed of pygame?
Use Psyco, for python2:
import psyco
psyco.full()
Also, enable doublebuffering. For example:
from pygame.locals import *
flags = FULLSCREEN | DOUBLEBUF
screen = pygame.display.set_mode(resolution, flags, bpp)
You could also turn off alpha if you don't need it:
screen.set_alpha(None)
Instead of flipping the entire screen every time, keep track of the changed areas and only update those. For example, something roughly like this (main loop):
events = pygame.events.get()
for event in events:
# deal with events
pygame.event.pump()
my_sprites.do_stuff_every_loop()
rects = my_sprites.draw()
activerects = rects + oldrects
activerects = filter(bool, activerects)
pygame.display.update(activerects)
oldrects = rects[:]
for rect in rects:
screen.blit(bgimg, rect, rect)
Most (all?) drawing functions return a rect.
You can also set only some allowed events, for more speedy event handling:
pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])
Also, I would not bother with creating a buffer manually and would not use the HWACCEL flag, as I've experienced problems with it on some setups.
Using this, I've achieved reasonably good FPS and smoothness for a small 2d-platformer.
All of these are great suggestions and work well, but you should also keep in mind two things:
1) Blitting surfaces onto surfaces is faster than drawing directly. So pre-drawing fixed images onto surfaces (outside the main game loop), then blitting the surface to the main screen will be more efficient. For exmample:
# pre-draw image outside of main game loop
image_rect = get_image("filename").get_rect()
image_surface = pygame.Surface((image_rect.width, image_rect.height))
image_surface.blit(get_image("filename"), image_rect)
......
# inside main game loop - blit surface to surface (the main screen)
screen.blit(image_surface, image_rect)
2) Make sure you aren't wasting resources by drawing stuff the user can't see. for example:
if point.x >= 0 and point.x <= SCREEN_WIDTH and point.y >= 0 and point.y <= SCREEN_HEIGHT:
# then draw your item
These are some general concepts that help me keep FPS high.
When using images it is important to convert them with the convert()-function of the image.
I have read that convert() disables alpha which is normally quite slow.
I also had speed problems until I used a colour depth of 16 bit and the convert function for my images. Now my FPS are around 150 even if I blit a big image to the screen.
image = image.convert()#video system has to be initialed
Also rotations and scaling takes a lot of time to calculate. A big, transformed image can be saved in another image if it is immutable.
So the idea is to calculate once and reuse the outcome multiple times.
When loading images, if you absolutely require transparency or other alpha values, use the Surface.convert_alpha() method. I have been using it for a game I've been programming, and it has been a huge increase in performance.
E.G: In your constructor, load your images using:
self.srcimage = pygame.image.load(imagepath).convert_alpha()
As far as I can tell, any transformations you do to the image retains the performance this method calls. E.G:
self.rotatedimage = pygame.transform.rotate(self.srcimage, angle).convert_alpha()
becomes redundant if you are using an image that has had convert_alpha() ran on it.
First, always use 'convert()' because it disables alpha which makes bliting faster.
Then only update the parts of the screen that need to be updated.
global rects
rects = []
rects.append(pygame.draw.line(screen, (0, 0, 0), (20, 20), (100, 400), 1))
pygame.display.update(rects) # pygame will only update those rects
Note:
When moving a sprite you have to include in the list the rect from their last position.
You could try using Psyco (http://psyco.sourceforge.net/introduction.html). It often makes quite a bit of difference.
There are a few things to consider for a well-performing Pygame application:
Ensure that the image Surface has the same format as the display Surface. Use convert() (or convert_alpha()) to create a Surface that has the same pixel format. This improves performance when the image is blit on the display, because the formats are compatible and blit does not need to perform an implicit transformation. e.g.:
surf = pygame.image.load('my_image.png').convert_alpha()
Do not load the images in the application loop. pygame.image.load is a very time-consuming operation because the image file must be loaded from the device and the image format must be decoded. Load the images once before the application loop, but use the images in the application loop.
If you have a static game map that consists of tiles, you can buy performance by paying with memory usage. Create a large Surface with the complete map. blit the area which is currently visible on the screen:
game_map = pygame.Surface((tile_size * columns, tile_size * rows))
for x in range(columns):
for y in range(rows):
tile_image = # image for this row and column
game_map.blit(tile_image , (x * tile_size, y * tile_size))
while game:
# [...]
map_sub_rect = screen.get_rect(topleft = (camera_x, camera_y))
screen.blit(game_map, (0, 0), map_sub_rect)
# [...]
If the text is static, the text does not need to be rendered in each frame. Create the text surface once at the beginning of the program or in the constructor of a class, and blit the text surface in each frame.
If the text is dynamic, it cannot even be pre-rendered. However, the most time-consuming is to create the pygame.font.Font/pygame.font.SysFont object. At the very least, you should avoid creating the font in every frame.
In a typical application you don't need all permutations of fonts and font sizes. You just need a couple of different font objects. Create a number of fonts at the beginning of the application and use them when rendering the text. For Instance. e.g.:
fontComic40 = pygame.font.SysFont("Comic Sans MS", 40)
fontComic180 = pygame.font.SysFont("Comic Sans MS", 180)

Categories

Resources