Advertisement
Guest User

Untitled

a guest
May 31st, 2011
756
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.63 KB | None | 0 0
  1. """
  2. Holding the left mouse button will repel birds from wherever you clicked, the right one attracts them. Use the little red x to close the window, I've found that Python crashes when I just close the window.
  3.  
  4. If you have any questions or suggestions or anything else: http://philippdow.blogspot.com/
  5. """
  6.  
  7.  
  8. import sys
  9. from math import *
  10. import random
  11. import pygame
  12. from pygame.locals import *
  13.  
  14. pygame.init()
  15. zeroview=[]
  16. running = True                                      #is the script running? gets set to False when the small x gets clicked, and the program then stops.
  17.  
  18. #colors
  19. green = (0,200,0)
  20. white=(255,255,255)
  21. black=(0,0,0)
  22. red=(250,0,0)
  23.  
  24.  
  25. #general variables
  26. screensize = [1000,700]                             #screen size in pixels
  27. loopscreen = False                                  #Lets the screen loop, although radius calculations then don't expand to the opposite side of the screen
  28. screen = pygame.display.set_mode((screensize[0],screensize[1]))
  29. pygame.draw.rect(screen, white, (0,0, screensize[0], screensize[1]),0)
  30.  
  31.  
  32. numbirds=80                         #number of birds. around 60-70 is good, but lower numbers allow the program to run much faster
  33.  
  34. birds=[["bird"+str(i),[0,0],[0,0],[0,0],[0,0]]
  35.            for i in range(numbirds)]                #the list of birds, in the form (name, position, velocity, last velocity, second last velocity)*number of birds
  36.  
  37. radius=20                                           #maximum distance of two birds to be considered "neighbours". standard: 50
  38. viewangle=abs(cos(1.65806279))                      #angle a bird can see, to each side of the current direction vector, around 95 is standard. the cos() is so that the isinview(x,y) function doesn't need to call acos() for every bird every frame
  39.  
  40.  
  41. averagebirdspeed=9                                  #average speed of the birds in pixels/frame. standard: 8
  42. lowerbound,upperbound=3,3                           #this lets the user control how far the speed of the birds can deviate - speed is going to be random in the range of averagebirdspeed-lowerbound to averagebirdspeed+upperbound. 3 and 3 are standard.
  43.  
  44.  
  45.  
  46. #view options for visualization:
  47. connectbirds=False                                  #interconnect all birds (very slow if there are many birds)
  48. connectaverageposition=False                        #connects all birds to the swarms average position
  49. showaveragevector=False                             #shows the swarms average velocity vector (length is proportional to magnitude, but the factor is not necessarily 1)
  50. connectaveragetocenter=False                        #draws a line from the center to the birds average position
  51. highlightbird=False                                 #highlights a single bird to visualize its trajectory
  52. traceimage=False                                    #if true, the white background doesn't get redrawn, and the bird trajectories will be traced out. also traces any lines that are being drawn.
  53.  
  54.  
  55. #weightings for velocity components:
  56. randomweight=20                                     #25
  57. neighbourweight=0                                   #10
  58. neighbourposweight=0                                #0.5
  59. mouseweight=200                                     #200, must be high for mouse attraction/repulsion to work properly
  60. viewweight=16                                       #15
  61. viewposweight=1                                     #1
  62.  
  63. #weighting for last velocity components, higher values here will create smoother flight curves
  64. o1weight=50                                         #50
  65. o2weight=15                                         #40
  66.  
  67. #gravity, to keep the birds from leaving the visible frame for too long
  68. gravstrength = 0.0004                               #1/2500 is good. This basically decides how far out of the screen area the birds will fly.
  69. gravitypoint=(
  70.         [int(screensize[0]/2),int(screensize[1]/2)])#middle of screensize is best
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77. #small functions, mostly for making it easier to work with the vectors
  78. def plusminus():                                    #random 1 or -1
  79.     if (random.random()>0.5):
  80.         return 1
  81.     else: return -1
  82.  
  83. def vmag(v):                                        #returns a vectors magnitude
  84.     return abs(sqrt( v[0]**2 + v[1]**2 ))
  85.  
  86. def addvectorcomponents(a,b):                       #adds the components of a and b
  87.     return [a[0]+b[0], a[1]+b[1]]
  88.  
  89. def subvectorcomponents(a,b):                       #subtracts the components of a and b
  90.     return [a[0]-b[0], a[1]-b[1]]
  91.  
  92. def averagevector(vectors):                         # accepts a list of vectors as input, returns the average vector
  93.     xsum=0
  94.     ysum=0
  95.     for i in range(len(vectors)):
  96.         xsum+=vectors[i][0]
  97.         ysum+=vectors[i][1]
  98.     return [xsum/len(vectors), ysum/len(vectors)]
  99.  
  100. def scalarmultivector(x,vect):                      #multiply vect by the scalar x
  101.     return [x*vect[0], x*vect[1]]
  102.  
  103. def randomspeedvector():                            #generates a random speed vector from the variables averagebirdspeed, upper and lower bound
  104.     return [random.randrange(1,averagebirdspeed*2+1)*plusminus(), random.randrange(1,averagebirdspeed*2+1)*plusminus()]
  105.  
  106. def scalevector(vector, magnitude):                 #scale a vector to a certain magnitude without altering its direction
  107.     ratio=magnitude/vmag(vector)
  108.     return [vector[0]*ratio, vector[1]*ratio]
  109.  
  110.  
  111.  
  112.  
  113. #more specific functions for calculations regarding the bird's positions and velocities
  114. def isinview(x, y):                                 #can bird x see bird y?
  115.    
  116.     if x==y:                                        #bird doesn't see itself
  117.         return False
  118.    
  119.     b1b2v = [birds[x][1][0]-birds[y][1][0],         #vector from bird 1 to bird 2
  120.              birds[x][1][1]-birds[y][1][1]]
  121.     if ((( (b1b2v[0]*birds[x][2][0] + b1b2v[1]*birds[x][2][1])/(vmag(b1b2v)*vmag(birds[x][2]))))) <= viewangle:
  122.         return True                                 #iff the angle between the birds velocity vector and the vector from bird 1 to bird 2 is within the birds viewing angle, bird 1 can see bird 2
  123.        
  124.     else:
  125.         return False
  126.  
  127. def updatevelocity(b):
  128.     global running
  129.     global zeroview
  130.     bird=birds[b]
  131.     neighbours=[[],[]]                              #list for neighbour velocity and position calculations
  132.     view=[[],[]]                                    #list for calculation of average velocity of birds within view
  133.     birds[b][4]=birds[b][3]                         #update previous velocities
  134.     birds[b][3]=birds[b][2]
  135.  
  136.    
  137.     if neighbourweight and neighbourposweight:
  138.         for x in range(numbirds):                   #this block calculates the neighbour birds' average velocity and the neighbour birds' average position
  139.             if (vmag(subvectorcomponents(birds[b][1], birds[x][1]))<=radius):
  140.                 neighbours[0].append(birds[x][2])
  141.                 neighbours[1].append(birds[x][1])
  142.         neighbouraveragevelocity=averagevector(neighbours[0])
  143.         neighbouraveragepos=subvectorcomponents(averagevector(neighbours[1]),birds[b][1])
  144.     else:
  145.         neighbouraveragevelocity=[0,0]
  146.         neighbouraveragepos=[0,0]
  147.  
  148.        
  149.     if viewweight:
  150.         for x in range(numbirds):                   #this block calculates the average velocity of the visible birds
  151.             if isinview(b,x):
  152.                 view[0].append(birds[x][2])
  153.                 view[1].append(birds[x][1])
  154.         if len(view[0]):
  155.             viewaveragevelocity=averagevector(view[0])
  156.             viewaverageposition=subvectorcomponents(averagevector(view[1]),birds[b][1])
  157.         else:
  158.             viewaveragevelocity=[0,0]
  159.             viewaverageposition=[0,0]
  160.     else:
  161.         viewaveragevelocity=[0,0]
  162.         viewaverageposition=[0,0]
  163.     if b==0:
  164.         zeroview=view[1][:]
  165.        
  166.     randomcomponent=randomspeedvector()             #add a random component, the birds "free will"
  167.    
  168.     gravweight=(vmag(subvectorcomponents(gravitypoint, birds[b][1])))
  169.     gravitycomponent=subvectorcomponents(gravitypoint, birds[b][1])
  170.  
  171.    
  172.    
  173.     mouse=pygame.mouse.get_pos()                    #this if-block checks whether the mouse is focused on the window and pressed, and then either attracts or repels birds from that point depending on which button is pressed
  174.    
  175.     if pygame.mouse.get_focused() and pygame.mouse.get_pressed()[0]:
  176.        
  177.         if ((mouse[0] >= (screensize[0]-15))        #checks if the "close" button has been pressed
  178.             and (mouse[1] <= (15))):
  179.             running = False
  180.        
  181.         bmV=subvectorcomponents(birds[b][1], mouse)
  182.         mousecomponent=scalevector(bmV, 1)
  183.         mousestrength=1/vmag(mousecomponent)**2
  184.  
  185.     elif pygame.mouse.get_focused() and pygame.mouse.get_pressed()[2]:
  186.        
  187.         bmV=subvectorcomponents(mouse,birds[b][1])
  188.         mousecomponent=scalevector(bmV, 1)
  189.         mousestrength=1/vmag(mousecomponent)**2
  190.  
  191.     else:
  192.         bmV=subvectorcomponents(mouse,birds[b][1])
  193.         mousecomponent=scalevector(bmV, 1)
  194.         mousestrength=0
  195.    
  196.     #update the actual velocity, taking into account the weightings
  197.  
  198.     birds[b][2] = [((neighbourweight*neighbouraveragevelocity[0]+
  199.                         viewweight*viewaveragevelocity[0]+
  200.                         viewposweight*viewaverageposition[0]+
  201.                         randomweight*randomcomponent[0]+
  202.                         neighbourposweight*neighbouraveragepos[0]+
  203.                         gravstrength*gravweight*gravitycomponent[0]+
  204.                         mouseweight*mousestrength*mousecomponent[0]+
  205.                         o1weight*birds[b][3][0]+
  206.                         o2weight*birds[b][4][0])/
  207.                     (viewposweight+randomweight+neighbourweight+neighbourposweight+viewweight+o1weight+o2weight+gravstrength*gravweight)),
  208.  
  209.                    
  210.                         ((neighbourweight*neighbouraveragevelocity[1]+
  211.                         viewweight*viewaveragevelocity[1]+
  212.                         viewposweight*viewaverageposition[1]+
  213.                         randomweight*randomcomponent[1]+
  214.                         neighbourposweight*neighbouraveragepos[1]+
  215.                         gravstrength*gravweight*gravitycomponent[1]+
  216.                         mouseweight*mousestrength*mousecomponent[1]+
  217.                         o1weight*birds[b][3][1]+
  218.                         o2weight*birds[b][4][1])/
  219.                     (viewposweight+randomweight+neighbourweight+neighbourposweight+viewweight+o1weight+o2weight+gravstrength*gravweight))]
  220.  
  221.     #Finally, we adjust the speed to a random speed in the range of averagebirdspeed-lowerbound and averagebirdspeed+upperbound. Not crucial, but makes the simulation look more natural (depending on how variables are set)
  222.    
  223.     birds[b][2]=scalevector(birds[b][2], random.randrange(averagebirdspeed-lowerbound,averagebirdspeed+upperbound))
  224.    
  225.    
  226. def updateposition(b):
  227.     if loopscreen:                                  #buggy for view and neighbour calculations
  228.         birds[b][1]=[(birds[b][1][0]+birds[b][2][0])%screensize[0], (birds[b][1][1]+birds[b][2][1])%screensize[1]]
  229.  
  230.     else:                                           #for screen that doesn't loop
  231.         birds[b][1]=[(birds[b][1][0]+birds[b][2][0]), (birds[b][1][1]+birds[b][2][1])]
  232.  
  233. def averagebirdposition():
  234.     return averagevector([birds[b][1] for b in range(numbirds)])
  235.  
  236. def averagebirdvelocity():
  237.     vel=[ birds[b][2] for b in range(numbirds)]
  238.     return scalevector(averagevector(vel), vmag(averagevector(vel))*8)
  239.  
  240.  
  241.  
  242.  
  243.  
  244. # "system" functions
  245. def setup():                                        #initializes birds with random positions and velocities
  246.     for b in range(numbirds):
  247.         birds[b][2] = birds[b][3] = birds[b][4] = randomspeedvector()
  248.         birds[b][1] = [random.randrange(0, screensize[0]), random.randrange(0, screensize[1])]
  249.  
  250.  
  251. def refreshscreen():                                #draw the birds, also includes conditionals for the various visualization options
  252.     if not traceimage:
  253.         pygame.draw.rect(screen, white, (0,0, screensize[0], screensize[1]),0)
  254.    
  255.     count=0
  256.     for bird in birds:
  257.         pygame.draw.rect(screen, black, (bird[1][0], bird[1][1], 2, 2), 0)
  258.         #if bird[0]=="bird0":
  259.          #   pygame.draw.rect(screen, green, (bird[1][0], bird[1][1], 4, 4), 0)
  260.         if highlightbird and count==0:              #this bit can highlight bird 0 to demonstrate a specific bird's motion
  261.            pygame.draw.rect(screen, red, (bird[1][0], bird[1][1], 3, 3), 1)
  262.        
  263.         if connectbirds:
  264.             for b in birds:
  265.                 pygame.draw.line(screen, green, bird[1], b[1], 1)
  266.         if connectaverageposition:
  267.             pygame.draw.line(screen, black, averagebirdposition(), bird[1], 1)
  268.     #for zv in zeroview:
  269.        # pygame.draw.rect(screen, red, (zv[0], zv[1], 3, 3), 0)
  270.        
  271.     if connectaveragetocenter:
  272.         pygame.draw.line(screen, green, [screensize[0]/2,screensize[1]/2], averagebirdposition(), 1)
  273.     if showaveragevector:
  274.         pygame.draw.line(screen, red, averagebirdposition(), [averagebirdvelocity()[0]+averagebirdposition()[0],averagebirdvelocity()[1]+averagebirdposition()[1]], 2)
  275.  
  276.     pygame.draw.rect(screen, red, (screensize[0]-16 , 0, 16,16),0)
  277.     pygame.draw.line(screen, black, [screensize[0]-15,15], [screensize[0],0], 1)
  278.     pygame.draw.line(screen, black, [screensize[0],14], [screensize[0]-15,0], 1)
  279.    
  280.    
  281.     pygame.display.update()
  282.  
  283.  
  284.  
  285.  
  286. setup()
  287. #main program loop
  288. while True:
  289.     pygame.event.pump()
  290.    
  291.     for b in range(numbirds):
  292.         updatevelocity(b)
  293.         updateposition(b)
  294.        
  295.     if running == False:
  296.         pygame.quit()
  297.         sys.exit()
  298.        
  299.     refreshscreen()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement