【问题标题】:Random movement pygame随机运动 pygame
【发布时间】:2020-11-30 06:57:27
【问题描述】:

我正在尝试制作一个简单的生活模拟器,我需要“细胞”在屏幕上几乎随机(有一些规则)移动。但问题是,一段时间后,它们往往会聚集在屏幕的左上角。我试图改变很多东西,比如完全跳过规则并让它们完全随机移动,但它们仍然会聚集在一起。我的代码中有一些明显的问题吗?还是我应该以完全不同的方式进行运动?

去掉不相关部分的代码:

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()

【问题讨论】:

  • 只是对我注意到的一些事情的建议。 move 使用 2 元组而不是列表可能更有意义,因为它似乎总是正好包含 2 个元素。
  • @Carcigenicate 你的意思是不做 move[0] = random x move[1] = random y 我应该做 move = (random x, random y)?如果是这样,为什么会比我现在拥有的更好?
  • 我的意思是,self.move 是一个移动方向列表;但其中只有 2 个条目。通常,如果您有一个始终大小相同的容器,您可以使用元组来防止可能与现有代码混淆的意外追加。如果它不应该被附加,它不应该被允许。
  • 哦,好的,我现在明白为什么了,我会使用一个元组。感谢您指出这一点。
  • Np。你玩弄我午餐时要考虑的事情。

标签: python random pygame game-physics


【解决方案1】:

您的单元格聚集在左上角的原因是random.randrange()

randrange() 部分处理范围,as per the pythonrange() 函数。查看range()函数,range( A, B )返回一个列表A -> B-1

>>> for i in range( 1,10 ): print( i, end = ", " )
... 
1, 2, 3, 4, 5, 6, 7, 8, 9,

因此,当您的代码执行random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) 时,它不包括范围中的最后一项,看起来是“SE”。因此,它们更有可能朝其他方向移动,经过数千次迭代,它们会移动到左上角。

【讨论】:

    【解决方案2】:

    许多随机数生成器倾向于使用较小的数字。您可能需要将随机值偏移一些其他微小的随机数,或者查看更复杂的生成器。

    我快速环顾四周,找不到任何“真正的”随机生成器。

    尝试将一个小数添加到其他随机数中,然后查看开始。

    只是为了澄清我的意思:

    #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
    

    您可能需要调整 smallOffset 以限制它可以达到的大小(因为它的值几乎可以达到 1,这已经不再很小了)

    【讨论】:

    • 经过一番测试,我意识到,确实,随机数生成器是导致细胞聚集的原因。但我不明白,我应该如何“将一个小数添加到其他随机数”以使其更好。
    • 好吧,如果是因为您的生成器稍微偏向较小的数字,您可以添加一个较小的数字来尝试补偿这种偏差。我会看看我是否可以举个例子,并更新我的答案。
    • @Uxeron 我添加了一个示例。如果您仍需要澄清,请告诉我。
    • 我尝试了您的想法,并且通过对偏移量进行了一些微调,它现在可以正常工作了。非常感谢您的帮助。
    • Np。这是在黑暗中拍摄的,所以我很高兴它奏效了。祝你的项目好运。
    猜你喜欢
    • 1970-01-01
    • 2015-06-16
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多