Pygame - Limiting instances of sprites - pygame

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.

Related

Move a sprite, but cannot delete the precedent image of it [duplicate]

I'm building a pong game trying to get better at programming but Im having trouble moving the ball. When the move_right method is called the ellipse stretches to the right instead of moving to the right. I've tried putting the ball variable in the init method but that just makes it not move at all even though the variables should be changing on account of the move_right method. I have also tried setting the x and y positions as parameters in the Ball class,but that just stretches it also.
I don't understand why when I run the following code the ball I'm trying to move stretches to the right instead of moves to the right. Can someone explain why this is happening? I have tried everything I can think of but i can't get it to do what I want.
import pygame,sys
import random
class Ball:
def __init__(self):
self.size = 30
self.color = light_grey
self.x_pos = width/2 -15
self.y_pos = height/2 -15
self.speed = 1
#self.ball = pygame.Rect(self.x_pos, self.y_pos,self.size,self.size)
def draw_ball(self):
ball = pygame.Rect(self.x_pos, self.y_pos,self.size,self.size)
pygame.draw.ellipse(screen,self.color,ball)
def move_right(self):
self.x_pos += self.speed
class Player:
def __init__(self,x_pos,y_pos,width,height):
self.x_pos = x_pos
self.y_pos = y_pos
self.width = width
self.height = height
self.color = light_grey
def draw_player(self):
player = pygame.Rect(self.x_pos,self.y_pos,self.width,self.height)
pygame.draw.rect(screen,self.color,player)
class Main:
def __init__(self):
self.ball=Ball()
self.player=Player(width-20,height/2 -70,10,140)
self.opponent= Player(10,height/2-70,10,140)
def draw_elements(self):
self.ball.draw_ball()
self.player.draw_player()
self.opponent.draw_player()
def move_ball(self):
self.ball.move_right()
pygame.init()
size = 30
clock = pygame.time.Clock()
pygame.display.set_caption("Pong")
width = 1000
height = 600
screen = pygame.display.set_mode((width,height))
bg_color = pygame.Color('grey12')
light_grey = (200,200,200)
main = Main()
#ball = pygame.Rect(main.ball.x_pos, main.ball.y_pos,main.ball.size,main.ball.size)
#player = pygame.Rect(width-20,height/2 -70,10,140)
#opponent = pygame.Rect(10,height/2-70,10,140)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#ball = pygame.Rect(main.ball.x_pos, main.ball.y_pos,main.ball.size,main.ball.size)
#pygame.draw.rect(screen,light_grey,player)
#pygame.draw.rect(screen,light_grey,opponent)
#pygame.draw.ellipse(screen,light_grey,ball)
main.draw_elements()
main.move_ball()
main.ball.x_pos += main.ball.speed
pygame.display.flip()
clock.tick(60)
You have to clear the display in every frame with pygame.Surface.fill:
while True:
# [...]
screen.fill(0) # <---
main.draw_elements()
main.move_ball()
main.ball.x_pos += main.ball.speed
pygame.display.flip()
# [...]
Everything that is drawn is drawn on the target surface. The entire scene is redraw in each frame. Therefore the display needs to be cleared at the begin of every frame in the application loop. The typical PyGame application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()

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.

Need help creating game close to "Pong" (Pygame)

As you read from the description (or not), I need help creating a game close to Pong.
I am really new in programming, and I am learning all by myself. The game you help me create will be my first game ever.
My version of game, explained:
Picture (Can't post a picture here since I am new):
http://www.upload.ee/image/3307299/test.png (THIS LINK IS SAFE)
So, number 1 stands for walls (black ones)
Number 2 marks the area, where time stops (game over)
3 is your time survived.
Number 4 is the ball that bounces (like they do in Pong).
Code:
import pygame
import random
pygame.init()
screen = pygame.display.set_mode([640, 480])
paddle = pygame.image.load("pulgake.png")
pygame.display.set_caption("PONG!")
back = pygame.image.load("taust.png")
screen.blit(back, (0, 0))
screen.blit(paddle, (600, 240))
pygame.display.flip()
xpaddle = 600
ypaddle = 240
delay = 10
interval = 10
pygame.key.set_repeat(delay, interval)
while True:
screen.blit(back, (0,0))
screen.blit(paddle, (xpaddle, ypaddle))
pygame.display.flip()
pygame.time.delay(20)
for i in pygame.event.get():
if i.type == pygame.QUIT:
sys.exit()
elif i.type == pygame.KEYDOWN:
if i.key == pygame.K_UP:
ypaddle = ypaddle - 10
if ypaddle < 10:
ypaddle = 10
elif i.key == pygame.K_DOWN:
ypaddle = ypaddle + 10
if ypaddle > 410:
ypaddle = 410
I would like to have a bouncing ball, but i don't have the knowledge to create it.
It doesn't have to be really difficult(maybe using pygame.draw.circle?)
Actually it has to be simple, because sprites are maybe too much for me.
My idea was to change coordinates every time ball gets to specific coordinates.
I am not just asking somebody to make a game I like, it's for educational purposes.
I would love to see some comments with the code you provide.
As I told, i just started learning it.
My english isn't best. Sorry about that.
Thanks in advance!
(I know that my post is a bit confusing and unspecific)
If needed, I will upload the background and paddle picture too.
You could create a Ball class, that will have 2 methods:
update() - that will move the ball according to speed_x and speed_y and
check if any collisions are detected
draw() - that will blit the surface/ or draw a circle at ball position.
another thing you have to think about, is collisions.
You can find if a point is in a rectangle like this:
We have a rectangle with points : p1,p2,p3,p4, p0 is our testing point.
p0 is in the rectangle if dist(p0,p1) + disp(p0,p2) + ... + disp(p0,p4) == WIDTH+HEIGHT
you can try to figure out the equation for a circle. Hint: radius is what you need.
EDIT: The class example:
class Ball:
def __init__(self):
self.pos = [0,0]
self.velocity = [1,0]
def move():
self.pos[0] += self.velocity[0]
self.pos[1] += self.velocity[1]
def draw(screen):
pygame.draw.circle(screen,WHITE,self.pos,5)
To extend on #Bartlomiej Lewandowski, To make the ball you need to
Every loop ball.update() will do:
ball.x += ball.xvel
ball.y += ball.yvel`
Then
if you collide with left/right walls ball.x *= -1
if you collide with top/bot walls ball.y *= -1
Using pygame.Rect will simplfy logic
# bounce on right side
ball.rect.right >= screen.rect.right:
ball.yvel *= -1
# bounce top
ball.rect.top <= screen.rect.top:
# bot
ball.rect.bottom >= screen.rect.bot:
# etc...
edit: Bart added different names but it's the same thing.

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 ?

Pygame where Sprite Skates

I'm having difficulty making my sprite skate.
The thing is my sprite should be sliding until it hits something like the border of the screen or a block. Also, this should be done when the sprite is on ice and if the sprite isn't on ice then the sprite should walk. So if the person presses up once, then the sprite will skate until it hits something that will stop its movement.
Thanks!
I don't know how you currently have your code, but a general template would be:
# main loop
while True:
for each object:
update(framerate)
render()
# skater code
class skater:
moving = True
speed = [0,0]
x = 0
y = 0
def update(framerate):
# check for collisions
if collision:
self.moving = False
# move the skater
if self.moving:
self.x += self.speed[0]*framerate
self.y += self.speed[1]*framerate
moving will be set to true then an arrow key is pressed.
where speed is decided by what arrow keys have been pressed (- for left and up, + for right and down)
From looking at your code at http://pastebin.com/cEpp44NS you're doing things like:
self.speedX1 *= (self.ice * self.normal_friction)
Which is going to very rapidly reduce self.speedX1 (especially since self.ice is set to 0.01)
From what you've said, it sounds like you don't want the speed to be decreasing at all whilst sliding, so try just removing this code.