Rolling a circle around a square

我与影子孤独终老i 提交于 2020-01-13 12:16:28

问题


After almost a month I am still stuck on this issue I managed to decide whether the circles (or pedestrians as I call them) should move left/right or up/down but I need to have the possibility to move the pedestrians around a building (that means they have to turn on the corners, basically does not matter whether direction, they just need to turn by 90 degrees

Thank you very much

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!')

So there are basically two goals, one is to make the pedestrians turn (probably I will have to before applying perpendicular force to apply force parallel to that they are moving right now of the opposite direction, so they would immediately stop and then turn but I do not know how to do that (or maybe there might be a different solution, that's why I am asking)

And the other goal is to do this in a for loop, because in my game there are four buildings... I tried to put it in the for loop but failed (I can post my for loop later if requested, but please I need to solve my first problem.

Disclaimer Some of you may notice that almost the same question appeared on GameDev.StackExchange.com, under my second user account, I do not why I created the other account, but I know that it was not a good solution, I am sorry for that. I just wanted to ask you for not talking about why I created the new account and that it is bad... I know that and once again I am sorry for that...

The reason I put the question here is that I think that here it is a better place for two reasons, First: it is more algorithm problem than a game-developing problem, Second: SO is much busier than GameDev and I am stuck on this for a very long time, so I really need help

EDIT: I managed to add this attribute to the Building Class and implement it into the pedestrian_walk function, it works occasionally, but how could I improve it? Or maybe make it more "pythonic" Thank you very much

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

回答1:


It is hard to tell what your code should do. But there are some things that are most probably not right. In

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

you do create pedestrians. However the positioning is weird. You randomly take one building (Which_Skyscraper) and mangle that with another randomly taken building (Random_Skyscraper). These buildings may be identical by chance but more probably they are different. I think you intended to place pedestrians inside a building which would require to have a building taken randomly once.

Even worse is the mangling of buildings and pedestrians in

# 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 ...

here you get a random index to your pedestrians random.randint(0,len(Johnnie_Walkers)-1) which you then apply to the list of buildings Skyscrapers[Random_Johnnie].shape[1]/2 which is nonsense. Johnny the 2nd has nothing to do with the building at street number 3.

There is more hard to understand code like resetting the tick counter Tick_Counter = 0 if no Force could be applied.

Some general hints:

Make your code readable. Name variables properly. Random_Johnnie may sound funny in your ears only. Also everyone can see the index was randomly chosen. But there is no hint what it will be used for. What about person_to_start_walking? Same for Which_Skyscraper. What about building_where_to_generate_person? How would the code read? Much better.

A very important issue when changing from a C-like language to python, (almost) never use indices, learn to work with the references, they are even cheaper than indices. Loop like for building in buildings: and also in your case use random.choice() when picking persons or buildings randomly. That way you cannot by accident use a person-index on a building-collection.

Also - use temporary variables instead of long, nested expressions. It is easier to read, especially if they have good names. Do not name something Which_Skyscraper if it is a position.



来源:https://stackoverflow.com/questions/58557869/rolling-a-circle-around-a-square

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!