问题
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