How to add random number of falling balls in pygame? - random

Here is some code for random falling balls, I am able to generate one falling ball. Having hard time to randomize the number of falling balls, also they need to be some random delays falling from "sky". Could you tell how to do it ?
import pygame
import random
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
robot = pygame.image.load("robot.png")
y1 = 0
y2 = 0
speed1 = 1
speed2 = 2
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
screen.fill((0, 0, 0))
robots = []
screen.blit(robot, (100, y1))
y1 += speed1
if y1 >= 640:
y1 = 0
pygame.display.flip()
clock.tick(60)

Maybe this is the best solution for your problem. I did a list with position (x, y) and then I used this values in for loop.
Here is code example:
balls_num = 100
robots = [[random.randint(0, width), random.randint(-600, 0)] for _ in range(balls_num)]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((0, 0, 0))
for pos in robots:
screen.blit(robot, (pos[0], pos[1]))
pos[1] += speed1
if pos[1] >= 640:
pos[1] = -100
I hope it will help you, Adam

Related

Collision problem between drawn circle and a group of sprites pygame (python) [duplicate]

This question already has answers here:
Sometimes the ball doesn't bounce off the paddle in pong game
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
I need to create a background of square sprites generated with a matrix of letters and have a ball that collides perfectly with these sprites regardless of its angle and speed. As you can see in my code the collision and bounce bugs are numerous, I cannot find the solution, can you help me, thank you
import pygame
from math import *
import sys
pygame.init()
clock = pygame.time.Clock()
display = pygame.display.set_mode((900, 900))
white = (255, 255, 255)
black = (30, 30, 30)
arial_font = pygame.font.SysFont("arial Black", 36)
TILE_SIZE = 100
level = [
"EEEEEEEE",
"E E",
"E E E E",
"E E",
"E X E",
"E E E E",
"E E",
"EEEEEEEE", ]
walls_group_sprites = pygame.sprite.Group()
spawn_ball = []
def create_level():
x = y = TILE_SIZE
for row in level:
for column in row:
if column == "E":
wall = Sprite("wall.png", x, y)
walls_group_sprites.add(wall)
if column == "X":
spawn_ball.append(x)
spawn_ball.append(y)
x += TILE_SIZE
y += TILE_SIZE
x = TILE_SIZE
class Sprite(pygame.sprite.Sprite):
def __init__(self, image_path, pos_x, pos_y):
super().__init__()
self.image = pygame.image.load(image_path)
self.rect = self.image.get_rect()
self.rect.center = [pos_x, pos_y]
class Ball:
def __init__(self, x, y, speed, angle):
self.x = x
self.y = y
self.color = white
self.angle = angle
self.speed = speed
self.radius = 25
def move(self):
# move Ball with math import cosinus/sinus
self.x += self.speed * cos(radians(self.angle))
self.y += self.speed * sin(radians(self.angle))
# Draw ball with pygame
self.circle = pygame.draw.circle(display, self.color, (self.x, self.y), self.radius)
def collide(self):
# My wall Sprite is a image (100X100 pixels) with rect, there are 100 sprites in the pygame group sprite
for wall_index in walls_group_sprites:
if self.y + self.radius > wall_index.rect.top and self.y - self.radius < wall_index.rect.bottom and self.x + self.radius > wall_index.rect.left and self.x - self.radius < wall_index.rect.right:
# if the ball.y is in the height of the sprite then the rebound is vertical
if wall_index.rect.top < self.y < wall_index.rect.bottom:
self.angle = 180 - int(self.angle)
# if the ball.x is in the width of the sprite then the rebound is horizontal
elif wall_index.rect.left < self.x < wall_index.rect.right:
self.angle = 360 - int(self.angle)
else:
#if the ball is in one of the two lower left or upper right corners then the rebound and sideways
if (self.y > wall_index.rect.bottom and self.x < wall_index.rect.left) or (self.y < wall_index.rect.top and self.x > wall_index.rect.right):
self.angle = 90 - int(self.angle)
#if the ball is in one of the two corners at the bottom right or the top left then the rebound and on the other side
elif (self.y > wall_index.rect.bottom and self.x > wall_index.rect.right) or (self.y < wall_index.rect.top and self.x < wall_index.rect.left):
self.angle = 270 - int(self.angle)
create_level()
ball = Ball(spawn_ball[0], spawn_ball[1], 7, 40)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN: ball.angle += 10
display.fill(black)
walls_group_sprites.draw(display)
ball.move()
ball.collide()
text = arial_font.render(f"Click to change Angle {abs(ball.angle)}", True, white)
display.blit(text, [200, 0])
clock.tick(60)
pygame.display.update()
my wall sprite (png)

Pygame window doesn't show on Mac OS Catalina

Running:
MacOS Catalina 10.15.3
Python 3.7.6.
Pygame 1.9.6
I just started programming and I am trying to run a reinforcement learning Pygame code (link: https://github.com/harvitronix/reinforcement-learning-car). When I run python3.7 -m pygame.examples.aliens I see the test window + sound and everything works.
However when I try to run the code for the game I am trying to get working I at first only saw the loading wheel, I fixed the loading wheel by putting in the following loop. `
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
When I try to run it now, I only see a black pygame window pop-up, so no loading wheel but also not the game, it also seems like the game doesn't run in the background (this was the case without the above loop). See the complete original code below:
import random
import math
import numpy as np
import pygame
from pygame.color import THECOLORS
import sys
import pymunk
from pymunk.vec2d import Vec2d
from pymunk.pygame_util import draw
# PyGame init
width = 1000
height = 700
pygame.init()
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
# Turn off alpha since we don't use it.
screen.set_alpha(None)
# Showing sensors and redrawing slows things down.
show_sensors = True
draw_screen = True
class GameState:
def __init__(self):
# Global-ish.
self.crashed = False
# Physics stuff.
self.space = pymunk.Space()
self.space.gravity = pymunk.Vec2d(0., 0.)
# Create the car.
self.create_car(100, 100, 0.5)
# Record steps.
self.num_steps = 0
# Create walls.
static = [
pymunk.Segment(
self.space.static_body,
(0, 1), (0, height), 1),
pymunk.Segment(
self.space.static_body,
(1, height), (width, height), 1),
pymunk.Segment(
self.space.static_body,
(width-1, height), (width-1, 1), 1),
pymunk.Segment(
self.space.static_body,
(1, 1), (width, 1), 1)
]
for s in static:
s.friction = 1.
s.group = 1
s.collision_type = 1
s.color = THECOLORS['red']
self.space.add(static)
# Create some obstacles, semi-randomly.
# We'll create three and they'll move around to prevent over-fitting.
self.obstacles = []
self.obstacles.append(self.create_obstacle(200, 350, 100))
self.obstacles.append(self.create_obstacle(700, 200, 125))
self.obstacles.append(self.create_obstacle(600, 600, 35))
# Create a cat.
self.create_cat()
def create_obstacle(self, x, y, r):
c_body = pymunk.Body(pymunk.inf, pymunk.inf)
c_shape = pymunk.Circle(c_body, r)
c_shape.elasticity = 1.0
c_body.position = x, y
c_shape.color = THECOLORS["blue"]
self.space.add(c_body, c_shape)
return c_body
def create_cat(self):
inertia = pymunk.moment_for_circle(1, 0, 14, (0, 0))
self.cat_body = pymunk.Body(1, inertia)
self.cat_body.position = 50, height - 100
self.cat_shape = pymunk.Circle(self.cat_body, 30)
self.cat_shape.color = THECOLORS["orange"]
self.cat_shape.elasticity = 1.0
self.cat_shape.angle = 0.5
direction = Vec2d(1, 0).rotated(self.cat_body.angle)
self.space.add(self.cat_body, self.cat_shape)
def create_car(self, x, y, r):
inertia = pymunk.moment_for_circle(1, 0, 14, (0, 0))
self.car_body = pymunk.Body(1, inertia)
self.car_body.position = x, y
self.car_shape = pymunk.Circle(self.car_body, 25)
self.car_shape.color = THECOLORS["green"]
self.car_shape.elasticity = 1.0
self.car_body.angle = r
driving_direction = Vec2d(1, 0).rotated(self.car_body.angle)
self.car_body.apply_impulse(driving_direction)
self.space.add(self.car_body, self.car_shape)
def frame_step(self, action):
if action == 0: # Turn left.
self.car_body.angle -= .2
elif action == 1: # Turn right.
self.car_body.angle += .2
# Move obstacles.
if self.num_steps % 100 == 0:
self.move_obstacles()
# Move cat.
if self.num_steps % 5 == 0:
self.move_cat()
driving_direction = Vec2d(1, 0).rotated(self.car_body.angle)
self.car_body.velocity = 100 * driving_direction
# Update the screen and stuff.
screen.fill(THECOLORS["black"])
draw(screen, self.space)
self.space.step(1./10)
if draw_screen:
pygame.display.flip()
clock.tick()
# Get the current location and the readings there.
x, y = self.car_body.position
readings = self.get_sonar_readings(x, y, self.car_body.angle)
normalized_readings = [(x-20.0)/20.0 for x in readings]
state = np.array([normalized_readings])
# Set the reward.
# Car crashed when any reading == 1
if self.car_is_crashed(readings):
self.crashed = True
reward = -500
self.recover_from_crash(driving_direction)
else:
# Higher readings are better, so return the sum.
reward = -5 + int(self.sum_readings(readings) / 10)
self.num_steps += 1
return reward, state
def move_obstacles(self):
# Randomly move obstacles around.
for obstacle in self.obstacles:
speed = random.randint(1, 5)
direction = Vec2d(1, 0).rotated(self.car_body.angle + random.randint(-2, 2))
obstacle.velocity = speed * direction
def move_cat(self):
speed = random.randint(20, 200)
self.cat_body.angle -= random.randint(-1, 1)
direction = Vec2d(1, 0).rotated(self.cat_body.angle)
self.cat_body.velocity = speed * direction
def car_is_crashed(self, readings):
if readings[0] == 1 or readings[1] == 1 or readings[2] == 1:
return True
else:
return False
def recover_from_crash(self, driving_direction):
"""
We hit something, so recover.
"""
while self.crashed:
# Go backwards.
self.car_body.velocity = -100 * driving_direction
self.crashed = False
for i in range(10):
self.car_body.angle += .2 # Turn a little.
screen.fill(THECOLORS["grey7"]) # Red is scary!
draw(screen, self.space)
self.space.step(1./10)
if draw_screen:
pygame.display.flip()
clock.tick()
def sum_readings(self, readings):
"""Sum the number of non-zero readings."""
tot = 0
for i in readings:
tot += i
return tot
def get_sonar_readings(self, x, y, angle):
readings = []
"""
Instead of using a grid of boolean(ish) sensors, sonar readings
simply return N "distance" readings, one for each sonar
we're simulating. The distance is a count of the first non-zero
reading starting at the object. For instance, if the fifth sensor
in a sonar "arm" is non-zero, then that arm returns a distance of 5.
"""
# Make our arms.
arm_left = self.make_sonar_arm(x, y)
arm_middle = arm_left
arm_right = arm_left
# Rotate them and get readings.
readings.append(self.get_arm_distance(arm_left, x, y, angle, 0.75))
readings.append(self.get_arm_distance(arm_middle, x, y, angle, 0))
readings.append(self.get_arm_distance(arm_right, x, y, angle, -0.75))
if show_sensors:
pygame.display.update()
return readings
def get_arm_distance(self, arm, x, y, angle, offset):
# Used to count the distance.
i = 0
# Look at each point and see if we've hit something.
for point in arm:
i += 1
# Move the point to the right spot.
rotated_p = self.get_rotated_point(
x, y, point[0], point[1], angle + offset
)
# Check if we've hit something. Return the current i (distance)
# if we did.
if rotated_p[0] <= 0 or rotated_p[1] <= 0 \
or rotated_p[0] >= width or rotated_p[1] >= height:
return i # Sensor is off the screen.
else:
obs = screen.get_at(rotated_p)
if self.get_track_or_not(obs) != 0:
return i
if show_sensors:
pygame.draw.circle(screen, (255, 255, 255), (rotated_p), 2)
# Return the distance for the arm.
return i
def make_sonar_arm(self, x, y):
spread = 10 # Default spread.
distance = 20 # Gap before first sensor.
arm_points = []
# Make an arm. We build it flat because we'll rotate it about the
# center later.
for i in range(1, 40):
arm_points.append((distance + x + (spread * i), y))
return arm_points
def get_rotated_point(self, x_1, y_1, x_2, y_2, radians):
# Rotate x_2, y_2 around x_1, y_1 by angle.
x_change = (x_2 - x_1) * math.cos(radians) + \
(y_2 - y_1) * math.sin(radians)
y_change = (y_1 - y_2) * math.cos(radians) - \
(x_1 - x_2) * math.sin(radians)
new_x = x_change + x_1
new_y = height - (y_change + y_1)
return int(new_x), int(new_y)
def get_track_or_not(self, reading):
if reading == THECOLORS['black']:
return 0
else:
return 1
if __name__ == "__main__":
game_state = GameState()
while True:
game_state.frame_step((random.randint(0, 2)))
I don't think the issue is with my python version because the test runs normal. Anybody see the issue?
Thanks!
Problem solved. I put the loop in the beginning of the code but it should have gone beneath:
if draw_screen:
pygame.display.flip()

I have a 600x1000 picture, i want to blit bottom part of the picture onto my 600x600 window using pygame

In the game our character jumps on platforms in order to move higher. My game resolution is 600x600. I have a picture that's going to be my background and has resolution of 600x1000. I'm trying to setup a background that progressively moves or changes as we go higher. So that when I get higher, the background shows not the bottom of the original picture (Y-axis 400-1000), but shows, for example, the middle part of the picture (Y-axis 200-800).
So far I haven't been able to figure out a way how to blit 600x600 image from 600x1000 image. It's like I want to cut the upper part of the original picture so that it fits. Could you help me with this?
I'm sorry if I didn't explain it properly. How do I blit a non-distorted, smaller-sized image from a bigger-sized image. The background I have in mind should look like from an android game called "Happy Jump".
Thank you for reading.
Have a good day.
enter image description here
import pygame
pygame.init()
run = True
surf = pygame.display.set_mode((600, 600))
img = pygame.image.load('image.jpg')
down = -400
center_of_screen = 300
maximum_limit_of_down = 0
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((40, 40))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = (300, 570)
self.isJump = False
self.jumpCount = 10
def update(self):
global down
key = pygame.key.get_pressed()
if key[pygame.K_UP] and not self.isJump:
self.isJump = True
if self.isJump:
if self.rect.y > center_of_screen or (down >= maximum_limit_of_down):
if self.jumpCount >= 0:
self.rect.y = self.rect.y - (self.jumpCount ** 2) * 0.5
self.jumpCount -= 1
else:
self.jumpCount = 10
self.isJump = False
if down >= maximum_limit_of_down:
down = maximum_limit_of_down
else:
if self.jumpCount >= 0:
down = down + (self.jumpCount ** 2) * 0.5
self.jumpCount -= 1
else:
self.jumpCount = 10
self.isJump = False
player = Player()
all_sprite = pygame.sprite.Group()
all_sprite.add(player)
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
surf.fill((0, 0, 0))
surf.blit(img, (0, down))
all_sprite.update()
all_sprite.draw(surf)
pygame.display.update()
This will help you, sorry for the Image i used whatever i found

Bouncing text animation issue in Pygame

I'm trying to code a program that can take text and animate it to bounce on a loop, like a ball bouncing to the floor. I used a similar piece of code I found a starting point as I'm still fairly new to Pygame (thank you Pete Shinners, whoever you are), but after updating the code and playing with it for a long time I still can't get it to blit to the screen correctly. The text starts above the rendered area and then gradually falls into view, but the top part of the text is cut off.
I've tried moving the blitted region around the window and resizing the rectangles and surface the program is using, but nothing seems to fix it.
import os, sys, math, pygame, pygame.font, pygame.image
from pygame.locals import *
def bounce():
# define constants
G = 0.98
FLOOR = 0
COEFFICIENT = 0.8
#define variables
ball = 500
direction = 'DOWN'
v = 0
count = 0
#create array to store data
array = [ball]
while True:
if count == 4:
return array
elif ball > FLOOR and direction == 'DOWN':
v += G
if (ball - v) >= FLOOR:
ball = ball - v
array.append(round(ball,2))
else:
ball = FLOOR
array.append(round(ball,2))
direction = 'UP'
v *= COEFFICIENT
count += 1
elif ball >= FLOOR and direction == 'UP':
v -= G
if (ball + v) >= FLOOR:
ball = ball + v
array.append(round(ball,2))
if v <= 0:
direction = 'DOWN'
else:
ball = FLOOR
array.append(ball)
direction = 'UP'
v *= COEFFICIENT
class textBouncy:
array = bounce()
def __init__(self, font, message, fontcolor, amount=10):
# Render the font message
self.base = font.render(message, 0, fontcolor)
# bounce amount (height)
self.amount = amount
#size = rect of maximum height/width of text
self.size = self.base.get_rect().inflate(0, amount).size
#normalise array to meet height restriction
self.array = [round(-x/(500/amount),2) for x in array]
def animate(self):
# create window surface s
s = pygame.Surface(self.size)
# height = max inflated height
height = self.size[1]
# define a step-sized rectangle in the location of the step
src = Rect(0, 0, self.base.get_width(), height)
# moves the message according to the array list.
dst = src.move(0, self.array[i])
if (i + 1) == len(self.array):
global i
i = 0
# blits the information onto the screen
s.blit(self.base, dst, src)
return s
entry_info = 'Bouncing ball text'
if __name__ == '__main__':
pygame.init()
#create text renderer
i = 0
array = bounce()
bigfont = pygame.font.Font(None, 60)
white = 255, 255, 255
renderer = textBouncy(bigfont, entry_info, white, 16)
text = renderer.animate()
#create a window the correct size
win = pygame.display.set_mode(text.get_size())
win.blit(text, (0, 10))
pygame.display.flip()
#run animation loop
finished = 0
while True:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
text = renderer.animate()
i += 1
win.blit(text, (0, 10)) # blits the finished product from animate
pygame.display.flip()
(Quote) "it all comes down to math really" Kay so you need to - the y axis when you want to make it go up and + the x axis to make it go side ways you could make it go up and down will moveing it horizontally and then when it reaches a point it will stop moving horizontally and just bonce up and down +ing it more every time
That was my 100$ which took me 5 mins to write
After revisiting this I managed to work this out - I needed to add everything I blitted down to compensate for the bounce up. So in the __init__function:
self.array = [round(-x/(500/amount),2)**+self.amount** for x in array]
Works perfectly now :)

image changing to another image changing in pygame

i made a program in pygame ware a mine turtle runs in a sqare but when you click in the box he explodes but when i change the image to an explodtion it shows th mineturtle first
here's my code:
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10
direction = 'right'
s=15
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
b = pygame.image.load("b.png")
time.sleep(2)
pygame.quit()
sys.exit()
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
i already have all of the files in the same loaction but when i did the image swich id didn't work! plz help
To show changes on screen you need to call pygame.display.update(). When you call sleep and exit, it does not update the screen, and no changes are seen.
time.
EDIT:
If you wish to show a new image for 2 seconds and then close the program, you should use pygame.time module. Have a variable that will store the time since the last click. You add the result of tick(). When the value will be high enough, you can exit pygame.
This will not freeze the window, and you will be able to see the changes.
i just did this
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10`enter code here`
direction = 'right'
s=15
explodetick=0
move=True
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
#for event in pygame.event.get():
#
if explodetick>0:
explodetick+=1
if explodetick==81:
pygame.quit()
if move:
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
cat = pygame.image.load("b.png")
pygame.display.update()
explodetick=1
move=False
pygame.display.update()
fpsClock.tick(FPS)

Resources