How to Display Sprites in Pygame? - python

This is just a quick question regarding sprites in PyGame, I have my image loaded as in the code below, and I'm just wondering how to display the sprite in PyGame like drawing a rectangle or circle. I don't want to have it behave in anyway. I think I use a blit command, but I'm not sure and I'm not finding much online.
Here's my image code for loading it.
Star = pygame.image.load('WhiteStar.png').convert_alpha()
You could just provide an outline for loading a sprite. I simply want to display it.

Use blit to draw an image. Actually blit draws one Surface onto another. Hence you need to blit the image onto the Surface associated to the display.
You need to specify the position where the image is blit on the target. The position can be specified by a pair of coordinates that define the top left position. Or it can be specified by a rectangle, only taking into account the top left point of the rectangle:
screen = pygame.dispaly.set_mode((width, height))
star = pygame.image.load('WhiteStar.png').convert_alpha()
# [...]
while run:
# [...]
screen.blit(star, (x, y))
# [...]
Use a pygame.Rect when you want to place the center of a surface at a specific point. pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument. For example, the center of the rectangle can be specified with the keyword argument center. These keyword argument are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a full list of the keyword arguments):
screen.blit(star, star.get_rect(center = (x, y)))

Related

pygame - surface from part of another surface

how can I create a surface from a section of another surface. Reason is that I have an image as a background, and on that am displaying a clock - so when i update a new time, I need to first restore the original background back on that section before bliting the new clock text. I could do this using flip / full screen update, but want to avoid that and only update / restore a section of the screen.
You can update a section of the screen by passing a a single rectnagle or a list of rectangles to pygame.display.update:
Update portions of the screen for software displays. [...] You can pass the function a single rectangle, or a sequence of rectangles.
e.g.:
pygame.display.update(rect_region)
You can define a subsurface that is directly linked to the source surface with the subsurface method:
Returns a new Surface that shares its pixels with its new parent. The new Surface is considered a child of the original. Modifications to either Surface pixels will effect each other.
e.g.:
rect_region = (x, y, width, height)
subsurf = source_surf.subsurface(rect_region)
Alternatively the blit method allows to specify a rectangular sub-area of a source Surface:
[...] An optional area rectangle can be passed as well. This represents a smaller portion of the source Surface to draw. [...]
e.g.:
rect_region = (x, y, width, height)
traget.blit(source_surf, (posx, posy), rect_region)
See also How can I crop an image with Pygame? and Pygame - blitting from x and y cordinates of image.

How to rotate an image in the same position?

I'm currently trying to code a game which includes a wee robot landing on a pad. In trying to work out the physics of the way it would fall, I have come across an issue with the rotation. It rotates on a left or right key press, in the respective direction.
I've tried using blit with the rect.center but it still doesn't seem to work. Any help would be much appreciated!!
def rotate_right(self):
self.new_angle = self.angle + 30
self.rotate_lander()
def rotate_lander(self):
self.image = pygame.transform.rotozoom(self.image, self.new_angle, 1)
self.rect = self.image.get_rect(center=self.image.get_rect().center)
screen.blit(self.image, self.rect.center)
I've managed to get it to rotate, but it moves with every rotation, and I need it to stay in the same position. I think the centre is off, but I'm not sure where it could have gone wrong.
First, in rotate_lander(), you should always rotate the original picture, otherwise it will get distorted (And in your case, run away). So, create another copy of self.image, which you wont change.
original = pygame.Surface(...)
...
def rotate_lander(self):
self.image = pygame.transform.rotozoom(self.original, self.new_angle, 1)
But now, the image still won't rotate on exact same position.
The problem is, that the bounding box of image is changing. And with that, the position of every point of image changes. You shouldn't set the position of self.rect to the center, because it is moving.
Instead, you must update the position according to the change of bounding box. You should compare the bounding box before and after the rotation.
You have a full tutorial on this topic already answered here:
Rotate an image around its center
*If you just wish to keep an image on place (not rotating it around its center), you can just get rid of center.
def rotate_lander(self):
self.image = pygame.transform.rotozoom(self.image, self.new_angle, 1)
self.rect = self.image.get_rect()
screen.blit(self.image, self.rect)

finding the position of a sprite in pygame

I am currently making a battleships type game and I have created a user-friendly interface that highlights spaces on a grid in order to finish my hit system in this game I need to find the position of my sprite at a certain instance(for example when the player presses enter).
So what you can do to find the position of a sprite in pygame is you can use the get_rect() to find the Rect of the sprite, and then using the .x and .y. I'm assuming that you're sprites are pygame.Surfaces.
find_loc(surface):
loc = (surface.get_rect().x, surface.get_rect().y)
return loc
# First, I get the Rect of your surface
# With the Rect, I get the variables of the x and y
# I assign the .get_rect().x and .get_rect().y to a tuple which is assigned to variable 'loc'
# I return 'loc'
I hope this helps.

Pygame collision detect with object and rect

Yep, I'm asking another question about this program :D
Anyway, I currently a program that creates two lines on the screen with a gap in between them that can scroll. From here, I obviously need to see if the two objects are colliding. Since I only have one sprite and one rectangle I thought it was slightly pointless and overkill to make two classes for them. However, I can only find tutorials relating to classes which I obviously don't need. So, my question really is:
Is it possible to test for collision between a standard image and a Pygame rect? If it is not, how can I convert either the image, rectangle or both the sprites to do this. (All preferably without using classes.)
Note: the image and rectangle are created in the following ways (if it makes a difference)
bird = pygame.image.load("bird.png").convert_alpha()
pipeTop = pygame.draw.rect(screen, (0,200,30), Rect((scrollx,0),(30,height)))
pipeBottom = pygame.draw.rect(screen, (0,200,30), Rect((scrollx,900),(30,-bheight)))
An image by itself does not have a position. You cannot test collision between a rect and something that is not placed in the world. I would recommend to create a class Bird along with a class Pipe that will both subclass pygame.Sprite.
Pygame already has collision detection built in.
A short example
bird = Bird()
pipes = pygame.Group()
pipes.add(pipeTop)
pipes.add(pipeBottom)
while True:
if pygame.sprite.spritecollide(bird,pipes):
print "Game Over"
EDIT:
Don't be afraid of classes, you will have to use them anyways sooner or later.
If you really don't want to use sprites, you can use the birds rect and the pipe and call collide_rect to check if they overlap.
EDIT2:
an example Bird class modified from pygame docs
class Bird(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bird.png").convert_alpha()
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
You could then add methods such as move, which will move the bird down with the force of gravity.
The same would apply for the Pipe but instead of loading an image, you can create an empty Surface, and fill it with a color.
image = pygame.Surface(width,height)
image.fill((0,200,30)
You can just get the x and y values and compare them:
if pipe.x < bird.x < pipe.x+pipe.width:
#collision code
pass

Pygame Surface Mechanics

I'm currently writing up some GUI code for a small project I'm working on and I've come to the point where I need to implement scroll bars and their associated containers. For ease of execution, I would love to be able to draw all elements within the "scroll box" (the window that the scroll bar will affect) to a separate surface from my main display surface. The separate surface would then be cropped as need be and then drawn to the display surface in the render loop. I'm having trouble getting this to work, however.
In the draw() method of my ScrollBox class, I have the following code.
def draw(self):
self.subSurface.blit(self.image, (x, y))
#subSurface is, naturally, a Surface, and image is a pygame.Image; x and y are whatever
self.displaySurface.blit(self.subSurface, (x,y))
As with all drawable GUI elements in my code, draw() is called every pass through the main render loop. What the above code gives me is the default filled-in black Rect and self.image is not displayed in any capacity. I tried replacing the first line with
pygame.draw.rect(self.subSurface, color, rect)
but it yielded the same results. From my reading up on other Pygame GUI libraries, it seems what I want to do is possible but I don't think I'm executing it properly. How do I attach other sources/surfaces to subSurface and then have subSurface be drawn (with the sources attached) by displaySurface?
Any help would be much appreciated. Thanks.
For people visiting this question in the future:
Remember that the dest argument for Surface.blit() is relative to the upper-left corner of the destination surface. So if you're assembling an image on a subsurface, remember to use coordinates relative to the top-left corner of the object you're assembling, rather than absolute display coordinates.
So to assemble a scrollbar and draw it somewhere:
class ScrollBar:
# ... code ...
def render(self, display, x, y):
self.subSurface.blit(self.handle_image, (0, self.handle_pos))
self.subSurface.blit(self.upbtn_image, (0, 0))
self.subSurface.blit(self.dnbtn_image, (0, self.height - self.btn_height))
# ... other rendering operations
display.blit(self.subSurface, (x, y))
Adjust all numbers and variable names to taste, but you get the idea. Notice that all the scrollbar elements are positioned in "scrollbar-local" coordinates, with only the final blit to the display surface positioned in screen/application coordinates.

Categories

Resources