将一个圆在正方形周围滚动

4

我已经卡了将近一个月了,始终无法解决这个问题。我设法决定圆圈(或者我称之为行人)应该向左/右移动还是向上/下移动,但我需要让行人有可能绕过一个建筑物(也就是说,他们必须在拐角处转弯,基本上无论朝向如何,他们都只需要转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")

请发布一个完整可运行的示例。通过运行代码并查找问题,比阅读您认为存在问题的部分要容易得多。有很多信息缺失。通过找到append,我可能会认为Skyscrapers是一个列表,但我不能确定。然而,Skyscrapers[Random_Johnnie]感觉就不对。 - stefan
请查看更新后的代码。 - Mechatrnk
1个回答

0

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

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_Skyscraper),并与另一个随机选取的建筑物 (Random_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 ...

这里你可以得到一个随机索引来获取行人:random.randint(0,len(Johnnie_Walkers)-1),然后将其应用于建筑物列表Skyscrapers[Random_Johnnie].shape[1]/2,这是无意义的。第二个约翰尼与第三号街道上的建筑物没有任何关系。

还有更难理解的代码,比如如果没有力量可以施加,则重置计时器Tick_Counter = 0

一些通用提示:

让你的代码易读。适当命名变量。Random_Johnnie可能只在你的耳中听起来有趣。而且每个人都可以看到索引是随机选择的。但是没有提示它将用于什么。那么person_to_start_walking呢?同样适用于Which_Skyscraper。那么building_where_to_generate_person呢?代码会怎么读?好多了。

从类C语言转换到Python时,一个非常重要的问题是(几乎)不要使用索引,学会使用引用,它们甚至比索引更便宜。像for building in buildings:这样的循环,在您选择随机人员或建筑物时也要使用random.choice()。这样,您就不会意外地在建筑物集合上使用人员索引。
此外-使用临时变量而不是长嵌套表达式。这样更容易阅读,特别是如果它们有良好的名称。如果某物是位置,请不要将其命名为Which_Skyscraper

非常感谢您的提示和建议,我一定会使用它们。关于行人的定位,这是我能找到的最简单的方法,我将他们放在随机的建筑物中,然后他们被迫离开建筑物(因为建筑物是静态的,而行人是动态的身体)。然后他们应该在建筑物周围移动(或者从一个建筑物的一侧开始移动,将它们转向移动周围的建筑物是另一个任务)。我需要找出一个算法来决定他们应该朝哪个方向移动(然后我将生成一辆汽车,应该避免它们...) - Mechatrnk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接