pygame: What is the difference between an image and a sprite? - python

What is the difference between importing a rocket sprite (for example) and setting it as an image vs importing a rocket sprite and setting it as a sprite in pygame?

I think you're just getting confused about the terminology:
Image
An image is just a collection of pixels. You're using "sprite" to refer to an image on the disk, but that's just an image file. To use your rocket example, you would load the image like this:
rocket_img = pygame.image.load('rocket.png').convert_alpha()
You can then draw this image anywhere you want with:
screen.blit(rocket_img, (x, y))
Sprite
A sprite in Pygame is an object, with a whole collection of built-in functionality. Sprites have an image as one of their properties, but there are a whole lot more. Plus you can put sprites together in groups to make them easier to update or draw. Sprites have collision functionality built into them. You can add your own properties to track location, velocity, animation, etc.
A simple sprite:
class Rocket(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('rocket.png').convert_alpha()
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 1
This would be a rocket sprite that you would instantiate by using
rocket = Rocket()
You can draw by using
screen.blit(rocket.image, rocket.rect)
and it moves slowly to the right (if you call update() in the game loop:
rocket.update()
I recommend looking at the Sprite docs - there's lots more you can do with groups to make working with lots of sprites very easy.
http://www.pygame.org/docs/ref/sprite.html

In Pygame "images" generally refer only to image files: importing and exporting them to disk. There is the "Surface" object that is a Python object that holds pixels, and can be used to stamp other surfaces, be transformed (scaled/rotated) , yielding other surfaces and so on.
The main screen itself is a Surface subclass - so when you stamp a Surface with data read from a disk image, using the blit method the image shows up on the screen.
Sprites on the other hand are a base class for objects in your game, and they don't even depend of having attached pixels data with them. Some of the Pygame API expect Sprite objects to have a rect attribute, which denotes the position where it will be rendered on a Surface - and an image attribute. If it is to be used, the sprite.image attribute should hold a surface object - usually read from disk (but could have been programatically drawn).
The main call using the sprite image attribute is the Group.draw() method.
But it is possible to create an entirely different game than an interactive one - one that would be the server side for a MMO game, without anything on the screen, for example, using the Sprite and Group classes, without ever making use of the image attribute on sprites.
Worth reading:
https://www.pygame.org/docs/ref/sprite.html
Conversely, you can bypass all the helper logic provided by Sprites and Groups and create a game that will only ever have Surface objects - representing images read from disk. Them you are responsible to track were and when to draw them, without using the elpe rmethods in sprite Groups.

Related

Box-box collision detection with PyOpenGL and Pygame at 3d

I'm writing a player class that, among other things, has mesh attributes (I use the py3d library and the mesh class from it) and collider (a class that I need to implement myself). The collider is a simple cube and should have a method to determine whether it collided with another collider-cube or not. I have a class that allows you to rotate and move 3d objects, I inherit the collider from it. The main problem is precisely to write a collision check function
I tried to use the methods built into Pygame to detect collisions, but it didn't work, because when the camera is removed, the collider remains the same size, and it can't be rotated. I'm bad at math, and all the guides I found were in C.game example
One way to detect box-box collisions in 3D using PyOpenGL and Pygame is to use the Bullet physics engine. Bullet is a 3D physics engine that can be used to detect collisions, apply forces, and simulate the motion of rigid bodies. To use Bullet, you would need to implement the collider class as a Bullet body, and then use the Bullet functions to detect collisions between the collider objects. You can also use the Bullet functions to rotate and move the colliders, which will allow you to keep the same size collider regardless of the camera position.
Here's a link to a tutorial on how to integrate bullet
http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-a-physics-library/

How do you rotate an image in Pygame without constantly redrawing the background?

I am making a randomized spinner in pygame, but the only method I've found is to constantly redraw the whole screen. Is there a way that doesn't use this, it becomes extremely laggy.
You can not. why do you want that? It is common to redraw the entire scene in each frame. Of course you can try to redraw just a rectangular section of the background. However, this is usually not worth the effort.
The pygame way to do this is to pass a list of rectangular areas to pygame.display.update(). If rectangles are passed to pygame.display.update() then not the entire display will be redrawn, just the specified areas::
Update portions of the screen for software displays
[...]
You can pass the function a single rectangle, or a sequence of rectangles. It is more efficient to pass many rectangles at once than to call update multiple times with single or a partial list of rectangles.
e.g.:
while run:
# [...]
screen.blit(background, (0, 0))
screen.blit(image1, bounding_rect1)
screen.blit(image2, bounding_rect2)
pygame.display.update([bounding_rect1, bounding_rect2])
That is how computer animation works, you're redrawing the screen on every frame. Every game practically works the same way. I am not sure what graphics pipeline pygame uses but in OpenGL you usually initialize all your geometry outside of the render loop and then use pointers to batch-process everything in the render-loop so you're not duplicating a lot of boilerplate code or making duplicate objects every frame.
A related question has been answered here:
https://gamedev.stackexchange.com/questions/125546/what-is-the-best-way-to-handle-the-actual-render-loop

What is Pygame.Rect() is used for in a program?

Can anyone tell me the use of Pygame.Rect. I am creating a simple program to draw and display rectangle in screen and check for collision with screen. I saw a video on youtube where the Youtuber uses the following code:
moving_rect=pygame.Rect(300,300,100,100)
Now I don't know what is Pygame.Rect is used for and what the above line of code actually does.
A pygame.Rec describes a rectangular area. It can be use to define the bounding box of an object. This can be useful for a collision test. See How do I detect collision in pygame?.
Actually it is used to define the location of a pygame.sprite.Sprite object.
Notice that a pygame.Surface object has no position. It only contains the pixel information. However, a Rect and a Surface together define the position of an image (Sprite) in the window.

Barrier shield collision detection for Space Invaders game in Python with pygame

I'm currently making the Space Invaders game in Python with pygame.
I currently have 3 base barriers that are all built with 1 x 1 pixel blocks (that 'extend' the pygame.sprite.Sprite class). For collision detection, I check if a missile has collided with the barrier.
For now, everything works, when I fire and hit one of the barriers, the pixel that was hit is eliminated.
Now the thing that bothers me is that in the original Space Invaders, when the ship's missile (or an alien's missile for that matter)
hits the barrier, it causes an 'explosion' that affects multiple pixels of the barrier. I would like to implement this
in my python/pygame code. How would I go about this?
Here is my collision detection code in my missile class (that 'extends' the pygame.sprite.Sprite):
baseBarrier_hit_list = pygame.sprite.spritecollide(self, all_baseBarrier_group, True)
for pixel in baseBarrier_hit_list:
self.kill() # I kill the missile after collision so that the other barrier pixels are unaffected.
break #so that the other pixels in the column are unaffected.
I thought of 'artificially' adding 'random' pixels to the baseBarrier_hit_list but I'm unable to add elements to the baseBarrier_hit_list.
Here is a video link of the original space invaders to see what I mean:
https://www.youtube.com/watch?v=axlx3o0codc
Here is also a link to a python/pygame version of Space Invaders that shows that only one pixel is affected when collision occurs between missile and base barrier. (Note that this is not MY version of the game). https://www.youtube.com/watch?v=_2yUP3WMDRc
EDIT: (see comment for picture explanation)
EDIT: TemporalWolf's suggestion worked. This is the code I added to my function.
shield_hit_list_random = pygame.sprite.spritecollide(self, all_blockShields_group, False, pygame.sprite.collide_rect_ratio(2))
Passing a False to the function prevents the killing of the sprites. Then, I randomly kill the some sprites in the shield_hit_list_random group like this:
for shield in shield_hit_list_random:
pourcentage =randint(0,3)
if pourcentage == 2:
shield.kill()
I would try using the scaled collision rect or the circle equivalent:
pygame.sprite.collide_rect_ratio() Collision detection between two
sprites, using rects scaled to a ratio.
collide_rect_ratio(ratio) -> collided_callable
A callable class that checks for collisions between
two sprites, using a scaled version of the sprites rects.
Is created with a ratio, the instance is then intended to be passed as
a collided callback function to the *collide functions.
A ratio is a floating point number - 1.0 is the same size, 2.0 is
twice as big, and 0.5 is half the size.
New in pygame 1.8.1
which would be given as the 4th parameter to your spritecollide function

Pygame: Updating Rects with scrolling levels

I'm currently making a 2D side-scrolling run'n'jump platform game in PyGame. Most of the stuff is working OK and very well in fact - I am exploiting the fast pyGame Sprite objects & groups.
What I'm interested to know is how people usually deal with Rects for scrolling games. I obviously have a level that is much bigger than visible area, and the player, enemies, bullets etc each have their own (x,y) coordinates which describe where they are in the level.
But now, since we use the "spriteGroup.draw(surface)" call, it will not display them in the right spot unless each objects Rects have been adjusted so that the right part displays on the screen. In other words, everytime a player/enemy/bullet/whatever else is updated, the Camera information needs to be passed, so that their Rect can be updated.
Is this the best method to use? It works but I don't really like passing the camera information to every single object at every update to offset the Rects.
Obviously the ideal method (I think) is to use Rects with "real" coordinates, blit everything to a buffer as big as the level, and then just blit the visible part to the screen, but in practice that slows the game down A LOT.
Any comments/insight would be appreciated.
Thanks
You could extend de Sprite.Group so it recives the camera information.
Then do one of these options:
A. Override the update method so it updates the on-screen coordinates of every sprite.
B. Override the draw method so it updates the on-screen coordinates of every sprite and then calls its parent draw method.
I think A it's easier and cleaner.
I don't really like passing the camera information to every single
object at every update to offset the Rects.
Camera may be global, or, a member of a global Game() class instance. Then your sprite class's draw method doesn't need an argument.
You can override draw yourself, so it does:
dest = game.camera.topleft + self.rect.topleft
screen.blit( self.surface, dest )
This keeps the bullet's rect in world-coordinates, yet blits using screen-coordinates.
One method I found is to keep track of a scrollx and a scrolly. Then, just add scrollx and scroll y to the coordinates when you move the rectangles.
You can have a 2 variables level_landlevel_d which see where you are in the level, Then check which sprites are in the visible area
level_d+height and level_l+width,
and draw them on the screen.
The simple way to do it is like that:
Create a CameraX and CameraY variables, and when you blit objects on the screen use this:
blit(surface, (x -CameraX, y -CameraY))
any object that gets affected by the camera should be drawn like that, but keep in mind that there are objects that you may want to remain uneffected (like health bars or status windows)
just keep in mind everytime you want to move camera do this
#Move Camera Right
CameraX += 10
#Move Camera Left
CameraX -= 10
#Move Camera Down
CameraY += 10
#Move Camera Up
CameraY -= 10
Just keep in mind that if they get negative values they may not work correctly, also you must probably define some limits (you dont want your camera to move over the limits of your map

Categories

Resources