绕着正方形滚一个圆圈

Rolling a circle around a square

提问人:Mechatrnk 提问时间:10/25/2019 最后编辑:Mechatrnk 更新时间:11/18/2019 访问量:587

问:

将近一个月后,我仍然被困在这个问题上,我设法决定圆圈(或我所说的行人)是否应该向左/向右或向上/向下移动,但我需要有可能在建筑物周围移动行人(这意味着他们必须转弯,基本上不管方向如何, 他们只需要旋转 90 度

谢谢

import numpy as np
import random
import keyboard
from Box2D.b2 import world, polygonShape, circleShape, edgeShape, staticBody, dynamicBody, kinematicBody, revoluteJoint, wheelJoint
from Box2D import b2Vec2, b2FixtureDef, b2PolygonShape, b2CircleShape, b2Dot, b2EdgeShape, b2Contact,b2ContactFilter,b2Filter,b2ContactListener,b2GetPointStates


import pygame
from pygame import HWSURFACE, DOUBLEBUF, RESIZABLE, VIDEORESIZE
from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE)
pygame.init()

box2world = world(contactListener = MyContactListener(), gravity = (0.0, 0.0), doSleep = True)

class Pedestrian():
    def __init__(self,box2world, position = None):

        if position == None:
            position = [5,5]

        self.position = position
        self.box2world = box2world
        self.Current_Position = []
        self.body = self.box2world.CreateDynamicBody(position = position, 
                                                       angle = 0.0,
                                                       fixtures = b2FixtureDef(
                                                            shape = b2CircleShape(radius = 0.5),
                                                            density = 2,
                                                            friction = 0.3,
                                                            ))


class Building():
    def __init__(self, box2world,shape, position, sensor= None):
        self.box2world = box2world
        self.shape = shape
        self.position = position

        if sensor == None:
            sensor = False
        self.corners = [((self.position[0] + self.shape[0]), (self.position[1] + self.shape[1])),
                        ((self.position[0] + self.shape[0]), (self.position[1] - self.shape[1])),
                        ((self.position[0] - self.shape[0]), (self.position[1] - self.shape[1])),
                        ((self.position[0] - self.shape[0]), (self.position[1] + self.shape[1]))]

        self.sensor = sensor
        self.footprint = self.box2world.CreateStaticBody(position = position,
                                                           angle = 0.0,
                                                           fixtures = b2FixtureDef(
                                                               shape = b2PolygonShape(box=(self.shape)),
                                                               density = 1000,
                                                               friction = 1000))


############################################################## Pygame visualisation
PPM = 10
SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
SCREEN_OFFSETX, SCREEN_OFFSETY = SCREEN_WIDTH/16, SCREEN_HEIGHT
POS_X = SCREEN_WIDTH/PPM/3
POS_Y = SCREEN_HEIGHT/PPM/3
MAX_AMOUNT_PEDESTRIANS = 10
FPS = 24
TIME_STEP = 1.0 / FPS
k = 0

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), HWSURFACE|DOUBLEBUF|RESIZABLE)
pygame.display.set_caption('Top Down Car Using OOP')
colors = {dynamicBody: (133, 187, 101, 0),  staticBody: (15, 0, 89, 0)}

walkers = [] 

skyscraper  = Building(box2world,shape = (5,5), position =  (POS_X + 3, POS_Y + 5))

def fix_vertices(vertices):
    return [(int(SCREEN_OFFSETX + v[0]), int(SCREEN_OFFSETY - v[1])) for v in vertices]


def _draw_polygon(polygon, screen, body, fixture):
    transform = body.transform
    vertices = fix_vertices([transform * v * PPM for v in polygon.vertices])
    pygame.draw.polygon(
        screen, [c / 2.0 for c in colors[body.type]], vertices, 0)
    pygame.draw.polygon(screen, colors[body.type], vertices, 1)
polygonShape.draw = _draw_polygon


def _draw_circle(circle, screen, body, fixture):
    position = fix_vertices([body.transform * circle.pos * PPM])[0]
    pygame.draw.circle(screen, colors[body.type],
                       position, int(circle.radius * PPM))
circleShape.draw = _draw_circle

running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            running = False

    screen.fill((255, 255, 255, 255))
    for body in box2world.bodies:
        for fixture in body.fixtures:
            fixture.shape.draw(screen, body, fixture)

    if k <= MAX_AMOUNT_PEDESTRIANS:
        walkers.append(Pedestrian(box2world, position = (skyscraper.position[0] -random.randint(-skyscraper.shape[0],skyscraper.shape[0]),\
                            skyscraper.position[1] -random.randint(-skyscraper.shape[1],skyscraper.shape[1]))))
        k = k+1
    for walker in walkers:
        pedestrian_walk(walker,skyscraper)
    # Simulate dynamic equation in each step
    TIME_STEP = 1.0 / FPS
    box2world.Step(TIME_STEP, 10, 10)

    # Flip the screen and try to keep at the target FPS
    pygame.display.flip() # Update the full display Surface to the screen
    pygame.time.Clock().tick(FPS)

pygame.quit()
print('Done!')

所以基本上有两个目标,一个是让行人转弯(可能我必须在施加垂直力之前施加平行于他们现在向相反方向移动的力,所以他们会立即停下来然后转弯,但我不知道该怎么做(或者可能有不同的解决方案, 这就是我问的原因)

另一个目标是在 for 循环中做到这一点,因为在我的游戏中有四座建筑......我试图把它放在for循环中,但失败了(如果需要,我可以稍后发布我的for循环,但请我需要解决我的第一个问题。

免責聲明你们中的一些人可能会注意到,在我的第二个用户帐户下,GameDev.StackExchange.com 上出现了几乎相同的问题,我不知道为什么我创建了另一个帐户,但我知道这不是一个好的解决方案,我很抱歉。我只是想问你不要谈论我为什么创建新帐户以及它很糟糕......我知道这一点,我再次为此感到抱歉......

我之所以把问题放在这里,是因为我认为这里是一个更好的地方,原因有两个,第一:它更多的是算法问题而不是游戏开发问题,第二:SO 比 GameDev 忙得多,而且我被困在这个问题上很长时间,所以我真的需要帮助

编辑:我设法将此属性添加到 Building 类并将其实现到 pedestrian_walk 函数中,它偶尔会起作用,但是我该如何改进它?或者也许让它更“pythonic”非常感谢

def pedestrian_walk(Pedestrian, Building):
    if Pedestrian.body.position[0] <= Building.position[0] and Building.position[1] - Building.shape[1] < Pedestrian.position[1] < Building.position[1] + Building.shape[1]:
        Pedestrian.body.__SetLinearVelocity(b2Vec2(0,10))
    elif Pedestrian.body.position[0] > Building.position[0] and Building.position[1] - Building.shape[1] < Pedestrian.position[1] < Building.position[1] + Building.shape[1]:
        Pedestrian.body.__SetLinearVelocity(b2Vec2(0,-10))
    elif Pedestrian.body.position[1] > Building.position[1] and Building.position[0] - Building.shape[0] < Pedestrian.position[0] < Building.position[0] + Building.shape[0]:
        Pedestrian.body.__SetLinearVelocity(b2Vec2(10,0))
    elif Pedestrian.body.position[1] <= Building.position[1] and Building.position[0] - Building.shape[0] < Pedestrian.position[0] < Building.position[0] + Building.shape[0]:
        Pedestrian.body.__SetLinearVelocity(b2Vec2(-10,0))

    if ((Building.corners[0][0] -0.5 <= Pedestrian.body.position[0] <= Building.corners[0][0] + 0.5 and\
        Building.corners[0][1] -0.5 <= Pedestrian.body.position[1] <= Building.corners[0][1] + 0.5)):
        Pedestrian.body.__SetLinearVelocity(b2Vec2(-100,100))
        print("Changing direction")
    elif((Building.corners[1][0] -0.5 <= Pedestrian.body.position[0] <= Building.corners[1][0] + 0.5 and\
        Building.corners[1][1] -0.5 <= Pedestrian.body.position[1] <= Building.corners[1][1] + 0.5)):
        Pedestrian.body.__SetLinearVelocity(b2Vec2(-100,200))
        print("Changing direction")
    elif((Building.corners[2][0] -0.5 <= Pedestrian.body.position[0] <= Building.corners[2][0] + 0.5 and\
        Building.corners[2][1] -0.5 <= Pedestrian.body.position[1] <= Building.corners[2][1] + 0.5)):
        Pedestrian.body.__SetLinearVelocity(b2Vec2(-100,200))
        print("Changing direction")
    elif((Building.corners[3][0] -0.5 <= Pedestrian.body.position[0] <= Building.corners[3][0] + 0.5 and\
        Building.corners[3][1] -0.5 <= Pedestrian.body.position[1] <= Building.corners[3][1] + 0.5)):
        Pedestrian.body.__SetLinearVelocity(b2Vec2(-100,200))
        print("Changing direction")
python 算法 if-statement position box2d

评论

0赞 stefan 10/26/2019
发布一个完整的可运行示例。运行代码并找到问题比阅读您认为有问题的部分要容易得多。缺少很多信息。通过发现,我可能认为是一个列表,但我不能确定。然而,只是感觉不对劲。appendSkyscrapersSkyscrapers[Random_Johnnie]
0赞 Mechatrnk 10/26/2019
查看更新后的代码

答:

0赞 stefan 10/26/2019 #1

很难说出你的代码应该做什么。但有些事情很可能是不对的。在

Which_Skyscraper = Skyscrapers[random.randint(0,len(Skyscrapers)-1)].position
Random_Skyscraper = Skyscrapers[random.randint(0,len(Skyscrapers)-1)]
Johnnie_Walkers.append(Pedestrian(Box_2_World, position = \
    (Which_Skyscraper[0] -random.randint(-Random_Skyscraper.shape[0],Random_Skyscraper.shape[0]), \
    Which_Skyscraper[1] -random.randint(-Random_Skyscraper.shape[1],Random_Skyscraper.shape[1]))))

你确实创造了行人。但是,定位很奇怪。你随机取一个建筑物(),并将其与另一个随机取的建筑物()混淆。这些建筑物可能是偶然的,但更有可能是不同的。我想你打算把行人放在一栋建筑物内,这需要随机拍摄一次建筑物。Which_SkyscraperRandom_Skyscraper

更糟糕的是建筑物和行人的混乱

# Make the pedestrian walk
Tick_Counter = Tick_Counter + 1
Random_Johnnie = random.randint(0,len(Johnnie_Walkers)-1)

if abs(Skyscrapers[Random_Johnnie].position[1] - Johnnie_Walkers[Random_Johnnie].position[0]) >= \
        Skyscrapers[Random_Johnnie].shape[1]/2 +1:
    Johnnie_Walkers[Random_Johnnie].body.ApplyForce(b2Vec2(5,0), \
    Johnnie_Walkers[Random_Johnnie].body.worldCenter,True)

elif ...

在这里,你会得到一个行人的随机索引,然后你将其应用于建筑物列表,这是无稽之谈。约翰尼二世与3号街的建筑物无关。random.randint(0,len(Johnnie_Walkers)-1)Skyscrapers[Random_Johnnie].shape[1]/2

还有更难理解的代码,例如在没有力的情况下重置刻度计数器。Tick_Counter = 0

一些一般提示:

使代码可读。正确命名变量。 可能只在你耳边听起来很有趣。此外,每个人都可以看到索引是随机选择的。但是没有暗示它将用于什么。怎么样?与 .怎么样?代码将如何读取?好多了。Random_Johnnieperson_to_start_walkingWhich_Skyscraperbuilding_where_to_generate_person

从类 C 语言更改为 python 时,一个非常重要的问题,(几乎)从不使用索引,学习使用引用,它们甚至比索引便宜。循环喜欢,在您的情况下,也可以在随机选择人员或建筑物时使用。这样,您就不会意外地在建筑物集合上使用人员索引。for building in buildings:random.choice()

此外 - 使用临时变量而不是长嵌套表达式。它更容易阅读,特别是如果他们有好名字。如果它是一个职位,请不要命名。Which_Skyscraper

评论

0赞 Mechatrnk 10/26/2019
非常感谢您的提示和建议,我一定会使用它们。关于行人的位置,这是我能找到的最简单的方法,我把他们放在随机的建筑物中,然后他们被迫搬出建筑物(因为建筑物是静态的,而行人是动态的)。然后他们应该在建筑物周围移动(或者首先沿着建筑物的一侧移动,将它们转动以在建筑物周围移动是另一回事)。我需要找出一种算法来决定它们应该向哪个方向移动(然后我将生成一辆应该避开它们的汽车......