Adding gravity to a bouncing ball using vectors - python

I have a gravity vector (in the form [r, theta]) which I add to my ball's velocity vector. For some reason, the ball doesn't return to the same height after bouncing, but instead slowly loses height sporadically. I am guessing there's some rounding error or something in a calculation I'm using, but I can't isolate the issue.
Here is my code. You need both files and pygame to run it. Sorry if it's a little confusing. I can comment anything some more if you want.
I added a marker whenever the ball reaches its max height so you guys what I mean. I want the ball to return to exactly the same height every time it bounces.
I took a little bit of unnecessary code out. The full program is under the pastebin links.
https://pastebin.com/FyejMCmg - PhysicsSim
import pygame, sys, math, tools, random, time
from pygame.locals import *
clock = pygame.time.Clock()
lines = []
class Particle:
def __init__(self,screen,colour, mass, loc, vel):
self.screen = screen
self.colour = colour
self.mass = mass
self.x = loc[0]
self.y = loc[1]
self.location = self.x,self.y
self.speed = vel[0]
self.angle = vel[1]
def update(self):
global lines
# add gravity
self.speed,self.angle = tools.add_vectors2([self.speed,self.angle], tools.GRAVITY)
# update position
dt = clock.tick(60)
self.x += self.speed * tools.SCALE * math.cos(self.angle) * dt
self.y -= self.speed * tools.SCALE * math.sin(self.angle) * dt
self.location = int(self.x),int(self.y)
# border checking
do = False
n=[]
if ((self.y+self.mass) > tools.SCREEN_HEIGHT):
self.y = tools.SCREEN_HEIGHT-self.mass
n = [0,1]
do = True
# adds position to array so max height so max height can be recorded
if (self.speed==0):
lines.append([self.screen, self.location, self.mass])
# bounce
if do:
#init, convert everything to cartesian
v = tools.polarToCartesian([self.speed, self.angle])
#final -> initial minus twice the projection onto n, where n is the normal to the surface
a = tools.scalarP(2*abs(tools.dotP(v,n)),n) #vector to be added to v
v = tools.add_vectors(v,a)
self.angle = tools.cartesianToPolar(v)[1] # does not set magnitude
# drawing
pygame.draw.circle(self.screen, self.colour, self.location, self.mass, 0)
# draws max height line
def draw_line(l):
screen = l[0]
location = l[1]
radius = l[2]
pygame.draw.line(screen, tools.BLACK, [location[0] + 15, location[1]-radius],[location[0] - 15, location[1]-radius])
def main():
pygame.init()
DISPLAY = pygame.display.set_mode(tools.SCREEN_SIZE,0,32)
DISPLAY.fill(tools.WHITE)
particles = []
particles.append(Particle(DISPLAY, tools.GREEN, 10, [100,100], [0,0]))
done = False
while not done:
global lines
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
DISPLAY.fill(tools.WHITE)
for i in particles:
i.update()
for l in lines:
draw_line(l)
pygame.display.update()
main()
https://pastebin.com/Epgqka31 - tools
import math
#colours
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
BLACK = ( 0, 0, 0)
COLOURS = [WHITE,BLUE,GREEN,RED,BLACK]
#screen
SCREEN_SIZE = SCREEN_WIDTH,SCREEN_HEIGHT = 1000,700
#vectors
GRAVITY = [5.0, 3*math.pi/2] # not 9.8 because it seems too high
SCALE = 0.01
# converts polar coordinates to cartesian coordinates in R2
def polarToCartesian(v):
return [v[0]*math.cos(v[1]), v[0]*math.sin(v[1])]
# converts cartesian coordinates to polar coordinates in R2
def cartesianToPolar(v):
return [math.sqrt(v[0]**2 + v[1]**2), math.atan2(v[1],v[0])]
# dots two cartesian vectors in R2
def dotP(v1, v2):
return v1[0]*v2[0] + v1[1]*v2[1]
# multiplies cartesian vector v by scalar s in Rn
def scalarP(s,v):
v_=[]
for i in v:
v_.append(s*i)
return v_
# returns the sum of two cartesian vectors in R2
def add_vectors(v1, v2):
return [v1[0]+v2[0], v1[1]+v2[1]]
# returns the sum of two polar vectors in R2, equations from https://math.stackexchange.com/questions/1365622/adding-two-polar-vectors
def add_vectors2(v1,v2):
r1,r2,t1,t2 = v1[0],v2[0],v1[1],v2[1]
return [math.sqrt(r1**2 + r2**2 + 2*r1*r2*math.cos(t2-t1)), t1 + math.atan2(r2*math.sin(t2 - t1), r1 + r2*math.cos(t2 - t1))]

Your time interval, dt = clock.tick(60), is not a constant. If you change it to dt = 60 your program runs as expected.
Have a look a the Verlet Algorithm and implement it in your code. You are on the right track!

Related

Python pygame noob question about animation [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
could you help me with a problem I have? I am a new person with regard to programming and to guide me I am using the book: How to think like a computer scientist 3rd edition. And it could not solve exercise 2 of chapter 17. This says that an error occurs when clicking on any frame that is on the right side of the sprite, which causes the animation to start, in theory it should only do the animation if it is you click directly on the sprite, I tried to solve it in many ways but I couldn't, could you help me ?, I think the error occurs in this part
return ( x >= my_x and x + my_width and y >= my_y and y < my_y + my_height)
but I'm not sure, for anything I leave you all the code I have
import pygame
gravity = 0.025
my_clock = pygame.time.Clock()
class QueenSprite:
def __init__(self, img, target_posn):
self.image = img
self.target_posn = target_posn
(x, y) = target_posn
self.posn = (x, 0) # Start ball at top of its column
self.y_velocity = 0 # with zero initial velocity
def update(self):
self.y_velocity += gravity
(x, y) = self.posn
new_y_pos = y + self.y_velocity
(target_x, target_y) = self.target_posn # Unpack the position
dist_to_go = target_y - new_y_pos # How far to our floor?
if dist_to_go < 0: # Are we under floor?
self.y_velocity = -0.65 * self.y_velocity # Bounce
new_y_pos = target_y + dist_to_go # Move back above floor
self.posn = (x, new_y_pos) # Set our new position.
def draw(self, target_surface): # Same as before.
target_surface.blit(self.image, self.posn)
def contains_point(self, pt):
""" Return True if my sprite rectangle contains point pt """
(my_x, my_y) = self.posn
my_width = self.image.get_width()
my_height = self.image.get_height()
(x, y) = pt
return ( x >= my_x and x < my_x + my_width and
y >= my_y and y < my_y + my_height)
def handle_click(self):
self.y_velocity += -2 # Kick it up
class DukeSprite:
def __init__(self, img, target_posn):
self.image = img
self.posn = target_posn
self.anim_frame_count = 0
self.curr_patch_num = 0
def update(self):
if self.anim_frame_count > 0:
self.anim_frame_count = (self.anim_frame_count + 1 ) % 60
self.curr_patch_num = self.anim_frame_count // 6
def draw(self, target_surface):
patch_rect = (self.curr_patch_num * 50, 0,
50, self.image.get_width())
target_surface.blit(self.image, self.posn, patch_rect)
def contains_point(self, pt):
""" Return True if my sprite rectangle contains pt """
(my_x, my_y) = self.posn
my_width = self.image.get_width()
my_height = self.image.get_height()
(x, y) = pt
return ( x >= my_x and x + my_width and y >= my_y and y < my_y + my_height)
def handle_click(self):
if self.anim_frame_count == 0:
self.anim_frame_count = 5
def draw_board(the_board):
""" Draw a chess board with queens, as determined by the the_board. """
pygame.init()
colors = [(255,0,0), (0,0,0)] # Set up colors [red, black]
n = len(the_board) # This is an NxN chess board.
surface_sz = 480 # Proposed physical surface size.
sq_sz = surface_sz // n # sq_sz is length of a square.
surface_sz = n * sq_sz # Adjust to exactly fit n squares.
# Create the surface of (width, height), and its window.
surface = pygame.display.set_mode((surface_sz, surface_sz))
ball = pygame.image.load("ball.png")
# Use an extra offset to centre the ball in its square.
# If the square is too small, offset becomes negative,
# but it will still be centered :-)
ball_offset = (sq_sz-ball.get_width()) // 2
all_sprites = [] # Keep a list of all sprites in the game
# Create a sprite object for each queen, and populate our list.
for (col, row) in enumerate(the_board):
a_queen = QueenSprite(ball,
(col*sq_sz+ball_offset, row*sq_sz+ball_offset))
all_sprites.append(a_queen)
# Load the sprite sheet
duke_sprite_sheet = pygame.image.load("duke_spritesheet.png")
# Instantiate two duke instances, put them on the chessboard
duke1 = DukeSprite(duke_sprite_sheet,(sq_sz*2, 0))
duke2 = DukeSprite(duke_sprite_sheet,(sq_sz*5, sq_sz))
# Add them to the list of sprites which our game loop manages
all_sprites.append(duke1)
all_sprites.append(duke2)
while True:
# Look for an event from keyboard, mouse, etc.
ev = pygame.event.poll()
if ev.type == pygame.QUIT:
break;
if ev.type == pygame.KEYDOWN:
key = ev.dict["key"]
if key == 27: # On Escape key ...
break # leave the game loop.
if key == ord("r"):
colors[0] = (255, 0, 0) # Change to red + black.
elif key == ord("g"):
colors[0] = (0, 255, 0) # Change to green + black.
elif key == ord("b"):
colors[0] = (0, 0, 255) # Change to blue + black.
if ev.type == pygame.MOUSEBUTTONDOWN: # Mouse gone down?
posn_of_click = ev.dict["pos"] # Get the coordinates.
for sprite in all_sprites:
if sprite.contains_point(posn_of_click):
sprite.handle_click()
break
for sprite in all_sprites:
sprite.update()
# Draw a fresh background (a blank chess board)
for row in range(n): # Draw each row of the board.
c_indx = row % 2 # Alternate starting color
for col in range(n): # Run through cols drawing squares
the_square = (col*sq_sz, row*sq_sz, sq_sz, sq_sz)
surface.fill(colors[c_indx], the_square)
# Now flip the color index for the next square
c_indx = (c_indx + 1) % 2
# Ask every sprite to draw itself.
for sprite in all_sprites:
sprite.draw(surface)
my_clock.tick(60) # Waste time so that frame rate becomes 60 fps
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
draw_board([0, 5, 3, 1, 6, 4, 2]) # 7 x 7 to test window size
There is < my_x missing in the comparisons expression in the method contains_point of the class DukeSprite:
return ( x >= my_x and x + my_width and y >= my_y and y < my_y + my_height)
return ( x >= my_x and x < my_x + my_width and y >= my_y and y < my_y + my_height)
Anyway in python you should use chained comparisons:
return my_x <= x < my_x + my_width and my_y <= y < my_y + my_height
In pygame you should use pygame.Rect and collidepoint(). The rectangle of the object you can get from the pygame.Surface with the method get_rect and the position can be set by an keyword argument:
def contains_point(self, pt):
""" Return True if my sprite rectangle contains pt """
my_rect = self.image.get_rect(topleft = self.posn)
return my_rect.collidepoint(pt)

Pygame for possible trajectories planning for a car and make the car follow one of that path/trajectory

I have to create a visualization where I have to create a car (I considered to represent it as a rectangle) and develop trajectories for that car depending on its lateral & longitudinal acceleration. My problem is I am unable to create trajectories. I am doing this as a part of own project. Hence I have no idea if I am in the right direction or not. Guide me if I am wrong.
Problem1 : How do I show predicted path trajectories (beginner step to create only 8 trajectories and not many) ? Is a possible way to also create trajectories also like a curve using Pygame? If not, can I use a mix pf pygame and tkinter to create a mix of curved and straight line trajectories?
Problem2 : Make my rectangular car run along the chosen trajectory (curved line or straight line) or make it follow the path defined in trajectory.
Solutions Tried:
I have taken a rectangular sprite as a car with an idea that I can make it move around the desired trajectory. I am successful with sprite creation and moving it. But I am unable to show display any trajectory curve and make the car follow the path. I am not sure if I have to take trajectories also as Sprite or only car as Sprite is sufficient and trajectories as lines/curves?
Code of the above same explanation is as follows:
My Sprite Class :
class Vehicle(pygame.sprite.Sprite):
def __init__(self,x,y,slip_angle,length=4):
super().__init__()
width = 50
height = 50
self.image = pygame.Surface([width,height])
#Create a car
self.image.fill(RED)
self.image.set_colorkey(RED)
pygame.draw.rect(self.image, WHITE, [0, 0, width, height])
self.rect = self.image.get_rect()
#Parameters of car
self.position = position = Vector2(x, y)
self.velocity = Vector2(0.0, 0.0)
self.slip_angle = slip_angle
self.length = length
self.max_velocity = 20
self.brake_deceleration = 10
self.free_deceleration = 2
self.initial_velocity = 0
self.long_acceleration = 0.0
self.lat_acceleration = 0.0
self.acceleration = 0.0
self.steering = 0.0
def update(self,dt):
self.velocity += (self.acceleration * dt, 0)
self.velocity.x = max(-self.max_velocity, min(self.velocity.x, self.max_velocity))
if self.steering:
turning_radius = self.length / sin(radians(self.steering))
angular_velocity = self.velocity.x / turning_radius
else:
angular_velocity = 0
self.position += self.velocity.rotate(-self.angle) * dt
self.slip_angle += degrees(angular_velocity) * dt
Trajectory Class:
class trajectory(object):
def __init__(self,x,y):
self.x = x
self.y = y
def draw():
x_value = []
time = []
for acc in range(10):
for dt in range(0,10,0.05):
x = vehicle1.initial_velocity + (vehicle1.velocity*dt) + (0.5 * vehicle1.long_acceleration * dt* dt)
x_value.append(x)
time.append(dt)
coordinates = (x_value,time)
canvas_1 = Canvas(root,700,600,background='pink')
canvas_1.grid(row=0,column=1)
x1 = coordinates[acc]
y1 = coordinates[time]
canvas_1.create_line(x1,y1)
#pygame.draw.line(screen,GREEN,list(coordinates),(700, 600))
def update(self):
#self.angle = vehicle1.slip_angle*pi / 180
self.velocity_h = vehicle1.velocity*cos(angle)
self.velocity_v = vehicle1.velocity*sin(angle)
Pygame Main Logic :
#main Logic
proceed = True
#Capturing events till exit
while proceed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
proceed = False
vehicle1.update(dt)
sprites_list.update(dt)
screen.fill(WHITE)
#screen.pygame.Surface.fill(color, rect=None, special_flags=0)
pygame.draw.line(screen, BLACK, [0, 0], [700, 300], 5)
# self.screen.blit(rotated, [20,30])
sprites_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I thank you for your advices and support. Happy to accept any guidance
A simple re-working of your trajectory.draw() should sort it out. I noticed the initial x and y passed to the constructor don't seem to be used. Is it intended that the trajectory is always from ( 0, 0 ) or suchlike?
def draw( screen, initial_vel, vel, accel ):
coordinates = []
for acc in range(10):
for dt in range( 0, 10, 0.05 ):
x = initial_vel + ( vel * dt ) + ( 0.5 * accel * dt * dt )
coordinates.append( ( x, dt ) )
if ( len( coordinates ) > 1 ):
PINK = ( 255, 192, 203 )
pygame.draw.lines( screen, PINK, False, coordinates )
Pass your Window and Vehicle Velocities as a parameters when calling trajectory.draw(), rather than relying on global variables.
my_trajectory.draw( screen, vehicle1.initial_velocity, vehicle1.velocity, vehicle1.long_acceleration )

Python Pygame randomly draw non overlapping circles

Im very new to python and seem to be missing something.
I want to randomly draw circles on a pygame display but only if the circles don't overlap each other.
I believe I must find the distance between all circle centers and only draw it if the distance is bigger than circle radius * 2.
I've tried many different things but all without success, I always get the same result - circles drawn overlapping.
#!/usr/bin/env python
import pygame, random, math
red = (255, 0, 0)
width = 800
height = 600
circle_num = 10
tick = 2
speed = 5
pygame.init()
screen = pygame.display.set_mode((width, height))
class circle():
def __init__(self):
self.x = random.randint(0,width)
self.y = random.randint(0,height)
self.r = 100
def new(self):
pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick)
c = []
for i in range(circle_num):
c.append('c'+str(i))
c[i] = circle()
for j in range(len(c)):
dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y))
if dist > int(c[i].r*2 + c[j].r*2):
c[j].new()
pygame.display.update()
else:
continue
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
You did not check against all other circles. I added a variable shouldprint which gets set to false if any other circle is too close.
import pygame, random, math
red = (255, 0, 0)
width = 800
height = 600
circle_num = 20
tick = 2
speed = 5
pygame.init()
screen = pygame.display.set_mode((width, height))
class circle():
def __init__(self):
self.x = random.randint(0,width)
self.y = random.randint(0,height)
self.r = 100
def new(self):
pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick)
c = []
for i in range(circle_num):
c.append('c'+str(i))
c[i] = circle()
shouldprint = True
for j in range(len(c)):
if i != j:
dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y))
if dist < int(c[i].r*2):
shouldprint = False
if shouldprint:
c[i].new()
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
The for loop has been changed to a while loop. It will keep trying to generate circles until the target number is reached. A circle is first generated. Then, it checks if it intersects with any existing circle using the formula from this answer.
It iterates through every existing circle (store in the list circles) and performs the check using the formula. any() returns True if the formula evaluates to True for any iteration. If it's True, it means it found an intersection. Thus, it continues to the next iteration to try again with a new circle.
circles = []
while len(circles) < circle_num:
new = circle()
if any(pow(c.r - new.r, 2) <=
pow(c.x - new.x, 2) + pow(c.y - new.y, 2) <=
pow(c.r + new.r, 2)
for c in circles):
continue
circles.append(new)
new.new()
pygame.display.update()

Python: pygame deleting image on mouse click and creating it again

im trying to make a simple game where the there are soldiers coming towards you and when you click them to "kill" them they go at the back of the screen and start to come towards you, so on.....
however i'm having trouble with pygame mouse click event and it just doesnt work.
heres my code so far:
import pygame, math
from random import randrange
import sys, math, pygame
from operator import itemgetter
def getKey(customobj):
return customobj.getKey()
class Point3D:
def __init__(self, imfiles, nfrm, x = 0, y = 0, z = 0):
self.x, self.y, self.z = float(x), float(y), float(z)
self.frms = []
self.nfrm=nfrm
self.index=0
for k in range(0,nfrm):
im=pygame.image.load(imfiles+'_'+str(k+1)+'.png')
im.set_colorkey((0,0,0))
self.frms.append(im)
def
project(self, win_width, win_height, fov, viewer_distance):
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + self.z)
x = self.x * factor + win_width / 2
y = -self.y * factor + win_height / 2
return Point3D(x, y, self.z)
def draw3D(self, wsurface, fov, viewer_distance, max_depth):
win_width=wsurface.get_width()
win_height=wsurface.get_height()
factor = fov / (viewer_distance + self.z)
x = self.x * factor + win_width / 2
y = -self.y * factor + win_height / 2
size = int((1 - float(self.z) / max_depth) * 64)
im=pygame.transform.smoothscale(self.frms[self.index],(size,size))
try:
wsurface.blit(im, (x, y))
except:
print((x,y))
self.index=self.index+1
if self.index >= self.nfrm:
self.index=0
def getKey(self):
return -self.z
class StartField:
def __init__(self, num_stars, max_depth):
pygame.init()
myWin = pygame.display.set_mode((640, 450), 0, 32)
pygame.display.set_caption('Drawing')
self.screen = myWin.subsurface([0,0,640,400]);
self.txtwin = myWin.subsurface([0,400,640,50]);
pygame.display.set_caption("Task C")
self.clock = pygame.time.Clock()
self.num_stars = num_stars
self.max_depth = max_depth
self.init_stars()
def init_stars(self):
""" Create the starfield """
self.stars = []
for i in range(self.num_stars):
# A star is represented as a list with this format: [X,Y,Z]
star = Point3D('im',8,randrange(-25,25), randrange(-25,25), randrange(1, self.max_depth))
self.stars.append(star)
def move_and_draw_stars(self):
""" Move and draw the stars """
origin_x = self.screen.get_width() / 2
origin_y = self.screen.get_height() / 2
stars=sorted(self.stars,key = getKey)
for star in stars:
# The Z component is decreased on each frame.
star.z -= 0.05
# If the star has past the screen (I mean Z<=0) then we
# reposition it far away from the screen (Z=max_depth)
# with random X and Y coordinates.
if star.z <= 0:
star.x = randrange(-25,25)
star.y = randrange(-25,25)
star.z = self.max_depth
# Convert the 3D coordinates to 2D using perspective projection.
star.draw3D(self.screen, 128, 0, self.max_depth)
def run(self):
""" Main Loop """
bgPicture = pygame.transform.smoothscale(pygame.image.load('Starfield.jpg'),(self.screen.get_width(),self.screen.get_height()))
font = pygame.font.Font(None, 36)
while 1:
# Lock the framerate at 50 FPS.
self.clock.tick(50)
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
self.screen.blit(bgPicture, [0,0])
self.move_and_draw_stars()
# Text window outputs
self.txtwin.fill([200,200,200])
text = font.render("Total Score: ", 1, (10, 10, 10))
self.txtwin.blit(text, [5, 5])
pygame.display.update()
if __name__ == "__main__":
StartField(256, 24).run()
pygame.init()
pygame.mixer.init()
sounda= pygame.mixer.Sound("MuseUprising.mp3")
sounda.play()
To test for the left mouse button:
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
If give the soldier a pygame.Rect you can use that to check for collision with the mouse pointer like this:
mouse_pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0] and self.rect.collidepoint(mouse_pos):

Pygame - Gravity Methods

I'm in the process of making a simple game in pygame. Its looking to be a platformer RPG. But that is neither final or relevant per this question. So far i have very little functionality in the game. Its just a skeleton at this point if that. My question is kind of two fold:
Whats the best (in terms of performance and flexibility) way to add gravity to classes in pygame?
What are the best practices for adding gravity in general? For example, do you just simply do a "if keyPressed == k_W then subtract 2pixels per tick from player-y for 20 ticks" or something with velocity in the up or negative-y direction?
I've seen other posts on adding gravity to games after the fact, where adding it really wasn't thought about during initial development. I want to add it in as early as possible so instead of adding gravity to other things, i can add other things to gravity. I'm going to continue to read up on this, so if you prefer to point me in the direction of some online resources, I'd much appreciate that as well!
Quick dislaimer: I do not know multiple ways to incorporate gravity, so I can not say which is "best". But, if you're fighting the performance battle in Python, you've probably fighting the wrong battle.
For gravity, you can use a vector system. Say a character jumps off the ground and has initial velocity of [5, -15] (negative y because positive y is down!), you can move your character's rect by this velocity every frame to simulate movement. To throw gravity into this, you need to add 9.8 to your y velocity component value every second. So 1 second in, the velocity will be about [5, -5]. This will have your character slow to a stop, and begin moving down.
For key pressed movement, I recommend using booleans. An example, upon pressing k_U , a variable that says you are moving up becomes True. Then, if this variable is True, you move him, say, [0, -5]. Upon keyup, set variable to false. Do this for north/east/south/west, and then you have a movement system in 4 directions, that moves you while you hold the key down.
I used the 1/2 mg^2 equation in this code, which has a snow like effect:
import math, sys, random, time
import pygame, inputbox
from pygame.locals import *
class flake:
def __init__(self, xpos, ypos, mass, color, drift):
self.xpos = xpos
self.ypos = ypos
self.mass = mass
self.rect = pygame.Rect(xpos, ypos, 2, 2)
self.checked = False
self.color = color
self.drift = drift
size = width, height = 510, 700
BLACK = (0,0,0)
WHITE = (255, 255, 255)
GREY = (128,128,128)
DARKGREY = (169,169,169)
SILVER = (192,192,192)
LIGHTGREY = (211,211,211)
LIGHTESTGREY = (220,220,220)
pygame.init()
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill(BLACK)
def init():
global theSnow, snowColours, clock, startrange
theSnow = []
snowColours = []
snowColours.append(WHITE)
snowColours.append(GREY)
snowColours.append(DARKGREY)
snowColours.append(SILVER)
snowColours.append(LIGHTGREY)
snowColours.append(LIGHTESTGREY)
for c in range(2000):
mass = 0.0
mass = float(random.randint(1,8) / 100.0)
xpos = random.randint(0,width)
ypos = random.randint(0,5)
ypos = -ypos
drift = ypos/10.0
colour = snowColours[random.randint(0,5)]
f = flake(xpos, ypos, mass, colour, drift)
theSnow.append(f)
print "flake x = " + str(f.xpos) + " y = " + str(f.ypos) + " mass = " + str(f.mass)
startrange = 200
clock = pygame.time.Clock()
def run():
global theSnow, clock
global startrange
newrange = 0
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
sys.exit()
keys=pygame.key.get_pressed()
if keys[K_q]:
return
g = 3
for count in range(startrange):
yinc = 0.0
yuncertainty = float(random.randint(1,5)/10.0)
yinc = float(0.5 * theSnow[count].mass * (g*g)) + yuncertainty
theSnow[count].ypos += yinc
xuncertainty = random.randint(1,10)
if xuncertainty > 4:
theSnow[count].xpos += theSnow[count].drift
else:
theSnow[count].xpos -= theSnow[count].drift
theSnow[count].rect = pygame.Rect(theSnow[count].xpos, theSnow[count].ypos, 2,2)
if not theSnow[count].checked:
if theSnow[count].ypos > 30:
for c in range(newrange, startrange):
print " c= " + str(c)
theSnow[c].checked = True
if startrange < 2000:
startrange += 100
newrange = startrange - 100
print " newrange = " + str(newrange)
print " startrange = " + str(startrange)
update()
pygame.time.wait(10)
#clock.tick(10)
def update():
global theSnow, startrange
background.fill(BLACK)
for count in range(startrange):
pygame.draw.rect(background, theSnow[count].color, theSnow[count].rect)
screen.blit(background, (0, 0))
pygame.display.flip()
if __name__ == "__main__":
init()
run()

Categories