pygame中的随机系统运动 [英] Random systematic movement in pygame

查看:96
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆