pygame中的随机系统运动 [英] Random systematic movement in pygame
问题描述
我正在制作一个 Covid 模拟器,需要我的球随机移动.但是,我希望它们保持在选择的第一个随机方向上移动,并且只有在碰到另一个单元格或碰到墙壁时才改变方向.
我目前的代码如下:
随机导入导入pygame# --- 常量 --- (UPPER_CASE_NAMES)GREEN1 = (0, 255, 0) # 健康细胞RED = (255, 0, 0) # 感染细胞GREEN2 = (0, 100, 0) # 健康细胞不敏感黑色 = (0, 0, 0) # 死细胞白色 = (255, 255, 255)背景颜色 = (225, 198, 153)屏幕尺寸 = (800, 800)# --- 类 --- (CamelCaseNames)# class 只保留一个单元格,所以它的名字应该是 `Cell` 而不是 `Cells`类单元格(pygame.sprite.Sprite):def __init__(self, color, speed, width, height):super().__init__()self.color = 颜色self.speed = 速度self.image = pygame.Surface([宽度,高度])self.image.fill(白色)self.image.set_colorkey(白色)self.radius = 宽度//2 # 25中心 = [宽度//2,高度//2]pygame.draw.circle(self.image,self.color,center,self.radius,width=0)self.rect = self.image.get_rect()self.rect.x = random.randint(0, 400)self.rect.y = random.randint(50, 700)self.pos = pygame.math.Vector2(self.rect.center)self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))定义更新(自我):self.pos += self.dir * self.speed如果 self.pos.x - self.radius <0 或 self.pos.x + self.radius >屏幕尺寸[0]:self.dir.x *= -1如果 self.pos.y - self.radius <0 或 self.pos.y + self.radius >屏幕尺寸[1]:self.dir.y *= -1对于 all_cells 中的 other_cell:如果 all_cells != self:distance_vec = self.pos - other_cell.pos如果 0
我想知道是否有办法做到这一点,非常感谢您的帮助.提前致谢.我尝试将下面的第一个答案复制到我的 pycharm 中,但它没有用,所以现在我已经把我的完整代码放在了一个部分,以防万一.抱歉之前没有全部放上
我推荐使用
随机导入导入pygameGREEN1 = (0, 255, 0) # 健康细胞RED = (255, 0, 0) # 感染细胞GREEN2 = (0, 100, 0) # 健康细胞不敏感黑色 = (0, 0, 0) # 死细胞白色 = (255, 255, 255)背景颜色 = (225, 198, 153)屏幕尺寸 = (800, 800)速度 = [0.5, -0.5]类单元格(pygame.sprite.Sprite):def __init__(self, color, speed, width, height):super().__init__()self.color = 颜色self.speed = 速度self.image = pygame.Surface([宽度,高度])self.image.fill(白色)self.image.set_colorkey(白色)self.radius = 宽度//2 # 5中心 = [宽度//2,高度//2]pygame.draw.circle(self.image,self.color,center,self.radius,width=0)self.rect = self.image.get_rect()self.rect.x = random.randint(0, 400)self.rect.y = random.randint(50, 700)self.pos = pygame.math.Vector2(self.rect.center)self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))定义更新(自我):self.pos += self.dir * self.speedborder_rect = pygame.Rect(0, 50, 400, 700)如果 self.pos.x - self.radius border_rect.right:self.pos.x = border_rect.right - self.radiusself.dir.x = -abs(self.dir.x)如果 self.pos.y - self.radius border_rect.bottom:self.pos.y = border_rect.bottom - self.radiusself.dir.y = -abs(self.dir.y)对于 all_cells 中的 other_cell:如果 all_cells != self:distance_vec = self.pos - other_cell.pos如果 0
I am making a Covid simulator and need my balls to move around randomly. However, I want them to stay moving in the first random direction that the chose, and only chnage direction if it hits another cell or hits the wall.
My current code is as follow:
import random
import pygame
# --- constants --- (UPPER_CASE_NAMES)
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (225, 198, 153)
SCREEN_SIZE = (800, 800)
# --- classes --- (CamelCaseNames)
# class keeep only one cell so it should has name `Cell` instead of `Cells`
class Cell(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.radius = width // 2 # 25
center = [width // 2, height // 2]
pygame.draw.circle(self.image, self.color, center, self.radius, width=0)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, 400)
self.rect.y = random.randint(50, 700)
self.pos = pygame.math.Vector2(self.rect.center)
self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))
def update(self):
self.pos += self.dir * self.speed
if self.pos.x - self.radius < 0 or self.pos.x + self.radius > SCREEN_SIZE[0]:
self.dir.x *= -1
if self.pos.y - self.radius < 0 or self.pos.y + self.radius > SCREEN_SIZE[1]:
self.dir.y *= -1
for other_cell in all_cells:
if all_cells != self:
distance_vec = self.pos - other_cell.pos
if 0 < distance_vec.length_squared() < (self.radius * 2) ** 2:
self.dir.reflect_ip(distance_vec)
other_cell.dir.reflect_ip(distance_vec)
self.rect.centerx = round(self.pos.x)
self.rect.centery = round(self.pos.y)
# --- functions --- (lower_case_names)
# empty
# --- main --- (lower_case_names)
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Covid-19 Simualtion")
speed = [0.5, -0.5]
# - objects -
all_cells = pygame.sprite.Group() # PEP8: lower_case_name
for _ in range(5):
cell = Cell(GREEN1, 5, 10, 10) # PEP8: lower_case_name
all_cells.add(cell)
# - loop -
clock = pygame.time.Clock()
end = False
while not end:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
end = True
# - upadates (without draws) -
all_cells.update()
# - draws (without updates) -
screen.fill(BACKGROUND_COLOR)
pygame.draw.rect(screen, BLACK, (0, 50, 400, 700), 3)
all_cells.draw(screen)
pygame.display.flip()
clock.tick(30) # to use less CPU
# - end
pygame.quit() # some system may need it to close window
I was wondering if there was a way to do this, really grateful for any help. Thanks in advance. I tried copy the first answer below into my pycharm but it didnt work, so now i have put my full code up as opposed to one section in case it is needed. Sorry for not putting it all before
I recommend to use pygame.math.Vector2
. Add the attributes pos
and dir
(position and direction) to the class Cell
. Set the position with the center of the rect
attribute and generate a vector with a random direction:
class Cell(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
# [...]
self.pos = pygame.math.Vector2(self.rect.center)
self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))
Change the position in t he method update
. Add the product of the direction vector dir
and the speed
to the position (pos
). Update the position of the rectangle by rounding (round
) the position vector:
class Cell(pygame.sprite.Sprite):
# [...]
def update(self):
self.pos += self.dir * self.speed
self.rect.centerx = round(self.pos.x)
self.rect.centery = round(self.pos.y)
See How to make ball bounce off wall with Pygame? and apply the suggestions to your code:
class Cell(pygame.sprite.Sprite):
# [...]
def update(self):
self.pos += self.dir * self.speed
if self.pos.x - self.radius < 0:
self.pos.x = self.radius
self.dir.x = abs(self.dir.x)
elif self.pos.x + self.radius > 400:
self.pos.x = 400 - self.radius
self.dir.x = -abs(self.dir.x)
if self.pos.y - self.radius < 50:
self.pos.y = 50 + self.radius
self.dir.y = abs(self.dir.y)
elif self.pos.y + self.radius > 700:
self.pos.y = 700 - self.radius
self.dir.y = -abs(self.dir.y)
self.rect.centerx = round(self.pos.x)
self.rect.centery = round(self.pos.y)
See Pygame how to let balls collide. Test to see if the cells collide and reflect the direction vectors when a collision is detected:
class Cell(pygame.sprite.Sprite):
# [...]
def update(self):
self.pos += self.dir * self.speed
# [...]
for other_cell in all_cells:
if all_cells != self:
distance_vec = self.pos - other_cell.pos
if 0 < distance_vec.length_squared() < (self.radius*2) ** 2:
self.dir.reflect_ip(distance_vec)
other_cell.dir.reflect_ip(distance_vec)
self.rect.centerx = round(self.pos.x)
self.rect.centery = round(self.pos.y)
See also Collision and Intersection - Circle and circle
Complete example:
import random
import pygame
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (225, 198, 153)
SCREEN_SIZE = (800, 800)
speed = [0.5, -0.5]
class Cell(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.radius = width // 2 # 5
center = [width // 2, height // 2]
pygame.draw.circle(self.image, self.color, center, self.radius, width=0)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, 400)
self.rect.y = random.randint(50, 700)
self.pos = pygame.math.Vector2(self.rect.center)
self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))
def update(self):
self.pos += self.dir * self.speed
border_rect = pygame.Rect(0, 50, 400, 700)
if self.pos.x - self.radius < border_rect.left:
self.pos.x = border_rect.left + self.radius
self.dir.x = abs(self.dir.x)
elif self.pos.x + self.radius > border_rect.right:
self.pos.x = border_rect.right - self.radius
self.dir.x = -abs(self.dir.x)
if self.pos.y - self.radius < border_rect.top:
self.pos.y = border_rect.top + self.radius
self.dir.y = abs(self.dir.y)
elif self.pos.y + self.radius > border_rect.bottom:
self.pos.y = border_rect.bottom - self.radius
self.dir.y = -abs(self.dir.y)
for other_cell in all_cells:
if all_cells != self:
distance_vec = self.pos - other_cell.pos
if 0 < distance_vec.length_squared() < (self.radius*2) ** 2:
self.dir.reflect_ip(distance_vec)
other_cell.dir.reflect_ip(distance_vec)
self.rect.centerx = round(self.pos.x)
self.rect.centery = round(self.pos.y)
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Covid-19 Simualtion")
all_cells = pygame.sprite.Group() # PEP8: lower_case_name
for i in range(100):
cell = Cell(GREEN1, 5, 10, 10) # PEP8: lower_case_name
all_cells.add(cell)
clock = pygame.time.Clock()
end = False
while not end:
for event in pygame.event.get():
if event.type == pygame.QUIT:
end = True
all_cells.update()
screen.fill(BACKGROUND_COLOR)
pygame.draw.rect(screen, BLACK, (0, 50, 400, 700), 3)
all_cells.draw(screen)
pygame.display.flip()
clock.tick(30) # to use less CPU
这篇关于pygame中的随机系统运动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!