问题
I'm trying to make a simple life simulator, and I need the "cells" to move almost randomly (with a few rules) across the screen. But the problem is, after a while they tend to bunch up in the upper-left corner of the screen. I tried to change a lot of things, like completely skipping the rules and making them move completely randomly, but they still bunch up. Is there some obvious problem in my code? Or should I be doing the movement completely differently?
The code with irrelevant parts cut out:
import sys, random, pygame
from pygame.locals import *
pygame.init()
WIDTH = 640 #game window width
HEIGHT = 480 #game window height
FPS = 60 #game's speeds
Pixsize = 2
screen = pygame.display.set_mode((WIDTH, HEIGHT)) #set the game window
class cell:
def __init__(self):
self.x = random.randrange(10, WIDTH-10) #x position
self.y = random.randrange(10, HEIGHT-10) #y position
self.speed = random.randrange(2,5) #cell speed
self.move = [None, None] #realtive x and y coordinates to move to
self.direction = None #movement direction
def draw(self):
pygame.draw.rect(screen, (255,255,255), (self.x,self.y,Pixsize,Pixsize),0) #draw the cell
def wander(self):
directions = {"S":((-1,2),(1,self.speed)),"SW":((-self.speed,-1),(1,self.speed)),"W":((-self.speed,-1),(-1,2)),"NW":((-self.speed,-1),(-self.speed,-1)),"N":((-1,2),(-self.speed,-1)),"NE":((1,self.speed),(-self.speed,-1)),"E":((1,self.speed),(-1,2)),"SE":((1,self.speed),(1,self.speed))} #((min x, max x)(min y, max y))
directionsName = ("S","SW","W","NW","N","NE","E","SE") #possible directions
if random.randrange(0,5) == 2: #move about once every 5 frames
if self.direction == None: #if no direction is set, set a random one
self.direction = random.choice(directionsName)
else:
a = directionsName.index(self.direction) #get the index of direction in directions list
b = random.randrange(a-1,a+2) #set the direction to be the same, or one next to the current direction
if b > len(directionsName)-1: #if direction index is outside the list, move back to the start
b = 0
self.direction = directionsName[b]
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) #change relative x to a random number between min x and max x
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) #change relative y to a random number between min y and max y
if self.x < 5 or self.x > WIDTH - 5 or self.y < 5 or self.y > HEIGHT - 5: #if cell is near the border of the screen, change direction
if self.x < 5:
self.direction = "E"
elif self.x > WIDTH - 5:
self.direction = "W"
elif self.y < 5:
self.direction = "S"
elif self.y > HEIGHT - 5:
self.direction = "N"
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) #change relative x to a random number between min x and max x
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) #change relative x to a random number between min x and max x
if self.move[0] != None: #add the relative coordinates to the cells coordinates
self.x += self.move[0]
self.y += self.move[1]
cells = []
for i in range(200): #generate n cells
Cell = cell()
cells.append(Cell)
def mainloop():
while True:
for event in pygame.event.get():
if event.type== QUIT: #if pressing the X, quit the progra
pygame.quit() #stop pygame
sys.exit() #stop the program
screen.fill((0,0,0)) #clear the screen;
for i in cells: #update all cells
i.wander()
i.draw()
pygame.display.update() #update display
pygame.time.Clock().tick(FPS) #limit FPS
mainloop()
回答1:
A lot of random number generators tend to favour smaller numbers. You may need to offset the random values by some other tiny random number, or look into more sophisticated generators.
I looked around quickly, and I couldn't find any "truly" random generators.
Try adding a tiny number to the other random numbers and see start happens.
Just to clarify what I meant:
#Instead of:
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1])
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1])
#Try something like:
smallOffset = random.random() #Random floating-point number between 0 and 1 ("Tiny number")
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) + smallOffset
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) + smallOffset
You may have to adjust smallOffset
to limit how large it can get (because, it can be a value up to almost 1, which isn't really small anymore)
回答2:
The reason your cells are bunching up to the top-left is because of random.randrange()
.
The randrange()
part handles the range, as per the python range()
function. Looking at the range()
function, range( A, B )
returns a list A
-> B-1
:
>>> for i in range( 1,10 ): print( i, end = ", " )
...
1, 2, 3, 4, 5, 6, 7, 8, 9,
So when your code is doing random.randrange(directions[self.direction][0][0],directions[self.direction][0][1])
, it's excluding the last item in the range, which looks to be "SE". Hence they're a little more likely to head in the other directions, and after thousands of iterations, that moves them to the top-left corner.
来源:https://stackoverflow.com/questions/30015787/random-movement-pygame