How to set the position of an image in pygame? - pygame

I created an object called "alien" in my game. Uploaded the image for "alien" and used "get_rect()" to set its rect attributes.
Now I want to change the x-coordinate value of "alien". Which of the following two ways is correct?
alien.x = ...... or alien.rect.x = ......
I saw in a textbook that the following codes are used:
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
Why didn't the author directly use alien.rect.x to change the x-coordinate value of "alien"? Like:
alien.rect.x = alien_width + 2 * alien_width * alien_number
Why does there have to be alien.x?

Unfortunately the answer is "it depends". Some people's code maintains the position of the object at an internal x and y, using a rect to handle collisions. Other code just maintains the rect, using the rect.x and rect.y if a single position is (ever) needed.
It's up to you really, but my advice is to keep it all inside a PyGame Rect, as this has benefits of easy collision detection, should you wish to use that down the track.
class Alien:
def __init__( self, x, y, image ):
self.image = image
self.rect = image.get_rect() # copy the image dimensions
self.rect.x = x
self.rect.y = y # move to location
def draw( self, window ):
window.blit( self.image, self.rect ) # paint it
When it's time to move the Alien, you can just as easy adjust the rectangle as an x and y
class Alien:
...
def moveBy( self, by_x, by_y ):
self.rect.move_ip( by_x, by_y )
def moveTo( self, x, y ):
self.rect.x = x
self.rect.y = y
Perhaps the author thought that having a separate x and y made the code easier to understand. This is a paramount reason that effects programming style. Program code is read many times more often than it is written, so often extra variables are included to illustrate the program flow better.
For example, like checking a mouse-click-event:
for event in pygame.event.get( ):
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
handleGameClick( mouse2Board( event.pos ) ) # <-- HERE
Adding extra variables documents what's going on:
elif event.type == pygame.MOUSEBUTTONUP:
mouse_click_coord = event.pos
game_board_coord = mouse2Board( mouse_click_coord )
handleGameClick( game_board_coord )
Here it tells the reader that event.pos is a co-ordinate (so probably a pair of values), and is from the mouse. Then it reenforces that the co-ordinate is then converted into a game-board space before being passed out to handleGameClick() for processing.
The two pieces of code have exactly the same outcome (and probably execution speed), but the second is much easier to follow.
IMHO one should ideally write code such that someone unfamiliar with the language (but still a programmer) can understand it without too much trouble. This is why in my answers you wont see much "pythonic" loop-in-list creation like:
[[col +1 for col in row] for row in a] # Taken from 10 vote answer
Because unless your very familiar with python syntax, it's unreadable.

Related

Questions with creating sprites in pygame

So basically what I know how to do is add a player sprite (make a player class that inherits from pygame.sprite, etc...) this works for me.
What I would like to know how to do is iterate the creation of sprites and add them to the sprite group.
This is because I have a 2 dimensional array and I have a function that reads this and places the "tiles" accordingly in the 2d space, this is to create levels easier.
So what I want this function to do is create these sprites (I guess with a for loop that reads the array ?) and add them to do the group but this doesn't work so I have some questions first:
1)Can you create sprites outside of the init function in a class?
2)What really are sprites, is it a surface coupled to a rect ?
3)And finally do you have an idea of simply how to get this done: If I give you a 2d array, how would you make the function that reads this array and calculates the position (this is okay, I think I have it figured out) and most importantly, make sprites out of the given positions that can then be added to the sprites group.
Thanks in advance
Can you create sprites outside of the init function in a class?
Sure.
What really are sprites, is it a surface coupled to a rect ?
If we talk about pygame's Sprite class: yes.
Such a sprite is basically a Surface (the image attribute) and a Rect (the rect
attribute). They work best together with pygame's Group classes.
And finally do you have an idea of simply how to get this done ....
Just create a nested loop to iterate over the array.
Here's a simple example:
import pygame
pygame.init()
TILESIZE = 64
class Actor(pygame.sprite.Sprite):
def __init__(self, color, pos):
super().__init__()
self.image = pygame.Surface((TILESIZE, TILESIZE))
self.image.fill(pygame.Color(color))
self.rect = self.image.get_rect(topleft = pos)
def main():
data = [
' YUB ',
' G ',
' B ',
' ',
' Y ',
' U ',
]
screen = pygame.display.set_mode((len(data[0]) * TILESIZE, len(data) * TILESIZE))
sprites = pygame.sprite.Group()
colors = {
'G': 'green',
'B': 'black',
'Y': 'yellow',
'U': 'dodgerblue'
}
x, y = 0, 0
for line in data:
for char in line:
if char in colors:
sprites.add(Actor(colors[char], (x * TILESIZE, y * TILESIZE)))
x += 1
x = 0
y += 1
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
return
sprites.update()
screen.fill((100, 100, 100))
sprites.draw(screen)
pygame.display.flip()
main()
You can find another example here.

Detach intermediate module in Pytorch with regard to part of the loss

Let's say I have the following forward pass that results in two separate losses:
forward(self, input)
x = self.layer1(input)
y = self.layer2(x)
z = self.layer3(y)
return y, z
We then calculate loss1(y) and loss2(z). Then we can optimize loss = loss1 + loss2 with a single optimizer.
But I have two caveats: (1) I want d_loss1 to be calculated with regards to layer2 only (without layer1), and (2) I want d_loss2 to be calculated with regards to layer3 and layer1 - without layer2.
Essentially, I want to train non-consecutive parts of the network separately with separate losses.
I believe I can solve (1) by introducing a stop-gradient in the input to layer2 like so:
forward(self, input)
x = self.layer1(input)
y = self.layer2(x)
y_stop_gradient = self.layer2(Variable(x.data))
z = self.layer3(y)
return y_stop_gradient, z
But how can I solve (2)?
In other words, I want loss2's gradients to "skip" layer2 while keeping layer2 trainable with regards to loss1.
While waiting for a proper answer I found one of my own, though it's a terribly inefficient one and I'm hoping for someone else to come up with a better solution.
My solution looks like this:
import copy
forward(self, input)
x = self.layer1(input)
y = copy.deepcopy(self.layer2)(x) # create a full copy of the layer
y_stop_gradient = self.layer2(Variable(x.data))
z = self.layer3(y)
return y_stop_gradient, z
This solution is inefficient because (1) I think deep copy is overkill for what I'm trying to do and too expensive and (2) the gradients for layer2 relative to z are still calculated, they're just unused.

Moving Sprites Right and Downwards

I am working on this project to move a sprite, but I can't seem to figure out how to move a sprite to the right as well as move it downwards. Any thoughts?
Here is my program:
import pygame
import time
import sys
pygame.init()
# Set up window
screen = pygame.display.set_mode((320, 240))
# Load an image
rocket = pygame.image.load("rocket.png")
rocketrect = rocket.get_rect()
x_coord = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
screen.fill((0,0,0))
screen.blit(rocket, rocketrect)
pygame.display.flip()
x_coord += 1
rocketrect.centerx = x_coord
In your method of mving the sprite, you change the coordinatses (x) and then assign it to the centerx of the images rectangle. If you want to keep this kind of method (changing and assigning), and also move the image down, you will need to give a y value. For example
# Define y variable
y_coord = 0
# Your code
…
y_coords += 1
rocketrect.centery = y_coord
This works similarly to how you moved your x_coords, but in total, the program is a bit basic and is not how programmers (or at least me) usually code. Another person might used a tuple for the location, along with making a rocket class. There are also some other ways to move the sprite, such as the .move() or .move_ip() that I would suggest. But it's up to you.

Pygame - Limiting instances of sprites

I'm using an example regarding sprite generation for a space scroller shootup that I'm developing. By slowly trying to understand how it works, I've managed to get multiple sprites to transverse across the screen. However, there are many sprites that are generated.
So what I'm having trouble with is limiting the initial number of sprites instead of the multitude that the code produces. I thought of using if sprites.__len__ < 10: sprites.add(drone) but when I tried that, it didn't work.
My thinking was that each time it looped, it would check the number of sprites in the group and if it was less then 10, add a sprite to the group until it hit 10. That way if it went off screen or is destroyed, then it would keep doing the check and keeping it constant.
This is the player class:
class Player(pygame.sprite.Sprite):
def __init__(self, *groups):
super(Player, self).__init__(*groups)
self.image = pygame.image.load('player.png')
self.rect = pygame.rect.Rect((screen_width, (random.randrange(0,screen_height))), self.image.get_size())
self.dx = -10
self.pos = random.randrange(0,screen_height)
def update(self):
self.rect.centerx += self.dx
if self.rect.right < 0:
self.kill()
and this is the section regarding the adding of the sprite.
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
It's probably obvious, but I'm still learning so guidance would be great.
Second question - More of a confirmation of thought. If I don't want the sprite to be half drawn on the bottom of the screen. Do I basically say that if self.rect.bottom > screen_height, then position the sprite # screen_height
Full source: http://pastebin.com/PLRVHtxz
EDIT - I think I've solved it, just need to make the sprites run smoother.
while 1:
clock.tick(40)
numberAlien = 5
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
if sprites.__len__() < numberAlien:
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
You could subclass SpriteGroup, add a new field of the total number of sprites, and check in the add method to see if it can be added.
You shouldn't test check any variables with __.
As for the movement, i believe, you do not see a smooth movement because of clock.tick(40).
It waits for 40ms until it resumes running. You could reduce tick to 10, and tune the dx you change for the sprites, or try a more universal approach.
A call to clock.tick() returns amount of ms since the last call. This will be your time delta. You can then have a global SPEED. The amount of pixels to be moved would be calculated from SPEED * delta.

Most simple algorithm to reverse direction on collision

I teach Computer Programming. For first course students I'm looking for most easy algorithm to change direction on collide (with window frame). This is my actual code:
import sys, pygame
pygame.init()
speed_x = 1
speed_y = 1
black = (0, 0, 0)
width, height = 320, 240
size = ( width, height )
screen = pygame.display.set_mode(size)
display_surface = pygame.display.get_surface()
display_rectangle = display_surface.get_rect()
ball_img = pygame.image.load("data/ball.gif")
ball = ball_img.convert_alpha()
ballrect = ball.get_rect()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if not display_rectangle.contains( ballrect.move([speed_x, 0]) ):
speed_x *= -1
else:
ballrect = ballrect.move([speed_x, 0])
if not display_rectangle.contains( ballrect.move([0, speed_y]) ):
speed_y *= -1
else:
ballrect = ballrect.move([0, speed_y])
screen.fill(black)
screen.blit(ball, ballrect)
pygame.display.flip()
pygame.time.delay(30)
This code works fine, my question is if someone know about a easy algorithm or clear algorithm to reverse direction using contains or any other collide pygame test.
Some times I think that an approach is most easy for students and a new clear approach appears.
All suggestions are welcome
Some suggestions? Thanks!
I think your approach is fine. Your code models the velocity of the ball using the 2-vector [speed_x, speed_y]. Bouncing off a (horizontal or vertical) wall involves negating the appropriate component of the vector.
As long as your students have a background in introductory physics (velocity, momentum, collisions) then your code should be understandable.
Your code probably works ok (I haven't tried, but it seems fine), but I have mixed feelings about it. You check the x-movement then the y-movement, which is ok, but the Rect.contains() tests both x and y so it seems a bit redundant to me.
And depending on your students background, it kind of hides what you are doing.
I think I'd like testing everything manually :
if display_rectangle.left<=ballrect.left+speed_x or display_rectangle.right<=ballrect.right+speed_x
speed_x*=-1
if display_rectangle.top<=ballrect.top+speed_y or display_rectangle.bottom<=ballrect.bottom+speed_y
speed_y*=-1
ballrect.move([speed_x, speed_y])
BTW : why is it ballrect and not ball_rect ?